From d7c8c99e2d95b5c7e3377a9aa8973be8a8fd0ef6 Mon Sep 17 00:00:00 2001 From: Cedric Roux <cedric.roux@eurecom.fr> Date: Mon, 21 Oct 2013 08:08:15 +0000 Subject: [PATCH] git-svn-id: http://svn.eurecom.fr/openair4G/trunk@4234 818b1a75-f10b-46b9-bf7c-635c3b92a50f --- openair-cn/AUTHORS | 1 + openair-cn/COMMON/as_message.h | 526 + openair-cn/COMMON/commonDef.h | 249 + openair-cn/COMMON/common_types.h | 250 + openair-cn/COMMON/gtpv1_u_messages_def.h | 8 + openair-cn/COMMON/gtpv1_u_messages_types.h | 58 + openair-cn/COMMON/ip_forward_messages_def.h | 6 + openair-cn/COMMON/ip_forward_messages_types.h | 67 + openair-cn/COMMON/messages_def.h | 15 + openair-cn/COMMON/messages_types.h | 24 + openair-cn/COMMON/mme_app_messages_def.h | 3 + openair-cn/COMMON/mme_app_messages_types.h | 6 + openair-cn/COMMON/nas_messages_def.h | 16 + openair-cn/COMMON/nas_messages_types.h | 77 + openair-cn/COMMON/s11_messages_def.h | 1 + openair-cn/COMMON/s11_messages_types.h | 4 + openair-cn/COMMON/s1ap_messages_def.h | 4 + openair-cn/COMMON/s1ap_messages_types.h | 51 + openair-cn/COMMON/s6a_messages_def.h | 5 + openair-cn/COMMON/s6a_messages_types.h | 43 + openair-cn/COMMON/sctp_messages_def.h | 6 + openair-cn/COMMON/sctp_messages_types.h | 34 + openair-cn/COMMON/security_types.h | 183 + openair-cn/COMMON/sgw_lite_def.h | 6 + openair-cn/COMMON/sgw_lite_messages_types.h | 209 + openair-cn/COMMON/tasks_def.h | 25 + openair-cn/COMMON/udp_messages_def.h | 3 + openair-cn/COMMON/udp_messages_types.h | 16 + openair-cn/COPYING | 674 + openair-cn/ChangeLog | 15 + openair-cn/DOCS/DOXYGEN/Doxyfile.in | 1718 ++ openair-cn/DOCS/DOXYGEN/Makefile.am | 22 + .../Latex/DefaultBearer/DefaultBearer.pdf | Bin 0 -> 141203 bytes .../Latex/DefaultBearer/DefaultBearer.tex | 1007 + openair-cn/DOCS/Latex/EPC/EPC.pdf | Bin 0 -> 243263 bytes openair-cn/DOCS/Latex/EPC/EPC.tex | 774 + openair-cn/DOCS/Latex/EPC/Makefile | 9 + openair-cn/DOCS/Makefile.am | 1 + openair-cn/GTPV1-U/Makefile.am | 31 + openair-cn/GTPV1-U/Makefile.eNB | 49 + openair-cn/GTPV1-U/gtpv1u.h | 51 + openair-cn/GTPV1-U/gtpv1u_eNB.c | 520 + openair-cn/GTPV1-U/gtpv1u_eNB_defs.h | 86 + openair-cn/GTPV1-U/gtpv1u_sgw_defs.h | 78 + openair-cn/GTPV1-U/gtpv1u_task.c | 553 + openair-cn/GTPV1-U/gtpv1u_teid_pool.c | 20 + openair-cn/GTPV1-U/nw-gtpv1u/AUTHORS | 1 + openair-cn/GTPV1-U/nw-gtpv1u/COPYING | 26 + openair-cn/GTPV1-U/nw-gtpv1u/ChangeLog | 0 openair-cn/GTPV1-U/nw-gtpv1u/NEWS | 0 openair-cn/GTPV1-U/nw-gtpv1u/README | 0 .../GTPV1-U/nw-gtpv1u/include/NwGtpv1uLog.h | 83 + .../nw-gtpv1u/include/NwGtpv1uPrivate.h | 230 + .../GTPV1-U/nw-gtpv1u/include/NwGtpv1uTrxn.h | 88 + .../include/NwGtpv1uTunnelEndPoint.h | 85 + .../GTPV1-U/nw-gtpv1u/shared/NwGtpv1u.h | 578 + .../GTPV1-U/nw-gtpv1u/shared/NwGtpv1uError.h | 62 + .../GTPV1-U/nw-gtpv1u/shared/NwGtpv1uIe.h | 66 + .../GTPV1-U/nw-gtpv1u/shared/NwGtpv1uMsg.h | 320 + openair-cn/GTPV1-U/nw-gtpv1u/shared/NwLog.h | 88 + openair-cn/GTPV1-U/nw-gtpv1u/shared/NwTypes.h | 83 + openair-cn/GTPV1-U/nw-gtpv1u/shared/NwUtils.h | 68 + openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c | 886 + .../GTPV1-U/nw-gtpv1u/src/NwGtpv1uMsg.c | 479 + .../GTPV1-U/nw-gtpv1u/src/NwGtpv1uTrxn.c | 391 + .../nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c | 134 + .../GTPV1-U/nw-gtpv1u/test-app/Makefile.am | 5 + .../GTPV1-U/nw-gtpv1u/test-app/Makefile.in | 461 + .../test-app/nw-helloworld/Makefile.am | 17 + .../test-app/nw-helloworld/Makefile.in | 433 + .../nw-gtpv1u/test-app/nw-helloworld/NwEvt.h | 81 + .../nw-helloworld/NwMiniLogMgrEntity.c | 60 + .../nw-helloworld/NwMiniLogMgrEntity.h | 58 + .../nw-helloworld/NwMiniTmrMgrEntity.c | 101 + .../nw-helloworld/NwMiniTmrMgrEntity.h | 54 + .../test-app/nw-helloworld/NwMiniUdpEntity.c | 155 + .../test-app/nw-helloworld/NwMiniUdpEntity.h | 52 + .../test-app/nw-helloworld/NwMiniUlpEntity.c | 306 + .../test-app/nw-helloworld/NwMiniUlpEntity.h | 65 + .../test-app/nw-helloworld/helloworld.c | 207 + openair-cn/GTPV2-C/Makefile.am | 1 + openair-cn/GTPV2-C/nwgtpv2c-0.11/AUTHORS | 1 + openair-cn/GTPV2-C/nwgtpv2c-0.11/COPYING | 26 + openair-cn/GTPV2-C/nwgtpv2c-0.11/ChangeLog | 0 openair-cn/GTPV2-C/nwgtpv2c-0.11/INSTALL | 370 + openair-cn/GTPV2-C/nwgtpv2c-0.11/Makefile.am | 6 + openair-cn/GTPV2-C/nwgtpv2c-0.11/NEWS | 0 openair-cn/GTPV2-C/nwgtpv2c-0.11/README | 168 + openair-cn/GTPV2-C/nwgtpv2c-0.11/aclocal.m4 | 986 + openair-cn/GTPV2-C/nwgtpv2c-0.11/configure.ac | 58 + .../nwgtpv2c-0.11/include/NwGtpv2cLog.h | 83 + .../include/NwGtpv2cMsgIeParseInfo.h | 97 + .../nwgtpv2c-0.11/include/NwGtpv2cPrivate.h | 242 + .../nwgtpv2c-0.11/include/NwGtpv2cTrxn.h | 117 + .../nwgtpv2c-0.11/include/NwGtpv2cTunnel.h | 80 + .../GTPV2-C/nwgtpv2c-0.11/include/queue.h | 566 + .../GTPV2-C/nwgtpv2c-0.11/include/tree.h | 678 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwError.h | 65 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2c.h | 595 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cIe.h | 159 + .../nwgtpv2c-0.11/shared/NwGtpv2cMsg.h | 631 + .../nwgtpv2c-0.11/shared/NwGtpv2cMsgParser.h | 154 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwLog.h | 85 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwTypes.h | 83 + .../GTPV2-C/nwgtpv2c-0.11/shared/NwUtils.h | 69 + .../GTPV2-C/nwgtpv2c-0.11/src/Makefile.am | 46 + .../GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2c.c | 1862 ++ .../GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsg.c | 734 + .../src/NwGtpv2cMsgIeParseInfo.c | 737 + .../nwgtpv2c-0.11/src/NwGtpv2cMsgParser.c | 316 + .../GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTrxn.c | 405 + .../nwgtpv2c-0.11/src/NwGtpv2cTunnel.c | 98 + .../nwgtpv2c-0.11/test-app/Makefile.am | 6 + .../test-app/nw-egtping/Makefile.am | 24 + .../test-app/nw-egtping/NwEgtPingMain.c | 290 + .../nwgtpv2c-0.11/test-app/nw-egtping/NwEvt.h | 81 + .../test-app/nw-egtping/NwMiniLogMgrEntity.c | 69 + .../test-app/nw-egtping/NwMiniLogMgrEntity.h | 90 + .../test-app/nw-egtping/NwMiniTmrMgrEntity.c | 97 + .../test-app/nw-egtping/NwMiniTmrMgrEntity.h | 59 + .../test-app/nw-egtping/NwMiniUdpEntity.c | 225 + .../test-app/nw-egtping/NwMiniUdpEntity.h | 57 + .../test-app/nw-egtping/NwMiniUlpEntity.c | 222 + .../test-app/nw-egtping/NwMiniUlpEntity.h | 55 + .../test-app/nw-helloworld/Makefile.am | 21 + .../test-app/nw-helloworld/NwEvt.h | 81 + .../nw-helloworld/NwMiniLogMgrEntity.c | 69 + .../nw-helloworld/NwMiniLogMgrEntity.h | 90 + .../nw-helloworld/NwMiniTmrMgrEntity.c | 100 + .../nw-helloworld/NwMiniTmrMgrEntity.h | 59 + .../test-app/nw-helloworld/NwMiniUdpEntity.c | 153 + .../test-app/nw-helloworld/NwMiniUdpEntity.h | 52 + .../test-app/nw-helloworld/NwMiniUlpEntity.c | 285 + .../test-app/nw-helloworld/NwMiniUlpEntity.h | 50 + .../test-app/nw-helloworld/helloworld.c | 185 + openair-cn/INSTALL | 370 + openair-cn/INTERTASK_INTERFACE/Makefile.am | 20 + .../INTERTASK_INTERFACE/intertask_interface.c | 459 + .../INTERTASK_INTERFACE/intertask_interface.h | 142 + .../intertask_interface_dump.c | 503 + .../intertask_interface_dump.h | 41 + .../intertask_interface_init.h | 87 + .../intertask_interface_types.h | 145 + .../intertask_messages_def.h | 5 + openair-cn/INTERTASK_INTERFACE/messages_def.h | 5 + .../INTERTASK_INTERFACE/messages_types.h | 15 + openair-cn/INTERTASK_INTERFACE/tasks_def.h | 4 + openair-cn/INTERTASK_INTERFACE/timer.c | 251 + openair-cn/INTERTASK_INTERFACE/timer.h | 76 + .../INTERTASK_INTERFACE/timer_messages_def.h | 1 + .../timer_messages_types.h | 9 + openair-cn/MME_APP/Makefile.am | 21 + openair-cn/MME_APP/mme_app_authentication.c | 285 + openair-cn/MME_APP/mme_app_bearer.c | 351 + openair-cn/MME_APP/mme_app_context.c | 348 + openair-cn/MME_APP/mme_app_defs.h | 72 + openair-cn/MME_APP/mme_app_extern.h | 36 + openair-cn/MME_APP/mme_app_main.c | 129 + openair-cn/MME_APP/mme_app_statistics.c | 25 + openair-cn/MME_APP/mme_app_statistics.h | 6 + openair-cn/MME_APP/mme_app_ue_context.h | 225 + openair-cn/MME_APP/s6a_2_nas_cause.c | 95 + openair-cn/Makefile.am | 63 + openair-cn/NAS/EURECOM-NAS/Makefile | 65 + openair-cn/NAS/EURECOM-NAS/Makefile.inc | 39 + openair-cn/NAS/EURECOM-NAS/Makerules | 26 + openair-cn/NAS/EURECOM-NAS/src/MMEprocess.c | 319 + openair-cn/NAS/EURECOM-NAS/src/Makefile | 118 + openair-cn/NAS/EURECOM-NAS/src/UEprocess.c | 467 + openair-cn/NAS/EURECOM-NAS/src/api/Makefile | 47 + .../NAS/EURECOM-NAS/src/api/mme/Makefile | 21 + .../NAS/EURECOM-NAS/src/api/mme/mme_api.c | 501 + .../NAS/EURECOM-NAS/src/api/mme/mme_api.h | 105 + .../NAS/EURECOM-NAS/src/api/network/Makefile | 185 + .../EURECOM-NAS/src/api/network/as_message.c | 347 + .../EURECOM-NAS/src/api/network/as_message.h | 515 + .../EURECOM-NAS/src/api/network/l2_message.h | 283 + .../EURECOM-NAS/src/api/network/nas_message.c | 725 + .../EURECOM-NAS/src/api/network/nas_message.h | 89 + .../EURECOM-NAS/src/api/network/network_api.c | 416 + .../EURECOM-NAS/src/api/network/network_api.h | 52 + .../NAS/EURECOM-NAS/src/api/user/Makefile | 21 + .../NAS/EURECOM-NAS/src/api/user/at_command.c | 1831 ++ .../NAS/EURECOM-NAS/src/api/user/at_command.h | 839 + .../NAS/EURECOM-NAS/src/api/user/at_error.c | 420 + .../NAS/EURECOM-NAS/src/api/user/at_error.h | 173 + .../EURECOM-NAS/src/api/user/at_response.c | 1126 + .../EURECOM-NAS/src/api/user/at_response.h | 761 + .../NAS/EURECOM-NAS/src/api/user/tst/Makefile | 37 + .../EURECOM-NAS/src/api/user/tst/at_parser.c | 130 + .../EURECOM-NAS/src/api/user/tst/at_parser.in | 2 + .../src/api/user/tst/at_parser.in.bis | 59 + .../src/api/user/tst/at_parser.out | 90 + .../src/api/user/tst/at_parser.out.bis | 204 + .../EURECOM-NAS/src/api/user/tst/smartcom.txt | 23 + .../NAS/EURECOM-NAS/src/api/user/user_api.c | 799 + .../NAS/EURECOM-NAS/src/api/user/user_api.h | 58 + .../src/api/user/user_indication.c | 156 + .../src/api/user/user_indication.h | 103 + .../NAS/EURECOM-NAS/src/api/usim/Makefile | 21 + .../EURECOM-NAS/src/api/usim/aka_functions.c | 399 + .../EURECOM-NAS/src/api/usim/aka_functions.h | 14 + .../NAS/EURECOM-NAS/src/api/usim/usim_api.c | 292 + .../NAS/EURECOM-NAS/src/api/usim/usim_api.h | 329 + openair-cn/NAS/EURECOM-NAS/src/emm/Attach.c | 2388 ++ .../NAS/EURECOM-NAS/src/emm/Authentication.c | 1382 + openair-cn/NAS/EURECOM-NAS/src/emm/Detach.c | 654 + .../NAS/EURECOM-NAS/src/emm/EmmCommon.c | 483 + .../NAS/EURECOM-NAS/src/emm/EmmCommon.h | 84 + .../NAS/EURECOM-NAS/src/emm/EmmStatusHdl.c | 145 + .../NAS/EURECOM-NAS/src/emm/Identification.c | 568 + openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.c | 1137 + openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.h | 62 + .../NAS/EURECOM-NAS/src/emm/LowerLayer.c | 478 + .../NAS/EURECOM-NAS/src/emm/LowerLayer.h | 73 + openair-cn/NAS/EURECOM-NAS/src/emm/Makefile | 213 + .../EURECOM-NAS/src/emm/SecurityModeControl.c | 953 + .../EURECOM-NAS/src/emm/ServiceRequestHdl.c | 110 + .../EURECOM-NAS/src/emm/TrackingAreaUpdate.c | 107 + openair-cn/NAS/EURECOM-NAS/src/emm/emmData.h | 484 + .../NAS/EURECOM-NAS/src/emm/emm_data_ctx.c | 59 + openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.c | 1049 + openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.h | 79 + openair-cn/NAS/EURECOM-NAS/src/emm/emm_proc.h | 224 + .../EURECOM-NAS/src/emm/msg/AttachAccept.c | 310 + .../EURECOM-NAS/src/emm/msg/AttachAccept.h | 110 + .../EURECOM-NAS/src/emm/msg/AttachComplete.c | 45 + .../EURECOM-NAS/src/emm/msg/AttachComplete.h | 42 + .../EURECOM-NAS/src/emm/msg/AttachReject.c | 81 + .../EURECOM-NAS/src/emm/msg/AttachReject.h | 55 + .../EURECOM-NAS/src/emm/msg/AttachRequest.c | 423 + .../EURECOM-NAS/src/emm/msg/AttachRequest.h | 125 + .../src/emm/msg/AuthenticationFailure.c | 81 + .../src/emm/msg/AuthenticationFailure.h | 55 + .../src/emm/msg/AuthenticationReject.c | 29 + .../src/emm/msg/AuthenticationReject.h | 37 + .../src/emm/msg/AuthenticationRequest.c | 63 + .../src/emm/msg/AuthenticationRequest.h | 50 + .../src/emm/msg/AuthenticationResponse.c | 45 + .../src/emm/msg/AuthenticationResponse.h | 42 + .../src/emm/msg/CsServiceNotification.c | 148 + .../src/emm/msg/CsServiceNotification.h | 70 + .../EURECOM-NAS/src/emm/msg/DetachAccept.c | 29 + .../EURECOM-NAS/src/emm/msg/DetachAccept.h | 37 + .../EURECOM-NAS/src/emm/msg/DetachRequest.c | 54 + .../EURECOM-NAS/src/emm/msg/DetachRequest.h | 50 + .../src/emm/msg/DownlinkNasTransport.c | 45 + .../src/emm/msg/DownlinkNasTransport.h | 42 + .../EURECOM-NAS/src/emm/msg/EmmInformation.c | 161 + .../EURECOM-NAS/src/emm/msg/EmmInformation.h | 70 + .../NAS/EURECOM-NAS/src/emm/msg/EmmStatus.c | 44 + .../NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h | 42 + .../src/emm/msg/ExtendedServiceRequest.c | 61 + .../src/emm/msg/ExtendedServiceRequest.h | 55 + .../src/emm/msg/GutiReallocationCommand.c | 82 + .../src/emm/msg/GutiReallocationCommand.h | 55 + .../src/emm/msg/GutiReallocationComplete.c | 29 + .../src/emm/msg/GutiReallocationComplete.h | 37 + .../EURECOM-NAS/src/emm/msg/IdentityRequest.c | 38 + .../EURECOM-NAS/src/emm/msg/IdentityRequest.h | 42 + .../src/emm/msg/IdentityResponse.c | 45 + .../src/emm/msg/IdentityResponse.h | 42 + .../NAS/EURECOM-NAS/src/emm/msg/Makefile | 41 + .../src/emm/msg/SecurityModeCommand.c | 145 + .../src/emm/msg/SecurityModeCommand.h | 72 + .../src/emm/msg/SecurityModeComplete.c | 70 + .../src/emm/msg/SecurityModeComplete.h | 51 + .../src/emm/msg/SecurityModeReject.c | 44 + .../src/emm/msg/SecurityModeReject.h | 42 + .../EURECOM-NAS/src/emm/msg/ServiceReject.c | 50 + .../EURECOM-NAS/src/emm/msg/ServiceReject.h | 47 + .../EURECOM-NAS/src/emm/msg/ServiceRequest.c | 57 + .../EURECOM-NAS/src/emm/msg/ServiceRequest.h | 44 + .../src/emm/msg/TrackingAreaUpdateAccept.c | 352 + .../src/emm/msg/TrackingAreaUpdateAccept.h | 113 + .../src/emm/msg/TrackingAreaUpdateComplete.c | 29 + .../src/emm/msg/TrackingAreaUpdateComplete.h | 37 + .../src/emm/msg/TrackingAreaUpdateReject.c | 45 + .../src/emm/msg/TrackingAreaUpdateReject.h | 42 + .../src/emm/msg/TrackingAreaUpdateRequest.c | 484 + .../src/emm/msg/TrackingAreaUpdateRequest.h | 145 + .../src/emm/msg/UplinkNasTransport.c | 45 + .../src/emm/msg/UplinkNasTransport.h | 42 + .../NAS/EURECOM-NAS/src/emm/msg/emm_cause.h | 107 + .../NAS/EURECOM-NAS/src/emm/msg/emm_msg.c | 409 + .../NAS/EURECOM-NAS/src/emm/msg/emm_msg.h | 116 + .../NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h | 116 + .../src/emm/sap/EmmCommonProcedureInitiated.c | 155 + .../EURECOM-NAS/src/emm/sap/EmmDeregistered.c | 202 + .../src/emm/sap/EmmDeregisteredAttachNeeded.c | 78 + .../sap/EmmDeregisteredAttemptingToAttach.c | 120 + .../src/emm/sap/EmmDeregisteredInitiated.c | 128 + .../emm/sap/EmmDeregisteredLimitedService.c | 141 + .../emm/sap/EmmDeregisteredNoCellAvailable.c | 120 + .../src/emm/sap/EmmDeregisteredNoImsi.c | 79 + .../emm/sap/EmmDeregisteredNormalService.c | 141 + .../src/emm/sap/EmmDeregisteredPlmnSearch.c | 136 + .../NAS/EURECOM-NAS/src/emm/sap/EmmNull.c | 110 + .../EURECOM-NAS/src/emm/sap/EmmRegistered.c | 196 + .../emm/sap/EmmRegisteredAttemptingToUpdate.c | 80 + .../sap/EmmRegisteredImsiDetachInitiated.c | 79 + .../src/emm/sap/EmmRegisteredInitiated.c | 240 + .../src/emm/sap/EmmRegisteredLimitedService.c | 75 + .../emm/sap/EmmRegisteredNoCellAvailable.c | 76 + .../src/emm/sap/EmmRegisteredNormalService.c | 75 + .../src/emm/sap/EmmRegisteredPlmnSearch.c | 103 + .../src/emm/sap/EmmRegisteredUpdateNeeded.c | 81 + .../src/emm/sap/EmmServiceRequestInitiated.c | 77 + .../sap/EmmTrackingAreaUpdatingInitiated.c | 77 + .../NAS/EURECOM-NAS/src/emm/sap/Makefile | 42 + .../NAS/EURECOM-NAS/src/emm/sap/emm_as.c | 1808 ++ .../NAS/EURECOM-NAS/src/emm/sap/emm_as.h | 47 + .../NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h | 240 + .../NAS/EURECOM-NAS/src/emm/sap/emm_esm.c | 157 + .../NAS/EURECOM-NAS/src/emm/sap/emm_esm.h | 47 + .../NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h | 94 + .../NAS/EURECOM-NAS/src/emm/sap/emm_fsm.c | 397 + .../NAS/EURECOM-NAS/src/emm/sap/emm_fsm.h | 95 + .../NAS/EURECOM-NAS/src/emm/sap/emm_recv.c | 1037 + .../NAS/EURECOM-NAS/src/emm/sap/emm_recv.h | 120 + .../NAS/EURECOM-NAS/src/emm/sap/emm_reg.c | 100 + .../NAS/EURECOM-NAS/src/emm/sap/emm_reg.h | 47 + .../NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h | 145 + .../NAS/EURECOM-NAS/src/emm/sap/emm_sap.c | 120 + .../NAS/EURECOM-NAS/src/emm/sap/emm_sap.h | 151 + .../NAS/EURECOM-NAS/src/emm/sap/emm_send.c | 1171 + .../NAS/EURECOM-NAS/src/emm/sap/emm_send.h | 130 + .../esm/DedicatedEpsBearerContextActivation.c | 635 + .../esm/DefaultEpsBearerContextActivation.c | 757 + .../src/esm/EpsBearerContextDeactivation.c | 749 + .../NAS/EURECOM-NAS/src/esm/EsmStatusHdl.c | 183 + openair-cn/NAS/EURECOM-NAS/src/esm/Makefile | 201 + .../NAS/EURECOM-NAS/src/esm/PdnConnectivity.c | 1424 + .../NAS/EURECOM-NAS/src/esm/PdnDisconnect.c | 702 + openair-cn/NAS/EURECOM-NAS/src/esm/esmData.h | 181 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.c | 704 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.h | 107 + .../NAS/EURECOM-NAS/src/esm/esm_ebr_context.c | 593 + .../NAS/EURECOM-NAS/src/esm/esm_ebr_context.h | 68 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_ip.c | 43 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.c | 398 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.h | 63 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_proc.h | 216 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.c | 543 + openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.h | 84 + .../ActivateDedicatedEpsBearerContextAccept.c | 70 + .../ActivateDedicatedEpsBearerContextAccept.h | 53 + .../ActivateDedicatedEpsBearerContextReject.c | 82 + .../ActivateDedicatedEpsBearerContextReject.h | 57 + ...ActivateDedicatedEpsBearerContextRequest.c | 215 + ...ActivateDedicatedEpsBearerContextRequest.h | 88 + .../ActivateDefaultEpsBearerContextAccept.c | 70 + .../ActivateDefaultEpsBearerContextAccept.h | 53 + .../ActivateDefaultEpsBearerContextReject.c | 82 + .../ActivateDefaultEpsBearerContextReject.h | 57 + .../ActivateDefaultEpsBearerContextRequest.c | 267 + .../ActivateDefaultEpsBearerContextRequest.h | 100 + .../esm/msg/BearerResourceAllocationReject.c | 82 + .../esm/msg/BearerResourceAllocationReject.h | 57 + .../esm/msg/BearerResourceAllocationRequest.c | 100 + .../esm/msg/BearerResourceAllocationRequest.h | 63 + .../msg/BearerResourceModificationReject.c | 82 + .../msg/BearerResourceModificationReject.h | 57 + .../msg/BearerResourceModificationRequest.c | 134 + .../msg/BearerResourceModificationRequest.h | 69 + .../msg/DeactivateEpsBearerContextAccept.c | 70 + .../msg/DeactivateEpsBearerContextAccept.h | 53 + .../msg/DeactivateEpsBearerContextRequest.c | 82 + .../msg/DeactivateEpsBearerContextRequest.h | 57 + .../src/esm/msg/EsmInformationRequest.c | 31 + .../src/esm/msg/EsmInformationRequest.h | 39 + .../src/esm/msg/EsmInformationResponse.c | 93 + .../src/esm/msg/EsmInformationResponse.h | 58 + .../NAS/EURECOM-NAS/src/esm/msg/EsmStatus.c | 44 + .../NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h | 44 + .../NAS/EURECOM-NAS/src/esm/msg/Makefile | 41 + .../esm/msg/ModifyEpsBearerContextAccept.c | 70 + .../esm/msg/ModifyEpsBearerContextAccept.h | 53 + .../esm/msg/ModifyEpsBearerContextReject.c | 82 + .../esm/msg/ModifyEpsBearerContextReject.h | 57 + .../esm/msg/ModifyEpsBearerContextRequest.c | 231 + .../esm/msg/ModifyEpsBearerContextRequest.h | 88 + .../src/esm/msg/PdnConnectivityReject.c | 81 + .../src/esm/msg/PdnConnectivityReject.h | 57 + .../src/esm/msg/PdnConnectivityRequest.c | 126 + .../src/esm/msg/PdnConnectivityRequest.h | 69 + .../src/esm/msg/PdnDisconnectReject.c | 81 + .../src/esm/msg/PdnDisconnectReject.h | 57 + .../src/esm/msg/PdnDisconnectRequest.c | 77 + .../src/esm/msg/PdnDisconnectRequest.h | 57 + .../NAS/EURECOM-NAS/src/esm/msg/esm_cause.h | 104 + .../NAS/EURECOM-NAS/src/esm/msg/esm_msg.c | 372 + .../NAS/EURECOM-NAS/src/esm/msg/esm_msg.h | 102 + .../NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h | 99 + .../NAS/EURECOM-NAS/src/esm/sap/Makefile | 42 + .../NAS/EURECOM-NAS/src/esm/sap/esm_recv.c | 1219 + .../NAS/EURECOM-NAS/src/esm/sap/esm_recv.h | 140 + .../NAS/EURECOM-NAS/src/esm/sap/esm_sap.c | 1138 + .../NAS/EURECOM-NAS/src/esm/sap/esm_sap.h | 47 + .../NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h | 150 + .../NAS/EURECOM-NAS/src/esm/sap/esm_send.c | 677 + .../NAS/EURECOM-NAS/src/esm/sap/esm_send.h | 134 + .../NAS/EURECOM-NAS/src/ies/AccessPointName.c | 66 + .../NAS/EURECOM-NAS/src/ies/AccessPointName.h | 24 + .../src/ies/AdditionalUpdateResult.c | 75 + .../src/ies/AdditionalUpdateResult.h | 26 + .../src/ies/AdditionalUpdateType.c | 34 + .../src/ies/AdditionalUpdateType.h | 22 + .../src/ies/ApnAggregateMaximumBitRate.c | 65 + .../src/ies/ApnAggregateMaximumBitRate.h | 25 + .../src/ies/AuthenticationFailureParameter.c | 66 + .../src/ies/AuthenticationFailureParameter.h | 24 + .../src/ies/AuthenticationParameterAutn.c | 66 + .../src/ies/AuthenticationParameterAutn.h | 24 + .../src/ies/AuthenticationParameterRand.c | 60 + .../src/ies/AuthenticationParameterRand.h | 24 + .../src/ies/AuthenticationResponseParameter.c | 63 + .../src/ies/AuthenticationResponseParameter.h | 24 + .../src/ies/CipheringKeySequenceNumber.c | 75 + .../src/ies/CipheringKeySequenceNumber.h | 26 + openair-cn/NAS/EURECOM-NAS/src/ies/Cli.c | 66 + openair-cn/NAS/EURECOM-NAS/src/ies/Cli.h | 24 + .../NAS/EURECOM-NAS/src/ies/CsfbResponse.c | 75 + .../NAS/EURECOM-NAS/src/ies/CsfbResponse.h | 26 + .../EURECOM-NAS/src/ies/DaylightSavingTime.c | 61 + .../EURECOM-NAS/src/ies/DaylightSavingTime.h | 22 + .../NAS/EURECOM-NAS/src/ies/DetachType.c | 82 + .../NAS/EURECOM-NAS/src/ies/DetachType.h | 36 + .../NAS/EURECOM-NAS/src/ies/DrxParameter.c | 64 + .../NAS/EURECOM-NAS/src/ies/DrxParameter.h | 27 + .../EURECOM-NAS/src/ies/EmergencyNumberList.c | 66 + .../EURECOM-NAS/src/ies/EmergencyNumberList.h | 25 + openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.c | 53 + openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.h | 22 + .../NAS/EURECOM-NAS/src/ies/EpsAttachResult.c | 77 + .../NAS/EURECOM-NAS/src/ies/EpsAttachResult.h | 28 + .../NAS/EURECOM-NAS/src/ies/EpsAttachType.c | 77 + .../NAS/EURECOM-NAS/src/ies/EpsAttachType.h | 30 + .../src/ies/EpsBearerContextStatus.c | 56 + .../src/ies/EpsBearerContextStatus.h | 22 + .../EURECOM-NAS/src/ies/EpsBearerIdentity.c | 19 + .../EURECOM-NAS/src/ies/EpsBearerIdentity.h | 25 + .../EURECOM-NAS/src/ies/EpsMobileIdentity.c | 346 + .../EURECOM-NAS/src/ies/EpsMobileIdentity.h | 68 + .../src/ies/EpsNetworkFeatureSupport.c | 61 + .../src/ies/EpsNetworkFeatureSupport.h | 22 + .../EURECOM-NAS/src/ies/EpsQualityOfService.c | 169 + .../EURECOM-NAS/src/ies/EpsQualityOfService.h | 38 + .../NAS/EURECOM-NAS/src/ies/EpsUpdateResult.c | 75 + .../NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h | 26 + .../NAS/EURECOM-NAS/src/ies/EpsUpdateType.c | 80 + .../NAS/EURECOM-NAS/src/ies/EpsUpdateType.h | 29 + openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.c | 53 + openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.h | 22 + .../src/ies/EsmInformationTransferFlag.c | 75 + .../src/ies/EsmInformationTransferFlag.h | 26 + .../EURECOM-NAS/src/ies/EsmMessageContainer.c | 78 + .../EURECOM-NAS/src/ies/EsmMessageContainer.h | 24 + .../NAS/EURECOM-NAS/src/ies/GprsTimer.c | 63 + .../NAS/EURECOM-NAS/src/ies/GprsTimer.h | 31 + openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.c | 77 + openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.h | 28 + .../NAS/EURECOM-NAS/src/ies/IdentityType2.c | 77 + .../NAS/EURECOM-NAS/src/ies/IdentityType2.h | 30 + .../NAS/EURECOM-NAS/src/ies/ImeisvRequest.c | 75 + .../NAS/EURECOM-NAS/src/ies/ImeisvRequest.h | 26 + .../src/ies/KsiAndSequenceNumber.c | 56 + .../src/ies/KsiAndSequenceNumber.h | 25 + .../EURECOM-NAS/src/ies/LcsClientIdentity.c | 66 + .../EURECOM-NAS/src/ies/LcsClientIdentity.h | 24 + .../NAS/EURECOM-NAS/src/ies/LcsIndicator.c | 53 + .../NAS/EURECOM-NAS/src/ies/LcsIndicator.h | 22 + .../src/ies/LinkedEpsBearerIdentity.c | 77 + .../src/ies/LinkedEpsBearerIdentity.h | 26 + .../src/ies/LlcServiceAccessPointIdentifier.c | 54 + .../src/ies/LlcServiceAccessPointIdentifier.h | 22 + .../src/ies/LocationAreaIdentification.c | 76 + .../src/ies/LocationAreaIdentification.h | 30 + openair-cn/NAS/EURECOM-NAS/src/ies/Makefile | 969 + .../NAS/EURECOM-NAS/src/ies/MessageType.c | 19 + .../NAS/EURECOM-NAS/src/ies/MessageType.h | 22 + .../NAS/EURECOM-NAS/src/ies/MobileIdentity.c | 632 + .../NAS/EURECOM-NAS/src/ies/MobileIdentity.h | 82 + .../src/ies/MobileStationClassmark2.c | 114 + .../src/ies/MobileStationClassmark2.h | 40 + .../src/ies/MobileStationClassmark3.c | 19 + .../src/ies/MobileStationClassmark3.h | 24 + .../EURECOM-NAS/src/ies/MsNetworkCapability.c | 66 + .../EURECOM-NAS/src/ies/MsNetworkCapability.h | 24 + .../EURECOM-NAS/src/ies/NasKeySetIdentifier.c | 82 + .../EURECOM-NAS/src/ies/NasKeySetIdentifier.h | 32 + .../EURECOM-NAS/src/ies/NasMessageContainer.c | 66 + .../EURECOM-NAS/src/ies/NasMessageContainer.h | 24 + .../src/ies/NasSecurityAlgorithms.c | 57 + .../src/ies/NasSecurityAlgorithms.h | 41 + .../NAS/EURECOM-NAS/src/ies/NetworkName.c | 82 + .../NAS/EURECOM-NAS/src/ies/NetworkName.h | 27 + openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.c | 52 + openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.h | 22 + .../NAS/EURECOM-NAS/src/ies/PTmsiSignature.c | 60 + .../NAS/EURECOM-NAS/src/ies/PTmsiSignature.h | 24 + .../src/ies/PacketFlowIdentifier.c | 61 + .../src/ies/PacketFlowIdentifier.h | 22 + .../NAS/EURECOM-NAS/src/ies/PagingIdentity.c | 54 + .../NAS/EURECOM-NAS/src/ies/PagingIdentity.h | 22 + .../NAS/EURECOM-NAS/src/ies/PdnAddress.c | 72 + .../NAS/EURECOM-NAS/src/ies/PdnAddress.h | 28 + openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.c | 77 + openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.h | 30 + openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.c | 79 + openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.h | 29 + .../src/ies/ProcedureTransactionIdentity.c | 19 + .../src/ies/ProcedureTransactionIdentity.h | 25 + .../src/ies/ProtocolConfigurationOptions.c | 85 + .../src/ies/ProtocolConfigurationOptions.h | 27 + .../src/ies/ProtocolDiscriminator.c | 19 + .../src/ies/ProtocolDiscriminator.h | 22 + .../EURECOM-NAS/src/ies/QualityOfService.c | 139 + .../EURECOM-NAS/src/ies/QualityOfService.h | 42 + .../NAS/EURECOM-NAS/src/ies/RadioPriority.c | 75 + .../NAS/EURECOM-NAS/src/ies/RadioPriority.h | 26 + .../NAS/EURECOM-NAS/src/ies/RequestType.c | 77 + .../NAS/EURECOM-NAS/src/ies/RequestType.h | 30 + .../EURECOM-NAS/src/ies/SecurityHeaderType.c | 19 + .../EURECOM-NAS/src/ies/SecurityHeaderType.h | 22 + .../NAS/EURECOM-NAS/src/ies/ServiceType.c | 75 + .../NAS/EURECOM-NAS/src/ies/ServiceType.h | 26 + openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.c | 52 + openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.h | 22 + openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.c | 53 + openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.h | 22 + .../EURECOM-NAS/src/ies/SupportedCodecList.c | 69 + .../EURECOM-NAS/src/ies/SupportedCodecList.h | 26 + openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.c | 53 + openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.h | 22 + .../NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.c | 83 + .../NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h | 30 + .../NAS/EURECOM-NAS/src/ies/TmsiStatus.c | 75 + .../NAS/EURECOM-NAS/src/ies/TmsiStatus.h | 26 + .../src/ies/TrackingAreaIdentity.c | 76 + .../src/ies/TrackingAreaIdentity.h | 30 + .../src/ies/TrackingAreaIdentityList.c | 92 + .../src/ies/TrackingAreaIdentityList.h | 37 + .../src/ies/TrafficFlowAggregateDescription.c | 19 + .../src/ies/TrafficFlowAggregateDescription.h | 24 + .../EURECOM-NAS/src/ies/TrafficFlowTemplate.c | 520 + .../EURECOM-NAS/src/ies/TrafficFlowTemplate.h | 171 + .../src/ies/TransactionIdentifier.c | 19 + .../src/ies/TransactionIdentifier.h | 24 + .../EURECOM-NAS/src/ies/UeNetworkCapability.c | 116 + .../EURECOM-NAS/src/ies/UeNetworkCapability.h | 83 + ...UeRadioCapabilityInformationUpdateNeeded.c | 75 + ...UeRadioCapabilityInformationUpdateNeeded.h | 26 + .../src/ies/UeSecurityCapability.c | 82 + .../src/ies/UeSecurityCapability.h | 71 + .../NAS/EURECOM-NAS/src/include/commonDef.h | 249 + .../NAS/EURECOM-NAS/src/include/networkDef.h | 251 + .../NAS/EURECOM-NAS/src/include/securityDef.h | 85 + .../NAS/EURECOM-NAS/src/include/userDef.h | 73 + openair-cn/NAS/EURECOM-NAS/src/nas_network.c | 248 + openair-cn/NAS/EURECOM-NAS/src/nas_network.h | 47 + openair-cn/NAS/EURECOM-NAS/src/nas_parser.c | 338 + openair-cn/NAS/EURECOM-NAS/src/nas_parser.h | 73 + openair-cn/NAS/EURECOM-NAS/src/nas_proc.c | 1582 ++ openair-cn/NAS/EURECOM-NAS/src/nas_proc.h | 116 + openair-cn/NAS/EURECOM-NAS/src/nas_user.c | 2482 ++ openair-cn/NAS/EURECOM-NAS/src/nas_user.h | 46 + openair-cn/NAS/EURECOM-NAS/src/util/Makefile | 101 + .../NAS/EURECOM-NAS/src/util/OctetString.c | 35 + .../NAS/EURECOM-NAS/src/util/OctetString.h | 18 + .../NAS/EURECOM-NAS/src/util/TLVDecoder.c | 28 + .../NAS/EURECOM-NAS/src/util/TLVDecoder.h | 112 + .../NAS/EURECOM-NAS/src/util/TLVEncoder.c | 25 + .../NAS/EURECOM-NAS/src/util/TLVEncoder.h | 77 + openair-cn/NAS/EURECOM-NAS/src/util/device.c | 233 + openair-cn/NAS/EURECOM-NAS/src/util/device.h | 55 + openair-cn/NAS/EURECOM-NAS/src/util/memory.c | 152 + openair-cn/NAS/EURECOM-NAS/src/util/memory.h | 47 + openair-cn/NAS/EURECOM-NAS/src/util/nas_log.c | 242 + openair-cn/NAS/EURECOM-NAS/src/util/nas_log.h | 93 + .../NAS/EURECOM-NAS/src/util/nas_timer.c | 729 + .../NAS/EURECOM-NAS/src/util/nas_timer.h | 66 + openair-cn/NAS/EURECOM-NAS/src/util/parser.c | 158 + openair-cn/NAS/EURECOM-NAS/src/util/parser.h | 73 + openair-cn/NAS/EURECOM-NAS/src/util/socket.c | 425 + openair-cn/NAS/EURECOM-NAS/src/util/socket.h | 56 + openair-cn/NAS/EURECOM-NAS/src/util/stty.c | 309 + .../NAS/EURECOM-NAS/src/util/tst/Makefile | 35 + .../NAS/EURECOM-NAS/src/util/tst/timer.c | 218 + .../EURECOM-NAS/src/util/tst/timer_debug.txt | 101 + openair-cn/NAS/EURECOM-NAS/tools/Makefile | 75 + openair-cn/NAS/EURECOM-NAS/tools/network.h | 92 + openair-cn/NAS/EURECOM-NAS/tools/ue_data.c | 355 + openair-cn/NAS/EURECOM-NAS/tools/usim_data.c | 518 + .../NAS/EURECOM-NAS/tst/MSC/ActivatePDN.png | Bin 0 -> 9430 bytes .../tst/MSC/AuthenticationReject.png | Bin 0 -> 21465 bytes .../NAS/EURECOM-NAS/tst/MSC/DeactivatePDN.png | Bin 0 -> 8833 bytes .../NAS/EURECOM-NAS/tst/MSC/InitialAttach.png | Bin 0 -> 32243 bytes .../tst/MSC/InitialAttachReject.png | Bin 0 -> 16271 bytes .../NAS/EURECOM-NAS/tst/MSC/NomalDetach.png | Bin 0 -> 5844 bytes openair-cn/NAS/EURECOM-NAS/tst/MSC/README | 34 + .../EURECOM-NAS/tst/MSC/SwitchOffDetach.png | Bin 0 -> 3697 bytes openair-cn/NAS/EURECOM-NAS/tst/MSC/msc_gen.py | 354 + openair-cn/NAS/EURECOM-NAS/tst/MSC/mscgen | Bin 0 -> 197742 bytes .../NAS/EURECOM-NAS/tst/as_simulator/Makefile | 231 + .../EURECOM-NAS/tst/as_simulator/as_data.c | 139 + .../EURECOM-NAS/tst/as_simulator/as_data.h | 56 + .../EURECOM-NAS/tst/as_simulator/as_process.c | 1231 + .../EURECOM-NAS/tst/as_simulator/as_process.h | 70 + .../tst/as_simulator/as_simulator.c | 630 + .../tst/as_simulator/as_simulator_parser.c | 206 + .../tst/as_simulator/as_simulator_parser.h | 61 + .../EURECOM-NAS/tst/as_simulator/nas_data.c | 919 + .../EURECOM-NAS/tst/as_simulator/nas_data.h | 81 + .../tst/as_simulator/nas_process.c | 937 + .../tst/as_simulator/nas_process.h | 43 + .../NAS/EURECOM-NAS/tst/network/Makefile | 187 + openair-cn/NAS/EURECOM-NAS/tst/network/README | 255 + .../EURECOM-NAS/tst/network/network_parser.c | 162 + .../EURECOM-NAS/tst/network/network_parser.h | 54 + .../tst/network/network_simulator.c | 1375 + openair-cn/NAS/EURECOM-NAS/tst/user/Makefile | 48 + .../NAS/EURECOM-NAS/tst/user/user_parser.c | 202 + .../NAS/EURECOM-NAS/tst/user/user_parser.h | 56 + .../NAS/EURECOM-NAS/tst/user/user_simulator.c | 301 + openair-cn/NAS/Makefile.am | 35 + openair-cn/NAS/Makefile.inc | 396 + openair-cn/NAS/nas_defs.h | 6 + openair-cn/NAS/nas_main.c | 108 + openair-cn/NEWS | 1 + openair-cn/OAISIM_MME/Makefile.am | 43 + openair-cn/OAISIM_MME/oai_mme_log.c | 54 + openair-cn/OAISIM_MME/oaisim_mme.c | 100 + openair-cn/OAISIM_MME/oaisim_mme.h | 33 + openair-cn/OAI_EPC/Makefile.am | 43 + openair-cn/OAI_EPC/oai_epc.c | 105 + openair-cn/OAI_EPC/oai_epc.h | 33 + openair-cn/OAI_EPC/oai_epc_log.c | 54 + openair-cn/OAI_SGW/Makefile.am | 34 + openair-cn/OAI_SGW/oai_sgw.c | 85 + openair-cn/OAI_SGW/oai_sgw.h | 38 + openair-cn/OAI_SGW/oai_sgw_log.c | 37 + openair-cn/README | 128 + openair-cn/S11/Makefile.am | 20 + openair-cn/S11/s11_common.c | 18 + openair-cn/S11/s11_common.h | 15 + openair-cn/S11/s11_ie_formatter.c | 1081 + openair-cn/S11/s11_ie_formatter.h | 209 + openair-cn/S11/s11_mme.h | 6 + openair-cn/S11/s11_mme_peer_manager.c | 4 + openair-cn/S11/s11_mme_session_manager.c | 177 + openair-cn/S11/s11_mme_session_manager.h | 44 + openair-cn/S11/s11_mme_task.c | 304 + openair-cn/S11/s11_sgw.c | 330 + openair-cn/S11/s11_sgw.h | 6 + openair-cn/S11/s11_sgw_bearer_manager.c | 208 + openair-cn/S11/s11_sgw_bearer_manager.h | 13 + openair-cn/S11/s11_sgw_session_manager.c | 495 + openair-cn/S11/s11_sgw_session_manager.h | 20 + openair-cn/S1AP/MESSAGES/ASN1/Makefile.am | 8 + .../ASN1/R10.5/S1AP-CommonDataTypes.asn | 232 + .../MESSAGES/ASN1/R10.5/S1AP-Constants.asn | 283 + .../MESSAGES/ASN1/R10.5/S1AP-Containers.asn | 197 + .../S1AP/MESSAGES/ASN1/R10.5/S1AP-IEs.asn | 1444 + .../MESSAGES/ASN1/R10.5/S1AP-PDU-Contents.asn | 2413 ++ .../ASN1/R10.5/S1AP-PDU-Descriptions.asn | 591 + .../S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU.asn | 413 + .../ASN1/R8.10/S1AP-CommonDataTypes.asn | 201 + .../MESSAGES/ASN1/R8.10/S1AP-Constants.asn | 249 + .../S1AP/MESSAGES/ASN1/R8.10/S1AP-IEs.asn | 1401 + .../MESSAGES/ASN1/R8.10/S1AP-PDU-Contents.asn | 2069 ++ .../S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU.asn | 663 + .../ASN1/R9.8/S1AP-CommonDataTypes.asn | 217 + .../MESSAGES/ASN1/R9.8/S1AP-Constants.asn | 265 + .../MESSAGES/ASN1/R9.8/S1AP-Containers.asn | 197 + .../S1AP/MESSAGES/ASN1/R9.8/S1AP-IEs.asn | 1213 + .../MESSAGES/ASN1/R9.8/S1AP-PDU-Contents.asn | 2419 ++ .../ASN1/R9.8/S1AP-PDU-Descriptions.asn | 591 + .../S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU.asn | 413 + openair-cn/S1AP/MESSAGES/ASN1/README | 15 + openair-cn/S1AP/MESSAGES/ASN1/asn1cpatch.p0 | 4240 +++ openair-cn/S1AP/MESSAGES/ASN1/asn1tostruct.py | 678 + openair-cn/S1AP/MESSAGES/Makefile.am | 777 + openair-cn/S1AP/MESSAGES/Makefile.inc | 760 + openair-cn/S1AP/Makefile.am | 36 + openair-cn/S1AP/Makefile.eNB | 96 + openair-cn/S1AP/Makefile.inc | 9 + openair-cn/S1AP/s1ap_common.c | 199 + openair-cn/S1AP/s1ap_common.h | 505 + openair-cn/S1AP/s1ap_eNB.c | 412 + openair-cn/S1AP/s1ap_eNB.h | 131 + openair-cn/S1AP/s1ap_eNB_decoder.c | 149 + openair-cn/S1AP/s1ap_eNB_decoder.h | 40 + openair-cn/S1AP/s1ap_eNB_defs.h | 336 + openair-cn/S1AP/s1ap_eNB_encoder.c | 300 + openair-cn/S1AP/s1ap_eNB_encoder.h | 37 + openair-cn/S1AP/s1ap_eNB_handlers.c | 382 + openair-cn/S1AP/s1ap_eNB_handlers.h | 49 + .../S1AP/s1ap_eNB_management_procedures.c | 115 + .../S1AP/s1ap_eNB_management_procedures.h | 37 + openair-cn/S1AP/s1ap_eNB_nas_procedures.c | 260 + openair-cn/S1AP/s1ap_eNB_nas_procedures.h | 44 + openair-cn/S1AP/s1ap_eNB_nnsf.c | 202 + openair-cn/S1AP/s1ap_eNB_nnsf.h | 49 + openair-cn/S1AP/s1ap_eNB_overload.c | 109 + openair-cn/S1AP/s1ap_eNB_overload.h | 48 + openair-cn/S1AP/s1ap_eNB_trace.c | 124 + openair-cn/S1AP/s1ap_eNB_trace.h | 49 + openair-cn/S1AP/s1ap_eNB_ue_context.c | 107 + openair-cn/S1AP/s1ap_eNB_ue_context.h | 90 + openair-cn/S1AP/s1ap_mme.c | 449 + openair-cn/S1AP/s1ap_mme.h | 188 + openair-cn/S1AP/s1ap_mme_decoder.c | 182 + openair-cn/S1AP/s1ap_mme_decoder.h | 40 + openair-cn/S1AP/s1ap_mme_encoder.c | 255 + openair-cn/S1AP/s1ap_mme_encoder.h | 39 + openair-cn/S1AP/s1ap_mme_handlers.c | 892 + openair-cn/S1AP/s1ap_mme_handlers.h | 91 + openair-cn/S1AP/s1ap_mme_itti_messaging.c | 54 + openair-cn/S1AP/s1ap_mme_itti_messaging.h | 41 + openair-cn/S1AP/s1ap_mme_nas_procedures.c | 386 + openair-cn/S1AP/s1ap_mme_nas_procedures.h | 71 + openair-cn/S1AP/s1ap_mme_retransmission.c | 146 + openair-cn/S1AP/s1ap_mme_retransmission.h | 52 + openair-cn/S1AP/s1ap_mme_ta.c | 150 + openair-cn/S1AP/s1ap_mme_ta.h | 45 + openair-cn/S6A/Makefile.am | 18 + openair-cn/S6A/freediameter/README.txt | 15 + .../S6A/freediameter/freediameter-1.1.5.patch | 4296 +++ .../S6A/freediameter/install_freediameter.sh | 116 + openair-cn/S6A/freediameter/make_certs.sh | 31 + openair-cn/S6A/freediameter/s6a.conf | 61 + openair-cn/S6A/s6a_apn_conf.c | 0 openair-cn/S6A/s6a_auth_info.c | 380 + openair-cn/S6A/s6a_defs.h | 201 + openair-cn/S6A/s6a_dict.c | 177 + openair-cn/S6A/s6a_error.c | 111 + openair-cn/S6A/s6a_messages.h | 47 + openair-cn/S6A/s6a_peer.c | 140 + openair-cn/S6A/s6a_subscription_data.c | 392 + openair-cn/S6A/s6a_task.c | 166 + openair-cn/S6A/s6a_up_loc.c | 284 + .../SCRIPTS/install_openvswitch1.9.0.bash | 55 + openair-cn/SCRIPTS/start_enb.bash | 320 + openair-cn/SCRIPTS/start_lte-epc-ovs.bash | 297 + openair-cn/SCRIPTS/start_lte-epc.bash | 324 + openair-cn/SCRIPTS/start_lte-sgw.bash | 310 + openair-cn/SCRIPTS/start_mme.bash | 35 + openair-cn/SCRIPTS/start_router.eur.bash | 221 + openair-cn/SCRIPTS/start_router.nord.eur.bash | 221 + openair-cn/SCRIPTS/start_spgw.bash | 70 + openair-cn/SCRIPTS/utils.bash | 276 + openair-cn/SCTP/Makefile.am | 18 + openair-cn/SCTP/Makefile.eNB | 47 + openair-cn/SCTP/sctp_common.c | 238 + openair-cn/SCTP/sctp_common.h | 68 + openair-cn/SCTP/sctp_eNB_defs.h | 66 + openair-cn/SCTP/sctp_itti_messaging.c | 60 + openair-cn/SCTP/sctp_itti_messaging.h | 13 + openair-cn/SCTP/sctp_primitives_client.c | 275 + openair-cn/SCTP/sctp_primitives_client.h | 110 + openair-cn/SCTP/sctp_primitives_server.c | 647 + openair-cn/SCTP/sctp_primitives_server.h | 70 + openair-cn/SECU/Makefile.am | 12 + openair-cn/SECU/Makefile.eNB | 38 + openair-cn/SECU/kdf.c | 45 + openair-cn/SECU/key_nas_deriver.c | 58 + openair-cn/SECU/key_nas_encryption.c | 45 + openair-cn/SECU/nas_stream_eea2.c | 72 + openair-cn/SECU/nas_stream_eia2.c | 89 + openair-cn/SECU/secu_defs.h | 57 + openair-cn/SGI/Makefile.am | 29 + openair-cn/SGI/sgi.h | 241 + openair-cn/SGI/sgi_egress.c | 307 + openair-cn/SGI/sgi_nf.c | 313 + openair-cn/SGI/sgi_pcap.c | 60 + openair-cn/SGI/sgi_socket.c | 774 + openair-cn/SGI/sgi_task.c | 292 + openair-cn/SGI/sgi_util.c | 208 + openair-cn/SGW-LITE/Makefile.am | 16 + openair-cn/SGW-LITE/s11_causes.c | 88 + openair-cn/SGW-LITE/s11_causes.h | 47 + openair-cn/SGW-LITE/sgw_lite.h | 63 + .../SGW-LITE/sgw_lite_context_manager.c | 364 + .../SGW-LITE/sgw_lite_context_manager.h | 232 + openair-cn/SGW-LITE/sgw_lite_defs.h | 49 + openair-cn/SGW-LITE/sgw_lite_handlers.c | 636 + openair-cn/SGW-LITE/sgw_lite_handlers.h | 42 + openair-cn/SGW-LITE/sgw_lite_ie_defs.h | 570 + openair-cn/SGW-LITE/sgw_lite_task.c | 143 + openair-cn/TEST/Makefile.am | 88 + openair-cn/TEST/oaisim_mme_client_test.c | 119 + openair-cn/TEST/oaisim_mme_itti_test.c | 101 + openair-cn/TEST/oaisim_mme_list_benchmark.c | 291 + openair-cn/TEST/oaisim_mme_s1ap_test.c | 180 + openair-cn/TEST/oaisim_mme_sctp_test.c | 88 + openair-cn/TEST/test_aes128_cmac_encrypt.c | 65 + openair-cn/TEST/test_aes128_ctr_decrypt.c | 60 + openair-cn/TEST/test_aes128_ctr_encrypt.c | 59 + openair-cn/TEST/test_kdf.c | 104 + openair-cn/TEST/test_s1ap.c | 183 + openair-cn/TEST/test_secu.c | 43 + openair-cn/TEST/test_secu_kenb.c | 43 + openair-cn/TEST/test_secu_knas.c | 70 + openair-cn/TEST/test_secu_knas_encrypt_eea2.c | 142 + openair-cn/TEST/test_secu_knas_encrypt_eia2.c | 178 + openair-cn/TEST/test_secu_knas_stream_int.c | 144 + openair-cn/TEST/test_util.c | 274 + openair-cn/TEST/test_util.h | 62 + openair-cn/UDP/Makefile.am | 11 + openair-cn/UDP/Makefile.eNB | 43 + openair-cn/UDP/udp_primitives_client.c | 161 + openair-cn/UDP/udp_primitives_client.h | 54 + openair-cn/UDP/udp_primitives_server.c | 286 + openair-cn/UDP/udp_primitives_server.h | 41 + openair-cn/UTILS/CONF/enb_default.conf | 12 + openair-cn/UTILS/CONF/enb_orcus.conf | 12 + openair-cn/UTILS/CONF/epc_nord.conf | 73 + openair-cn/UTILS/CONF/epc_orcus.conf | 73 + openair-cn/UTILS/CONF/mme_default.conf | 73 + openair-cn/UTILS/CONF/s6a.conf.in | 61 + openair-cn/UTILS/HASHTABLE/Makefile.am | 9 + openair-cn/UTILS/HASHTABLE/Makefile.eNB | 34 + openair-cn/UTILS/HASHTABLE/hashtable.c | 280 + openair-cn/UTILS/HASHTABLE/hashtable.h | 46 + openair-cn/UTILS/HASHTABLE/obj_hashtable.c | 238 + openair-cn/UTILS/HASHTABLE/obj_hashtable.h | 39 + openair-cn/UTILS/Makefile.am | 21 + openair-cn/UTILS/assertions.h | 85 + openair-cn/UTILS/backtrace.c | 65 + openair-cn/UTILS/backtrace.h | 40 + openair-cn/UTILS/conversions.c | 74 + openair-cn/UTILS/conversions.h | 270 + openair-cn/UTILS/enum_string.c | 62 + openair-cn/UTILS/enum_string.h | 21 + openair-cn/UTILS/log.c | 51 + openair-cn/UTILS/log.h | 46 + openair-cn/UTILS/mme_config.c | 287 + openair-cn/UTILS/mme_config.h | 127 + openair-cn/UTILS/mme_default_values.h | 150 + openair-cn/UTILS/mme_parser.y | 548 + openair-cn/UTILS/mme_scanner.l | 128 + openair-cn/UTILS/queue.h | 592 + openair-cn/UTILS/signals.c | 132 + openair-cn/UTILS/signals.h | 8 + openair-cn/UTILS/tree.h | 678 + openair-cn/aclocal.m4 | 9895 +++++++ openair-cn/autogen.sh | 8 + openair-cn/compile | 342 + openair-cn/config.guess | 1530 ++ openair-cn/config.h.in | 331 + openair-cn/config.sub | 1773 ++ openair-cn/configure | 22230 ++++++++++++++++ openair-cn/configure.ac | 374 + openair-cn/cppcheck.sh | 2 + openair-cn/depcomp | 707 + openair-cn/install-sh | 527 + openair-cn/ltmain.sh | 9661 +++++++ openair-cn/missing | 331 + openair-cn/valgrind.sh | 2 + 860 files changed, 212101 insertions(+) create mode 100644 openair-cn/AUTHORS create mode 100644 openair-cn/COMMON/as_message.h create mode 100644 openair-cn/COMMON/commonDef.h create mode 100644 openair-cn/COMMON/common_types.h create mode 100644 openair-cn/COMMON/gtpv1_u_messages_def.h create mode 100644 openair-cn/COMMON/gtpv1_u_messages_types.h create mode 100755 openair-cn/COMMON/ip_forward_messages_def.h create mode 100755 openair-cn/COMMON/ip_forward_messages_types.h create mode 100644 openair-cn/COMMON/messages_def.h create mode 100644 openair-cn/COMMON/messages_types.h create mode 100644 openair-cn/COMMON/mme_app_messages_def.h create mode 100644 openair-cn/COMMON/mme_app_messages_types.h create mode 100644 openair-cn/COMMON/nas_messages_def.h create mode 100644 openair-cn/COMMON/nas_messages_types.h create mode 100644 openair-cn/COMMON/s11_messages_def.h create mode 100644 openair-cn/COMMON/s11_messages_types.h create mode 100644 openair-cn/COMMON/s1ap_messages_def.h create mode 100644 openair-cn/COMMON/s1ap_messages_types.h create mode 100644 openair-cn/COMMON/s6a_messages_def.h create mode 100644 openair-cn/COMMON/s6a_messages_types.h create mode 100644 openair-cn/COMMON/sctp_messages_def.h create mode 100644 openair-cn/COMMON/sctp_messages_types.h create mode 100644 openair-cn/COMMON/security_types.h create mode 100644 openair-cn/COMMON/sgw_lite_def.h create mode 100644 openair-cn/COMMON/sgw_lite_messages_types.h create mode 100644 openair-cn/COMMON/tasks_def.h create mode 100644 openair-cn/COMMON/udp_messages_def.h create mode 100644 openair-cn/COMMON/udp_messages_types.h create mode 100644 openair-cn/COPYING create mode 100644 openair-cn/ChangeLog create mode 100644 openair-cn/DOCS/DOXYGEN/Doxyfile.in create mode 100644 openair-cn/DOCS/DOXYGEN/Makefile.am create mode 100644 openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.pdf create mode 100644 openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.tex create mode 100644 openair-cn/DOCS/Latex/EPC/EPC.pdf create mode 100644 openair-cn/DOCS/Latex/EPC/EPC.tex create mode 100644 openair-cn/DOCS/Latex/EPC/Makefile create mode 100644 openair-cn/DOCS/Makefile.am create mode 100644 openair-cn/GTPV1-U/Makefile.am create mode 100644 openair-cn/GTPV1-U/Makefile.eNB create mode 100644 openair-cn/GTPV1-U/gtpv1u.h create mode 100644 openair-cn/GTPV1-U/gtpv1u_eNB.c create mode 100644 openair-cn/GTPV1-U/gtpv1u_eNB_defs.h create mode 100644 openair-cn/GTPV1-U/gtpv1u_sgw_defs.h create mode 100644 openair-cn/GTPV1-U/gtpv1u_task.c create mode 100644 openair-cn/GTPV1-U/gtpv1u_teid_pool.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/AUTHORS create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/COPYING create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/ChangeLog create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/NEWS create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/README create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uLog.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uPrivate.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTrxn.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTunnelEndPoint.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1u.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uError.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uIe.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uMsg.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwLog.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwTypes.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/shared/NwUtils.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uMsg.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTrxn.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.am create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.in create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.am create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.in create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwEvt.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.c create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.h create mode 100644 openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/helloworld.c create mode 100644 openair-cn/GTPV2-C/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/AUTHORS create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/COPYING create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/ChangeLog create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/INSTALL create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/NEWS create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/README create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/aclocal.m4 create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/configure.ac create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cLog.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cMsgIeParseInfo.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cPrivate.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTrxn.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTunnel.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/queue.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/include/tree.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwError.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2c.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cIe.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsg.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsgParser.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwLog.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwTypes.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwUtils.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2c.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsg.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgIeParseInfo.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgParser.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTrxn.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTunnel.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEgtPingMain.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEvt.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/Makefile.am create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwEvt.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.c create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.h create mode 100644 openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/helloworld.c create mode 100644 openair-cn/INSTALL create mode 100644 openair-cn/INTERTASK_INTERFACE/Makefile.am create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface.c create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface.h create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.c create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.h create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface_init.h create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_interface_types.h create mode 100644 openair-cn/INTERTASK_INTERFACE/intertask_messages_def.h create mode 100644 openair-cn/INTERTASK_INTERFACE/messages_def.h create mode 100644 openair-cn/INTERTASK_INTERFACE/messages_types.h create mode 100644 openair-cn/INTERTASK_INTERFACE/tasks_def.h create mode 100644 openair-cn/INTERTASK_INTERFACE/timer.c create mode 100644 openair-cn/INTERTASK_INTERFACE/timer.h create mode 100644 openair-cn/INTERTASK_INTERFACE/timer_messages_def.h create mode 100644 openair-cn/INTERTASK_INTERFACE/timer_messages_types.h create mode 100644 openair-cn/MME_APP/Makefile.am create mode 100644 openair-cn/MME_APP/mme_app_authentication.c create mode 100644 openair-cn/MME_APP/mme_app_bearer.c create mode 100644 openair-cn/MME_APP/mme_app_context.c create mode 100644 openair-cn/MME_APP/mme_app_defs.h create mode 100644 openair-cn/MME_APP/mme_app_extern.h create mode 100644 openair-cn/MME_APP/mme_app_main.c create mode 100644 openair-cn/MME_APP/mme_app_statistics.c create mode 100644 openair-cn/MME_APP/mme_app_statistics.h create mode 100644 openair-cn/MME_APP/mme_app_ue_context.h create mode 100644 openair-cn/MME_APP/s6a_2_nas_cause.c create mode 100644 openair-cn/Makefile.am create mode 100644 openair-cn/NAS/EURECOM-NAS/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/Makefile.inc create mode 100644 openair-cn/NAS/EURECOM-NAS/Makerules create mode 100644 openair-cn/NAS/EURECOM-NAS/src/MMEprocess.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/UEprocess.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/mme/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/l2_message.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in.bis create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out.bis create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/tst/smartcom.txt create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/usim/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/Attach.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/Authentication.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/Detach.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/EmmStatusHdl.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/Identification.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/SecurityModeControl.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/ServiceRequestHdl.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/TrackingAreaUpdate.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/emmData.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/emm_data_ctx.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/emm_proc.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmCommonProcedureInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregistered.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttachNeeded.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttemptingToAttach.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredLimitedService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoCellAvailable.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoImsi.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNormalService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredPlmnSearch.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmNull.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegistered.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredAttemptingToUpdate.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredImsiDetachInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredLimitedService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNoCellAvailable.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNormalService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredPlmnSearch.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredUpdateNeeded.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmServiceRequestInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmTrackingAreaUpdatingInitiated.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/DedicatedEpsBearerContextActivation.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/DefaultEpsBearerContextActivation.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/EpsBearerContextDeactivation.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/EsmStatusHdl.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/PdnConnectivity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/PdnDisconnect.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esmData.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_ip.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_proc.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/Cli.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/Cli.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/include/commonDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/include/networkDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/include/securityDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/include/userDef.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_network.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_network.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_parser.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_proc.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_proc.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_user.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/nas_user.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/OctetString.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/OctetString.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/device.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/device.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/memory.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/memory.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/nas_log.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/nas_log.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/parser.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/socket.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/socket.h create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/stty.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/tst/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/tst/timer.c create mode 100644 openair-cn/NAS/EURECOM-NAS/src/util/tst/timer_debug.txt create mode 100644 openair-cn/NAS/EURECOM-NAS/tools/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/tools/network.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tools/ue_data.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tools/usim_data.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/ActivatePDN.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/AuthenticationReject.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/DeactivatePDN.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttach.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttachReject.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/NomalDetach.png create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/README create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/MSC/SwitchOffDetach.png create mode 100755 openair-cn/NAS/EURECOM-NAS/tst/MSC/msc_gen.py create mode 100755 openair-cn/NAS/EURECOM-NAS/tst/MSC/mscgen create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/network/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/network/README create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/network/network_simulator.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/user/Makefile create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.c create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.h create mode 100644 openair-cn/NAS/EURECOM-NAS/tst/user/user_simulator.c create mode 100644 openair-cn/NAS/Makefile.am create mode 100644 openair-cn/NAS/Makefile.inc create mode 100644 openair-cn/NAS/nas_defs.h create mode 100644 openair-cn/NAS/nas_main.c create mode 100644 openair-cn/NEWS create mode 100644 openair-cn/OAISIM_MME/Makefile.am create mode 100644 openair-cn/OAISIM_MME/oai_mme_log.c create mode 100644 openair-cn/OAISIM_MME/oaisim_mme.c create mode 100644 openair-cn/OAISIM_MME/oaisim_mme.h create mode 100644 openair-cn/OAI_EPC/Makefile.am create mode 100644 openair-cn/OAI_EPC/oai_epc.c create mode 100644 openair-cn/OAI_EPC/oai_epc.h create mode 100644 openair-cn/OAI_EPC/oai_epc_log.c create mode 100644 openair-cn/OAI_SGW/Makefile.am create mode 100644 openair-cn/OAI_SGW/oai_sgw.c create mode 100644 openair-cn/OAI_SGW/oai_sgw.h create mode 100644 openair-cn/OAI_SGW/oai_sgw_log.c create mode 100644 openair-cn/README create mode 100644 openair-cn/S11/Makefile.am create mode 100644 openair-cn/S11/s11_common.c create mode 100644 openair-cn/S11/s11_common.h create mode 100644 openair-cn/S11/s11_ie_formatter.c create mode 100644 openair-cn/S11/s11_ie_formatter.h create mode 100644 openair-cn/S11/s11_mme.h create mode 100644 openair-cn/S11/s11_mme_peer_manager.c create mode 100644 openair-cn/S11/s11_mme_session_manager.c create mode 100644 openair-cn/S11/s11_mme_session_manager.h create mode 100644 openair-cn/S11/s11_mme_task.c create mode 100644 openair-cn/S11/s11_sgw.c create mode 100644 openair-cn/S11/s11_sgw.h create mode 100644 openair-cn/S11/s11_sgw_bearer_manager.c create mode 100644 openair-cn/S11/s11_sgw_bearer_manager.h create mode 100644 openair-cn/S11/s11_sgw_session_manager.c create mode 100644 openair-cn/S11/s11_sgw_session_manager.h create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/Makefile.am create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-CommonDataTypes.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Constants.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Containers.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-IEs.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Contents.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Descriptions.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-CommonDataTypes.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-Constants.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-IEs.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU-Contents.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-CommonDataTypes.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Constants.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Containers.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-IEs.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Contents.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Descriptions.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU.asn create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/README create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/asn1cpatch.p0 create mode 100644 openair-cn/S1AP/MESSAGES/ASN1/asn1tostruct.py create mode 100644 openair-cn/S1AP/MESSAGES/Makefile.am create mode 100644 openair-cn/S1AP/MESSAGES/Makefile.inc create mode 100644 openair-cn/S1AP/Makefile.am create mode 100644 openair-cn/S1AP/Makefile.eNB create mode 100644 openair-cn/S1AP/Makefile.inc create mode 100644 openair-cn/S1AP/s1ap_common.c create mode 100644 openair-cn/S1AP/s1ap_common.h create mode 100644 openair-cn/S1AP/s1ap_eNB.c create mode 100644 openair-cn/S1AP/s1ap_eNB.h create mode 100644 openair-cn/S1AP/s1ap_eNB_decoder.c create mode 100644 openair-cn/S1AP/s1ap_eNB_decoder.h create mode 100644 openair-cn/S1AP/s1ap_eNB_defs.h create mode 100644 openair-cn/S1AP/s1ap_eNB_encoder.c create mode 100644 openair-cn/S1AP/s1ap_eNB_encoder.h create mode 100644 openair-cn/S1AP/s1ap_eNB_handlers.c create mode 100644 openair-cn/S1AP/s1ap_eNB_handlers.h create mode 100644 openair-cn/S1AP/s1ap_eNB_management_procedures.c create mode 100644 openair-cn/S1AP/s1ap_eNB_management_procedures.h create mode 100644 openair-cn/S1AP/s1ap_eNB_nas_procedures.c create mode 100644 openair-cn/S1AP/s1ap_eNB_nas_procedures.h create mode 100644 openair-cn/S1AP/s1ap_eNB_nnsf.c create mode 100644 openair-cn/S1AP/s1ap_eNB_nnsf.h create mode 100644 openair-cn/S1AP/s1ap_eNB_overload.c create mode 100644 openair-cn/S1AP/s1ap_eNB_overload.h create mode 100644 openair-cn/S1AP/s1ap_eNB_trace.c create mode 100644 openair-cn/S1AP/s1ap_eNB_trace.h create mode 100644 openair-cn/S1AP/s1ap_eNB_ue_context.c create mode 100644 openair-cn/S1AP/s1ap_eNB_ue_context.h create mode 100644 openair-cn/S1AP/s1ap_mme.c create mode 100644 openair-cn/S1AP/s1ap_mme.h create mode 100644 openair-cn/S1AP/s1ap_mme_decoder.c create mode 100644 openair-cn/S1AP/s1ap_mme_decoder.h create mode 100644 openair-cn/S1AP/s1ap_mme_encoder.c create mode 100644 openair-cn/S1AP/s1ap_mme_encoder.h create mode 100644 openair-cn/S1AP/s1ap_mme_handlers.c create mode 100644 openair-cn/S1AP/s1ap_mme_handlers.h create mode 100644 openair-cn/S1AP/s1ap_mme_itti_messaging.c create mode 100644 openair-cn/S1AP/s1ap_mme_itti_messaging.h create mode 100644 openair-cn/S1AP/s1ap_mme_nas_procedures.c create mode 100644 openair-cn/S1AP/s1ap_mme_nas_procedures.h create mode 100644 openair-cn/S1AP/s1ap_mme_retransmission.c create mode 100644 openair-cn/S1AP/s1ap_mme_retransmission.h create mode 100644 openair-cn/S1AP/s1ap_mme_ta.c create mode 100644 openair-cn/S1AP/s1ap_mme_ta.h create mode 100644 openair-cn/S6A/Makefile.am create mode 100644 openair-cn/S6A/freediameter/README.txt create mode 100644 openair-cn/S6A/freediameter/freediameter-1.1.5.patch create mode 100755 openair-cn/S6A/freediameter/install_freediameter.sh create mode 100755 openair-cn/S6A/freediameter/make_certs.sh create mode 100644 openair-cn/S6A/freediameter/s6a.conf create mode 100644 openair-cn/S6A/s6a_apn_conf.c create mode 100644 openair-cn/S6A/s6a_auth_info.c create mode 100644 openair-cn/S6A/s6a_defs.h create mode 100644 openair-cn/S6A/s6a_dict.c create mode 100644 openair-cn/S6A/s6a_error.c create mode 100644 openair-cn/S6A/s6a_messages.h create mode 100644 openair-cn/S6A/s6a_peer.c create mode 100644 openair-cn/S6A/s6a_subscription_data.c create mode 100644 openair-cn/S6A/s6a_task.c create mode 100644 openair-cn/S6A/s6a_up_loc.c create mode 100755 openair-cn/SCRIPTS/install_openvswitch1.9.0.bash create mode 100755 openair-cn/SCRIPTS/start_enb.bash create mode 100755 openair-cn/SCRIPTS/start_lte-epc-ovs.bash create mode 100755 openair-cn/SCRIPTS/start_lte-epc.bash create mode 100644 openair-cn/SCRIPTS/start_lte-sgw.bash create mode 100755 openair-cn/SCRIPTS/start_mme.bash create mode 100755 openair-cn/SCRIPTS/start_router.eur.bash create mode 100644 openair-cn/SCRIPTS/start_router.nord.eur.bash create mode 100755 openair-cn/SCRIPTS/start_spgw.bash create mode 100755 openair-cn/SCRIPTS/utils.bash create mode 100644 openair-cn/SCTP/Makefile.am create mode 100644 openair-cn/SCTP/Makefile.eNB create mode 100644 openair-cn/SCTP/sctp_common.c create mode 100644 openair-cn/SCTP/sctp_common.h create mode 100644 openair-cn/SCTP/sctp_eNB_defs.h create mode 100644 openair-cn/SCTP/sctp_itti_messaging.c create mode 100644 openair-cn/SCTP/sctp_itti_messaging.h create mode 100644 openair-cn/SCTP/sctp_primitives_client.c create mode 100644 openair-cn/SCTP/sctp_primitives_client.h create mode 100644 openair-cn/SCTP/sctp_primitives_server.c create mode 100644 openair-cn/SCTP/sctp_primitives_server.h create mode 100644 openair-cn/SECU/Makefile.am create mode 100644 openair-cn/SECU/Makefile.eNB create mode 100644 openair-cn/SECU/kdf.c create mode 100644 openair-cn/SECU/key_nas_deriver.c create mode 100644 openair-cn/SECU/key_nas_encryption.c create mode 100644 openair-cn/SECU/nas_stream_eea2.c create mode 100644 openair-cn/SECU/nas_stream_eia2.c create mode 100644 openair-cn/SECU/secu_defs.h create mode 100644 openair-cn/SGI/Makefile.am create mode 100755 openair-cn/SGI/sgi.h create mode 100755 openair-cn/SGI/sgi_egress.c create mode 100755 openair-cn/SGI/sgi_nf.c create mode 100755 openair-cn/SGI/sgi_pcap.c create mode 100644 openair-cn/SGI/sgi_socket.c create mode 100644 openair-cn/SGI/sgi_task.c create mode 100755 openair-cn/SGI/sgi_util.c create mode 100644 openair-cn/SGW-LITE/Makefile.am create mode 100644 openair-cn/SGW-LITE/s11_causes.c create mode 100644 openair-cn/SGW-LITE/s11_causes.h create mode 100755 openair-cn/SGW-LITE/sgw_lite.h create mode 100644 openair-cn/SGW-LITE/sgw_lite_context_manager.c create mode 100644 openair-cn/SGW-LITE/sgw_lite_context_manager.h create mode 100644 openair-cn/SGW-LITE/sgw_lite_defs.h create mode 100644 openair-cn/SGW-LITE/sgw_lite_handlers.c create mode 100644 openair-cn/SGW-LITE/sgw_lite_handlers.h create mode 100644 openair-cn/SGW-LITE/sgw_lite_ie_defs.h create mode 100644 openair-cn/SGW-LITE/sgw_lite_task.c create mode 100644 openair-cn/TEST/Makefile.am create mode 100644 openair-cn/TEST/oaisim_mme_client_test.c create mode 100644 openair-cn/TEST/oaisim_mme_itti_test.c create mode 100644 openair-cn/TEST/oaisim_mme_list_benchmark.c create mode 100644 openair-cn/TEST/oaisim_mme_s1ap_test.c create mode 100644 openair-cn/TEST/oaisim_mme_sctp_test.c create mode 100644 openair-cn/TEST/test_aes128_cmac_encrypt.c create mode 100644 openair-cn/TEST/test_aes128_ctr_decrypt.c create mode 100644 openair-cn/TEST/test_aes128_ctr_encrypt.c create mode 100644 openair-cn/TEST/test_kdf.c create mode 100644 openair-cn/TEST/test_s1ap.c create mode 100644 openair-cn/TEST/test_secu.c create mode 100644 openair-cn/TEST/test_secu_kenb.c create mode 100644 openair-cn/TEST/test_secu_knas.c create mode 100644 openair-cn/TEST/test_secu_knas_encrypt_eea2.c create mode 100644 openair-cn/TEST/test_secu_knas_encrypt_eia2.c create mode 100644 openair-cn/TEST/test_secu_knas_stream_int.c create mode 100644 openair-cn/TEST/test_util.c create mode 100644 openair-cn/TEST/test_util.h create mode 100644 openair-cn/UDP/Makefile.am create mode 100644 openair-cn/UDP/Makefile.eNB create mode 100644 openair-cn/UDP/udp_primitives_client.c create mode 100644 openair-cn/UDP/udp_primitives_client.h create mode 100644 openair-cn/UDP/udp_primitives_server.c create mode 100644 openair-cn/UDP/udp_primitives_server.h create mode 100755 openair-cn/UTILS/CONF/enb_default.conf create mode 100644 openair-cn/UTILS/CONF/enb_orcus.conf create mode 100644 openair-cn/UTILS/CONF/epc_nord.conf create mode 100644 openair-cn/UTILS/CONF/epc_orcus.conf create mode 100644 openair-cn/UTILS/CONF/mme_default.conf create mode 100644 openair-cn/UTILS/CONF/s6a.conf.in create mode 100755 openair-cn/UTILS/HASHTABLE/Makefile.am create mode 100755 openair-cn/UTILS/HASHTABLE/Makefile.eNB create mode 100755 openair-cn/UTILS/HASHTABLE/hashtable.c create mode 100755 openair-cn/UTILS/HASHTABLE/hashtable.h create mode 100755 openair-cn/UTILS/HASHTABLE/obj_hashtable.c create mode 100755 openair-cn/UTILS/HASHTABLE/obj_hashtable.h create mode 100644 openair-cn/UTILS/Makefile.am create mode 100644 openair-cn/UTILS/assertions.h create mode 100644 openair-cn/UTILS/backtrace.c create mode 100644 openair-cn/UTILS/backtrace.h create mode 100644 openair-cn/UTILS/conversions.c create mode 100644 openair-cn/UTILS/conversions.h create mode 100644 openair-cn/UTILS/enum_string.c create mode 100644 openair-cn/UTILS/enum_string.h create mode 100644 openair-cn/UTILS/log.c create mode 100644 openair-cn/UTILS/log.h create mode 100644 openair-cn/UTILS/mme_config.c create mode 100644 openair-cn/UTILS/mme_config.h create mode 100644 openair-cn/UTILS/mme_default_values.h create mode 100644 openair-cn/UTILS/mme_parser.y create mode 100644 openair-cn/UTILS/mme_scanner.l create mode 100644 openair-cn/UTILS/queue.h create mode 100644 openair-cn/UTILS/signals.c create mode 100644 openair-cn/UTILS/signals.h create mode 100644 openair-cn/UTILS/tree.h create mode 100644 openair-cn/aclocal.m4 create mode 100755 openair-cn/autogen.sh create mode 100644 openair-cn/compile create mode 100644 openair-cn/config.guess create mode 100644 openair-cn/config.h.in create mode 100644 openair-cn/config.sub create mode 100755 openair-cn/configure create mode 100644 openair-cn/configure.ac create mode 100644 openair-cn/cppcheck.sh create mode 100644 openair-cn/depcomp create mode 100644 openair-cn/install-sh create mode 100644 openair-cn/ltmain.sh create mode 100644 openair-cn/missing create mode 100644 openair-cn/valgrind.sh diff --git a/openair-cn/AUTHORS b/openair-cn/AUTHORS new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/openair-cn/AUTHORS @@ -0,0 +1 @@ + diff --git a/openair-cn/COMMON/as_message.h b/openair-cn/COMMON/as_message.h new file mode 100644 index 0000000000..de29af754f --- /dev/null +++ b/openair-cn/COMMON/as_message.h @@ -0,0 +1,526 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_message.h + +Version 0.1 + +Date 2012/10/18 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the messages supported by the Access Stratum sublayer + protocol (usually RRC and S1AP for E-UTRAN) and functions used + to encode and decode + +*****************************************************************************/ +#ifndef __AS_MESSAGE_H__ +#define __AS_MESSAGE_H__ + +#include "commonDef.h" +// #include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Access Stratum message types + * -------------------------------------------------------------------------- + */ +#define AS_REQUEST 0x0100 +#define AS_RESPONSE 0x0200 +#define AS_INDICATION 0x0400 +#define AS_CONFIRM 0x0800 + +/* + * -------------------------------------------------------------------------- + * Access Stratum message identifiers + * -------------------------------------------------------------------------- + */ + +/* Broadcast information */ +#define AS_BROADCAST_INFO 0x01 +#define AS_BROADCAST_INFO_IND (AS_BROADCAST_INFO | AS_INDICATION) + +/* Cell information relevant for cell selection processing */ +#define AS_CELL_INFO 0x02 +#define AS_CELL_INFO_REQ (AS_CELL_INFO | AS_REQUEST) +#define AS_CELL_INFO_CNF (AS_CELL_INFO | AS_CONFIRM) +#define AS_CELL_INFO_IND (AS_CELL_INFO | AS_INDICATION) + +/* Paging information */ +#define AS_PAGING 0x03 +#define AS_PAGING_REQ (AS_PAGING | AS_REQUEST) +#define AS_PAGING_IND (AS_PAGING | AS_INDICATION) + +/* NAS signalling connection establishment */ +#define AS_NAS_ESTABLISH 0x04 +#define AS_NAS_ESTABLISH_REQ (AS_NAS_ESTABLISH | AS_REQUEST) +#define AS_NAS_ESTABLISH_IND (AS_NAS_ESTABLISH | AS_INDICATION) +#define AS_NAS_ESTABLISH_RSP (AS_NAS_ESTABLISH | AS_RESPONSE) +#define AS_NAS_ESTABLISH_CNF (AS_NAS_ESTABLISH | AS_CONFIRM) + +/* NAS signalling connection release */ +#define AS_NAS_RELEASE 0x05 +#define AS_NAS_RELEASE_REQ (AS_NAS_RELEASE | AS_REQUEST) +#define AS_NAS_RELEASE_IND (AS_NAS_RELEASE | AS_INDICATION) + +/* Uplink information transfer */ +#define AS_UL_INFO_TRANSFER 0x06 +#define AS_UL_INFO_TRANSFER_REQ (AS_UL_INFO_TRANSFER | AS_REQUEST) +#define AS_UL_INFO_TRANSFER_CNF (AS_UL_INFO_TRANSFER | AS_CONFIRM) +#define AS_UL_INFO_TRANSFER_IND (AS_UL_INFO_TRANSFER | AS_INDICATION) + +/* Downlink information transfer */ +#define AS_DL_INFO_TRANSFER 0x07 +#define AS_DL_INFO_TRANSFER_REQ (AS_DL_INFO_TRANSFER | AS_REQUEST) +#define AS_DL_INFO_TRANSFER_CNF (AS_DL_INFO_TRANSFER | AS_CONFIRM) +#define AS_DL_INFO_TRANSFER_IND (AS_DL_INFO_TRANSFER | AS_INDICATION) + +/* Radio Access Bearer establishment */ +#define AS_RAB_ESTABLISH 0x08 +#define AS_RAB_ESTABLISH_REQ (AS_RAB_ESTABLISH | AS_REQUEST) +#define AS_RAB_ESTABLISH_IND (AS_RAB_ESTABLISH | AS_INDICATION) +#define AS_RAB_ESTABLISH_RSP (AS_RAB_ESTABLISH | AS_RESPONSE) +#define AS_RAB_ESTABLISH_CNF (AS_RAB_ESTABLISH | AS_CONFIRM) + +/* Radio Access Bearer release */ +#define AS_RAB_RELEASE 0x09 +#define AS_RAB_RELEASE_REQ (AS_RAB_RELEASE | AS_REQUEST) +#define AS_RAB_RELEASE_IND (AS_RAB_RELEASE | AS_INDICATION) + +/* NAS Cause */ +#define EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED (8) +#define EPS_SERVICES_NOT_ALLOWED (7) +#define PLMN_NOT_ALLOWED (11) +#define TRACKING_AREA_NOT_ALLOWED (12) +#define ROAMING_NOT_ALLOWED_IN_THIS_TRACKING_AREA (13) +#define EPS_SERVICES_NOT_ALLOWED_IN_THIS_PLMN (14) +#define NO_SUITABLE_CELLS_IN_TRACKING_AREA (15) +#define NETWORK_FAILURE (17) +#define ESM_FAILURE (19) + +/* + * -------------------------------------------------------------------------- + * Access Stratum message global parameters + * -------------------------------------------------------------------------- + */ + +/* Error code */ +enum { + AS_SUCCESS = 1, /* Success code, transaction is going on */ + AS_TERMINATED_NAS, /* Transaction terminated by NAS */ + AS_TERMINATED_AS, /* Transaction terminated by AS */ + AS_FAILURE /* Failure code */ +}; + +/* Core network domain */ +enum { + AS_PS = 1, /* Packet-Switched */ + AS_CS /* Circuit-Switched */ +}; + +/* SAE Temporary Mobile Subscriber Identity */ +typedef struct { + UInt8_t MMEcode; /* MME code that allocated the GUTI */ + UInt32_t m_tmsi; /* M-Temporary Mobile Subscriber Identity */ +} as_stmsi_t; + +/* Dedicated NAS information */ +typedef struct { + UInt32_t length; /* Length of the NAS information data */ + Byte_t* data; /* Dedicated NAS information data container */ +} as_nas_info_t; + +/* Radio Access Bearer identity */ +typedef UInt8_t as_rab_id_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Broadcast information + * -------------------------------------------------------------------------- + */ + +/* + * AS->NAS - Broadcast information indication + * AS may asynchronously report to NAS available PLMNs within specific + * location area + */ +typedef struct { +#define PLMN_LIST_MAX_SIZE 6 + PLMN_LIST_T(PLMN_LIST_MAX_SIZE) plmnIDs; /* List of PLMN identifiers */ + ci_t cellID; /* Identity of the cell serving the listed PLMNs */ + tac_t tac; /* Code of the tracking area the cell belongs to */ +} broadcast_info_ind_t; + +/* + * -------------------------------------------------------------------------- + * Cell information relevant for cell selection processing + * -------------------------------------------------------------------------- + */ + +/* Radio access technologies supported by the network */ +#define AS_GSM (1 << NET_ACCESS_GSM) +#define AS_COMPACT (1 << NET_ACCESS_COMPACT) +#define AS_UTRAN (1 << NET_ACCESS_UTRAN) +#define AS_EGPRS (1 << NET_ACCESS_EGPRS) +#define AS_HSDPA (1 << NET_ACCESS_HSDPA) +#define AS_HSUPA (1 << NET_ACCESS_HSUPA) +#define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) +#define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) + +/* + * NAS->AS - Cell Information request + * NAS request AS to search for a suitable cell belonging to the selected + * PLMN to camp on. + */ +typedef struct { + plmn_t plmnID; /* Selected PLMN identity */ + Byte_t rat; /* Bitmap - set of radio access technologies */ +} cell_info_req_t; + +/* + * AS->NAS - Cell Information confirm + * AS search for a suitable cell and respond to NAS. If found, the cell + * is selected to camp on. + */ +typedef struct { + UInt8_t errCode; /* Error code */ + ci_t cellID; /* Identity of the cell serving the selected PLMN */ + tac_t tac; /* Code of the tracking area the cell belongs to */ + AcT_t rat; /* Radio access technology supported by the cell */ + UInt8_t rsrq; /* Reference signal received quality */ + UInt8_t rsrp; /* Reference signal received power */ +} cell_info_cnf_t; + +/* + * AS->NAS - Cell Information indication + * AS may change cell selection if a more suitable cell is found. + */ +typedef struct { + ci_t cellID; /* Identity of the new serving cell */ + tac_t tac; /* Code of the tracking area the cell belongs to */ +} cell_info_ind_t; + +/* + * -------------------------------------------------------------------------- + * Paging information + * -------------------------------------------------------------------------- + */ + +/* Paging cause */ +enum { + AS_CONNECTION_ESTABLISH, /* Establish NAS signalling connection */ + AS_EPS_ATTACH, /* Perform local detach and initiate EPS + * attach procedure */ + AS_CS_FALLBACK /* Inititate CS fallback procedure */ +}; + +/* + * NAS->AS - Paging Information request + * NAS requests the AS that NAS signalling messages or user data is pending + * to be sent. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t CN_domain; /* Core network domain */ +} paging_req_t; + +/* + * AS->NAS - Paging Information indication + * AS reports to the NAS that appropriate procedure has to be initiated. + */ +typedef struct { + UInt8_t cause; /* Paging cause */ +} paging_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection establishment + * -------------------------------------------------------------------------- + */ + +/* Cause of RRC connection establishment */ +#define AS_CAUSE_EMERGENCY (NET_ESTABLISH_CAUSE_EMERGENCY) +#define AS_CAUSE_HIGH_PRIO (NET_ESTABLISH_CAUSE_HIGH_PRIO) +#define AS_CAUSE_MT_ACCESS (NET_ESTABLISH_CAUSE_MT_ACCESS) +#define AS_CAUSE_MO_SIGNAL (NET_ESTABLISH_CAUSE_MO_SIGNAL) +#define AS_CAUSE_MO_DATA (NET_ESTABLISH_CAUSE_MO_DATA) +#define AS_CAUSE_V1020 (NET_ESTABLISH_CAUSE_V1020) + +/* Type of the call associated to the RRC connection establishment */ +#define AS_TYPE_ORIGINATING_SIGNAL (NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL) +#define AS_TYPE_EMERGENCY_CALLS (NET_ESTABLISH_TYPE_EMERGENCY_CALLS) +#define AS_TYPE_ORIGINATING_CALLS (NET_ESTABLISH_TYPE_ORIGINATING_CALLS) +#define AS_TYPE_TERMINATING_CALLS (NET_ESTABLISH_TYPE_TERMINATING_CALLS) +#define AS_TYPE_MO_CS_FALLBACK (NET_ESTABLISH_TYPE_MO_CS_FALLBACK) + + +/* + * NAS->AS - NAS signalling connection establishment request + * NAS requests the AS to perform the RRC connection establishment procedure + * to transfer initial NAS message to the network while UE is in IDLE mode. + */ +typedef struct { + UInt8_t cause; /* RRC connection establishment cause */ + UInt8_t type; /* RRC associated call type */ + as_stmsi_t s_tmsi; /* UE identity */ + plmn_t plmnID; /* Selected PLMN identity */ + as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */ +} nas_establish_req_t; + +/* + * AS->NAS - NAS signalling connection establishment indication + * AS transfers the initial NAS message to the NAS. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + tac_t tac; /* Code of the tracking area the initiating + * UE belongs to */ + as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */ +} nas_establish_ind_t; + +/* + * NAS->AS - NAS signalling connection establishment response + * NAS responds to the AS that initial answer message has to be provided to + * the UE. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t errCode; /* Transaction status */ + as_nas_info_t nasMsg; /* NAS message to transfer */ +} nas_establish_rsp_t; + +/* + * AS->NAS - NAS signalling connection establishment confirm + * AS transfers the initial answer message to the NAS. + */ +typedef struct { + UInt8_t errCode; /* Transaction status */ + as_nas_info_t nasMsg; /* NAS message to transfer */ +} nas_establish_cnf_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection release + * -------------------------------------------------------------------------- + */ + +/* Release cause */ +enum { + AS_AUTHENTICATION_FAILURE = 1, /* Authentication procedure failed */ + AS_DETACH /* Detach requested */ +}; + +/* + * NAS->AS - NAS signalling connection release request + * NAS requests the termination of the connection with the UE. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t cause; /* Release cause */ +} nas_release_req_t; + +/* + * AS->NAS - NAS signalling connection release indication + * AS reports that connection has been terminated by the network. + */ +typedef struct { + UInt8_t cause; /* Release cause */ +} nas_release_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS information transfer + * -------------------------------------------------------------------------- + */ + +/* + * NAS->AS - Uplink data transfer request + * NAS requests the AS to transfer uplink information to the NAS that + * operates at the network side. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + as_nas_info_t nasMsg; /* Uplink NAS message */ +} ul_info_transfer_req_t; + +/* + * AS->NAS - Uplink data transfer confirm + * AS immediately notifies the NAS whether uplink information has been + * successfully sent to the network or not. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + UInt8_t errCode; /* Transaction status */ +} ul_info_transfer_cnf_t; + +/* + * AS->NAS - Uplink data transfer indication + * AS delivers the uplink information message to the NAS that operates + * at the network side. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_nas_info_t nasMsg; /* Uplink NAS message */ +} ul_info_transfer_ind_t; + +/* + * NAS->AS - Downlink data transfer request + * NAS requests the AS to transfer downlink information to the NAS that + * operates at the UE side. + */ +typedef ul_info_transfer_req_t dl_info_transfer_req_t; + +/* + * AS->NAS - Downlink data transfer confirm + * AS immediately notifies the NAS whether downlink information has been + * successfully sent to the network or not. + */ +typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t; + +/* + * AS->NAS - Downlink data transfer indication + * AS delivers the downlink information message to the NAS that operates + * at the UE side. + */ +typedef ul_info_transfer_ind_t dl_info_transfer_ind_t; + +/* + * -------------------------------------------------------------------------- + * Radio Access Bearer establishment + * -------------------------------------------------------------------------- + */ + +/* TODO: Quality of Service parameters */ +typedef struct {} as_qos_t; + +/* + * NAS->AS - Radio access bearer establishment request + * NAS requests the AS to allocate transmission resources to radio access + * bearer initialized at the network side. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ + as_qos_t QoS; /* Requested Quality of Service */ +} rab_establish_req_t; + +/* + * AS->NAS - Radio access bearer establishment indication + * AS notifies the NAS that specific radio access bearer has to be setup. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_establish_ind_t; + +/* + * NAS->AS - Radio access bearer establishment response + * NAS responds to AS whether the specified radio access bearer has been + * successfully setup or not. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ + UInt8_t errCode; /* Transaction status */ +} rab_establish_rsp_t; + +/* + * AS->NAS - Radio access bearer establishment confirm + * AS notifies NAS whether the specified radio access bearer has been + * successfully setup at the UE side or not. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ + UInt8_t errCode; /* Transaction status */ +} rab_establish_cnf_t; + +/* + * -------------------------------------------------------------------------- + * Radio Access Bearer release + * -------------------------------------------------------------------------- + */ + +/* + * NAS->AS - Radio access bearer release request + * NAS requests the AS to release transmission resources previously allocated + * to specific radio access bearer at the network side. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_release_req_t; + +/* + * AS->NAS - Radio access bearer release indication + * AS notifies NAS that specific radio access bearer has been released. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_release_ind_t; + +/* + * -------------------------------------------------------------------------- + * Structure of the AS messages handled by the network sublayer + * -------------------------------------------------------------------------- + */ +typedef struct { + UInt16_t msgID; + union { + broadcast_info_ind_t broadcast_info_ind; + cell_info_req_t cell_info_req; + cell_info_cnf_t cell_info_cnf; + cell_info_ind_t cell_info_ind; + paging_req_t paging_req; + paging_ind_t paging_ind; + nas_establish_req_t nas_establish_req; + nas_establish_ind_t nas_establish_ind; + nas_establish_rsp_t nas_establish_rsp; + nas_establish_cnf_t nas_establish_cnf; + nas_release_req_t nas_release_req; + nas_release_ind_t nas_release_ind; + ul_info_transfer_req_t ul_info_transfer_req; + ul_info_transfer_cnf_t ul_info_transfer_cnf; + ul_info_transfer_ind_t ul_info_transfer_ind; + dl_info_transfer_req_t dl_info_transfer_req; + dl_info_transfer_cnf_t dl_info_transfer_cnf; + dl_info_transfer_ind_t dl_info_transfer_ind; + rab_establish_req_t rab_establish_req; + rab_establish_ind_t rab_establish_ind; + rab_establish_rsp_t rab_establish_rsp; + rab_establish_cnf_t rab_establish_cnf; + rab_release_req_t rab_release_req; + rab_release_ind_t rab_release_ind; + } __attribute__((__packed__)) msg; +} as_message_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int as_message_decode(const char* buffer, as_message_t* msg, int length); + +int as_message_encode(char* buffer, as_message_t* msg, int length); + +/* Implemented in the network_api.c body file */ +int as_message_send(as_message_t* as_msg); + +#endif /* __AS_MESSAGE_H__*/ diff --git a/openair-cn/COMMON/commonDef.h b/openair-cn/COMMON/commonDef.h new file mode 100644 index 0000000000..84dca6a654 --- /dev/null +++ b/openair-cn/COMMON/commonDef.h @@ -0,0 +1,249 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source commonDef.h + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem include + +Author Frederic Maurel + +Description Contains global common definitions + +*****************************************************************************/ +#ifndef __COMMONDEF_H__ +#define __COMMONDEF_H__ + +#include <stdint.h> +#include <stddef.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#define RETURNok (0) +#define RETURNerror (-1) + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif + +/* + * Name of the environment variable which defines the default directory + * where the NAS application is executed and where are located files + * where non-volatile data are stored + */ +#define DEFAULT_NAS_PATH "PWD" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* +----------------------------------------------------------------------------- + Standard data type definitions +----------------------------------------------------------------------------- +*/ +typedef int8_t SByte_t; /* 8 bit signed integer */ +typedef int8_t Int8_t; /* 8 bit signed integer */ +typedef int16_t Int16_t; /* 16 bit signed integer */ +typedef int32_t Int32_t; /* 32 bit signed integer */ +typedef int64_t Int64_t; /* 64 bit signed integer */ + + +typedef uint8_t Byte_t; /* 8 bit unsigned integer */ +typedef uint8_t UInt8_t; /* 8 bit unsigned integer */ +typedef uint16_t UInt16_t; /* 16 bit unsigned integer */ +typedef uint32_t UInt32_t; /* 32 bit unsigned integer */ +typedef uint64_t UInt64_t; /* 64 bit unsigned integer */ + +/* +----------------------------------------------------------------------------- + Common NAS data type definitions +----------------------------------------------------------------------------- +*/ + +typedef UInt8_t Stat_t; /* Registration status */ +typedef UInt16_t lac_t; /* Location Area Code */ +typedef UInt8_t rac_t; /* Routing Area Code */ +typedef UInt16_t tac_t; /* Tracking Area Code */ +typedef UInt32_t ci_t; /* Cell Identifier */ +typedef UInt8_t AcT_t; /* Access Technology */ + +/* + * International Mobile Subscriber Identity + */ +typedef struct { + Byte_t length; + union { + struct { + Byte_t digit15:4; + Byte_t digit14:4; + Byte_t digit13:4; + Byte_t digit12:4; + Byte_t digit11:4; + Byte_t digit10:4; + Byte_t digit9:4; + Byte_t digit8:4; + Byte_t digit7:4; + Byte_t digit6:4; + Byte_t digit5:4; + Byte_t digit4:4; + Byte_t digit3:4; + Byte_t digit2:4; + Byte_t digit1:4; +#define EVEN_PARITY 0 +#define ODD_PARITY 1 + Byte_t parity:4; + } num; +#define IMSI_SIZE 8 + Byte_t value[IMSI_SIZE]; + } u; +} imsi_t; + +/* + * Mobile subscriber dialing number + */ +typedef struct { + Byte_t ext:1; + /* Type Of Number */ +#define MSISDN_TON_UNKNOWKN 0b000 +#define MSISDN_TON_INTERNATIONAL 0b001 +#define MSISDN_TON_NATIONAL 0b010 +#define MSISDN_TON_NETWORK 0b011 +#define MSISDN_TON_SUBCRIBER 0b100 +#define MSISDN_TON_ABBREVIATED 0b110 +#define MSISDN_TON_RESERVED 0b111 + Byte_t ton:3; + /* Numbering Plan Identification */ +#define MSISDN_NPI_UNKNOWN 0b0000 +#define MSISDN_NPI_ISDN_TELEPHONY 0b0001 +#define MSISDN_NPI_GENERIC 0b0010 +#define MSISDN_NPI_DATA 0b0011 +#define MSISDN_NPI_TELEX 0b0100 +#define MSISDN_NPI_MARITIME_MOBILE 0b0101 +#define MSISDN_NPI_LAND_MOBILE 0b0110 +#define MSISDN_NPI_ISDN_MOBILE 0b0111 +#define MSISDN_NPI_PRIVATE 0b1110 +#define MSISDN_NPI_RESERVED 0b1111 + Byte_t npi:4; + /* Dialing Number */ + struct { + Byte_t lsb:4; + Byte_t msb:4; +#define MSISDN_DIGIT_SIZE 10 + } digit[MSISDN_DIGIT_SIZE]; +} msisdn_t; + +/* + * International Mobile Equipment Identity + */ +typedef imsi_t imei_t; + +/* + * Public Land Mobile Network identifier + * PLMN = BCD encoding (Mobile Country Code + Mobile Network Code) + */ +typedef struct { + Byte_t MCCdigit2:4; + Byte_t MCCdigit1:4; + Byte_t MNCdigit3:4; + Byte_t MCCdigit3:4; + Byte_t MNCdigit2:4; + Byte_t MNCdigit1:4; +} plmn_t; + +/* + * Location Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + lac_t lac; /* Location Area Code */ +} lai_t; + +/* + * GPRS Routing Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + lac_t lac; /* Location Area Code */ + rac_t rac; /* Routing Area Code */ +} RAI_t; + +/* + * EPS Tracking Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + tac_t tac; /* Tracking Area Code */ +} tai_t; + +/* + * EPS Globally Unique MME Identity + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + UInt16_t MMEgid; /* MME group identifier */ + UInt8_t MMEcode; /* MME code */ +} gummei_t; + +/* + * EPS Globally Unique Temporary UE Identity + */ +typedef struct { + gummei_t gummei; /* Globally Unique MME Identity */ + UInt32_t m_tmsi; /* M-Temporary Mobile Subscriber Identity */ +} GUTI_t; + +/* Checks PLMN validity */ +#define PLMN_IS_VALID(plmn) (((plmn).MCCdigit1 & \ + (plmn).MCCdigit2 & \ + (plmn).MCCdigit3) != 0x0F) + +/* Checks TAC validity */ +#define TAC_IS_VALID(tac) (((tac) != 0x0000) && ((tac) != 0xFFF0)) + +/* Checks TAI validity */ +#define TAI_IS_VALID(tai) (PLMN_IS_VALID((tai).plmn) && \ + TAC_IS_VALID((tai).tac)) +/* + * A list of PLMNs + */ +#define PLMN_LIST_T(SIZE) struct {Byte_t n_plmns; plmn_t plmn[SIZE];} + +/* + * A list of TACs + */ +#define TAC_LIST_T(SIZE) struct {Byte_t n_tacs; TAC_t tac[SIZE];} + +/* + * A list of TAIs + */ +#define TAI_LIST_T(SIZE) struct {Byte_t n_tais; tai_t tai[SIZE];} + +/* + * User notification callback, executed whenever a change of data with + * respect of network information (e.g. network registration and/or + * location change, new PLMN becomes available) is notified by the + * EPS Mobility Management sublayer + */ +typedef int (*indication_callback_t) (Stat_t, tac_t, ci_t, AcT_t, const char*, size_t); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __COMMONDEF_H__*/ diff --git a/openair-cn/COMMON/common_types.h b/openair-cn/COMMON/common_types.h new file mode 100644 index 0000000000..97175afe01 --- /dev/null +++ b/openair-cn/COMMON/common_types.h @@ -0,0 +1,250 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "commonDef.h" + +#include "queue.h" + +#ifndef COMMON_TYPES_H_ +#define COMMON_TYPES_H_ + +#define MSISDN_LENGTH (15) +#define IMSI_DIGITS_MAX (15) +#define APN_MAX_LENGTH (100) +#define PRIORITY_LEVEL_MAX (15) +#define PRIORITY_LEVEL_MIN (1) +#define BEARERS_PER_UE (11) +#define MAX_APN_PER_UE (5) + +typedef enum { + RAT_WLAN = 0, + RAT_VIRTUAL = 1, + RAT_UTRAN = 1000, + RAT_GERAN = 1001, + RAT_GAN = 1002, + RAT_HSPA_EVOLUTION = 1003, + RAT_EUTRAN = 1004, + RAT_CDMA2000_1X = 2000, + RAT_HRPD = 2001, + RAT_UMB = 2002, + RAT_EHRPD = 2003, +} rat_type_t; + +#define NUMBER_OF_RAT_TYPE 11 + +typedef enum { + SS_SERVICE_GRANTED = 0, + SS_OPERATOR_DETERMINED_BARRING = 1, + SS_MAX, +} subscriber_status_t; + +typedef enum { + NAM_PACKET_AND_CIRCUIT = 0, + NAM_RESERVED = 1, + NAM_ONLY_PACKET = 2, + NAM_MAX, +} network_access_mode_t; + +typedef uint32_t bitrate_t; + +typedef uint8_t ebi_t; +typedef char* APN_t; +typedef uint8_t APNRestriction_t; +typedef uint8_t DelayValue_t; +typedef uint8_t priority_level_t; +typedef uint32_t Teid_t; +typedef uint32_t SequenceNumber_t; +typedef uint32_t access_restriction_t; +typedef uint32_t context_identifier_t; +typedef uint32_t rau_tau_timer_t; + +typedef uint32_t ard_t; +#define ARD_UTRAN_NOT_ALLOWED (1U) +#define ARD_GERAN_NOT_ALLOWED (1U << 1) +#define ARD_GAN_NOT_ALLOWED (1U << 2) +#define ARD_I_HSDPA_EVO_NOT_ALLOWED (1U << 3) +#define ARD_E_UTRAN_NOT_ALLOWED (1U << 4) +#define ARD_HO_TO_NON_3GPP_NOT_ALLOWED (1U << 5) +#define ARD_MAX (1U << 6) + +typedef struct { + plmn_t plmn; + unsigned cell_identity:28; +} cgi_t; + +typedef union { + struct { + uint8_t imei[13]; + uint8_t sotfware_version[2]; + } id; + uint8_t imeisv[15]; +} me_identity_t; + +typedef struct { + bitrate_t br_ul; + bitrate_t br_dl; +} ambr_t; + +typedef enum { + IPv4 = 0, + IPv6 = 1, + IPv4_AND_v6 = 2, + IPv4_OR_v6 = 3, + IP_MAX, +} pdn_type_t; + +typedef struct { + pdn_type_t pdn_type; + struct { + uint8_t ipv4_address[4]; + uint8_t ipv6_address[16]; + } address; +} ip_address_t; + +typedef enum { + QCI_1 = 1, + QCI_2 = 2, + QCI_3 = 3, + QCI_4 = 4, + QCI_5 = 5, + QCI_6 = 6, + QCI_7 = 7, + QCI_8 = 8, + QCI_9 = 9, + /* Values from 128 to 254 are operator specific. + * Other are reserved. + */ + QCI_MAX, +} qci_t; + +typedef enum { + PRE_EMPTION_CAPABILITY_ENABLED = 0, + PRE_EMPTION_CAPABILITY_DISABLED = 1, + PRE_EMPTION_CAPABILITY_MAX, +} pre_emp_capability_t; + +typedef enum { + PRE_EMPTION_VULNERABILITY_ENABLED = 0, + PRE_EMPTION_VULNERABILITY_DISABLED = 1, + PRE_EMPTION_VULNERABILITY_MAX, +} pre_emp_vulnerability_t; + +typedef struct { + priority_level_t priority_level; + pre_emp_vulnerability_t pre_emp_vulnerability; + pre_emp_capability_t pre_emp_capability; +} allocation_retention_priority_t; + +typedef struct eps_subscribed_qos_profile_s { + qci_t qci; + allocation_retention_priority_t allocation_retention_priority; +} eps_subscribed_qos_profile_t; + +typedef struct apn_configuration_s { + context_identifier_t context_identifier; + + /* Each APN configuration can have 0, 1, or 2 ip address: + * - 0 means subscribed is dynamically allocated by P-GW depending on the + * pdn_type + * - 1 Only one type of IP address is returned by HSS + * - 2 IPv4 and IPv6 address are returned by HSS and are statically + * allocated + */ + uint8_t nb_ip_address; + ip_address_t ip_address[2]; + + pdn_type_t pdn_type; + char service_selection[APN_MAX_LENGTH]; + int service_selection_length; + eps_subscribed_qos_profile_t subscribed_qos; + ambr_t ambr; +} apn_configuration_t; + +typedef enum { + ALL_APN_CONFIGURATIONS_INCLUDED = 0, + MODIFIED_ADDED_APN_CONFIGURATIONS_INCLUDED = 1, + ALL_APN_MAX, +} all_apn_conf_ind_t; + +typedef struct { + context_identifier_t context_identifier; + all_apn_conf_ind_t all_apn_conf_ind; + /* Number of APNs provided */ + uint8_t nb_apns; + /* List of APNs configuration 1 to n elements */ + struct apn_configuration_s apn_configuration[MAX_APN_PER_UE]; +} apn_config_profile_t; + +typedef struct { + subscriber_status_t subscriber_status; + char msisdn[MSISDN_LENGTH + 1]; + uint8_t msisdn_length; + network_access_mode_t access_mode; + access_restriction_t access_restriction; + ambr_t subscribed_ambr; + apn_config_profile_t apn_config_profile; + rau_tau_timer_t rau_tau_timer; +} subscription_data_t; + +typedef struct { + uint8_t nb_of_vectors; + STAILQ_HEAD(e_utran_vector_list, eutran_vector_s) e_utran_vectors; +} authentication_info_t; + +typedef enum { + DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE = 4181, + DIAMETER_ERROR_USER_UNKNOWN = 5001, + DIAMETER_ERROR_ROAMING_NOT_ALLOWED = 5004, + DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION = 5420, + DIAMETER_ERROR_RAT_NOT_ALLOWED = 5421, + DIAMETER_ERROR_EQUIPMENT_UNKNOWN = 5422, + DIAMETER_ERROR_UNKOWN_SERVING_NODE = 5423, +} s6a_experimental_result_t; + +typedef enum { + DIAMETER_SUCCESS = 2001, +} s6a_base_result_t; + +typedef struct { +#define S6A_RESULT_BASE 0x0 +#define S6A_RESULT_EXPERIMENTAL 0x1 + unsigned present:1; + + union { + /* Experimental result as defined in 3GPP TS 29.272 */ + s6a_experimental_result_t experimental; + /* Diameter basics results as defined in RFC 3588 */ + s6a_base_result_t base; + } choice; +} s6a_result_t; + +#endif /* COMMON_TYPES_H_ */ diff --git a/openair-cn/COMMON/gtpv1_u_messages_def.h b/openair-cn/COMMON/gtpv1_u_messages_def.h new file mode 100644 index 0000000000..1774923056 --- /dev/null +++ b/openair-cn/COMMON/gtpv1_u_messages_def.h @@ -0,0 +1,8 @@ +MESSAGE_DEF(GTPV1U_CREATE_TUNNEL_REQ, MESSAGE_PRIORITY_MED, Gtpv1uCreateTunnelReq, gtpv1uCreateTunnelReq) +MESSAGE_DEF(GTPV1U_CREATE_TUNNEL_RESP, MESSAGE_PRIORITY_MED, Gtpv1uCreateTunnelResp, gtpv1uCreateTunnelResp) +MESSAGE_DEF(GTPV1U_UPDATE_TUNNEL_REQ, MESSAGE_PRIORITY_MED, Gtpv1uUpdateTunnelReq, gtpv1uUpdateTunnelReq) +MESSAGE_DEF(GTPV1U_UPDATE_TUNNEL_RESP, MESSAGE_PRIORITY_MED, Gtpv1uUpdateTunnelResp, gtpv1uUpdateTunnelResp) +MESSAGE_DEF(GTPV1U_DELETE_TUNNEL_REQ, MESSAGE_PRIORITY_MED, Gtpv1uDeleteTunnelReq, gtpv1uDeleteTunnelReq) +MESSAGE_DEF(GTPV1U_DELETE_TUNNEL_RESP, MESSAGE_PRIORITY_MED, Gtpv1uDeleteTunnelResp, gtpv1uDeleteTunnelResp) +MESSAGE_DEF(GTPV1U_TUNNEL_DATA_IND, MESSAGE_PRIORITY_MED, Gtpv1uTunnelDataInd, gtpv1uTunnelDataInd) +MESSAGE_DEF(GTPV1U_TUNNEL_DATA_REQ, MESSAGE_PRIORITY_MED, Gtpv1uTunnelDataReq, gtpv1uTunnelDataReq) diff --git a/openair-cn/COMMON/gtpv1_u_messages_types.h b/openair-cn/COMMON/gtpv1_u_messages_types.h new file mode 100644 index 0000000000..97b36efa78 --- /dev/null +++ b/openair-cn/COMMON/gtpv1_u_messages_types.h @@ -0,0 +1,58 @@ +#ifndef GTPV1_U_MESSAGES_TYPES_H_ +#define GTPV1_U_MESSAGES_TYPES_H_ + +#include "../SGW-LITE/sgw_lite_ie_defs.h" + +typedef struct { + Teid_t context_teid; ///< Tunnel Endpoint Identifier + ebi_t eps_bearer_id; +} Gtpv1uCreateTunnelReq; + +typedef struct { + uint8_t status; ///< Status of S1U endpoint creation (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< local SGW S11 Tunnel Endpoint Identifier + Teid_t S1u_teid; ///< Tunnel Endpoint Identifier + ebi_t eps_bearer_id; +} Gtpv1uCreateTunnelResp; + +typedef struct { + Teid_t context_teid; ///< S11 Tunnel Endpoint Identifier + Teid_t sgw_S1u_teid; ///< SGW S1U local Tunnel Endpoint Identifier + Teid_t enb_S1u_teid; ///< eNB S1U Tunnel Endpoint Identifier + ip_address_t enb_ip_address_for_S1u; + ebi_t eps_bearer_id; +} Gtpv1uUpdateTunnelReq; + +typedef struct { + uint8_t status; ///< Status (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< S11 Tunnel Endpoint Identifier + Teid_t sgw_S1u_teid; ///< SGW S1U local Tunnel Endpoint Identifier + Teid_t enb_S1u_teid; ///< eNB S1U Tunnel Endpoint Identifier + ebi_t eps_bearer_id; +} Gtpv1uUpdateTunnelResp; + +typedef struct { + Teid_t context_teid; ///< local SGW S11 Tunnel Endpoint Identifier + Teid_t S1u_teid; ///< local S1U Tunnel Endpoint Identifier to be deleted +} Gtpv1uDeleteTunnelReq; + +typedef struct { + uint8_t status; ///< Status of S1U endpoint deleteion (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< local SGW S11 Tunnel Endpoint Identifier + Teid_t S1u_teid; ///< local S1U Tunnel Endpoint Identifier to be deleted +} Gtpv1uDeleteTunnelResp; + +typedef struct { + uint8_t *buffer; + uint32_t length; + Teid_t local_S1u_teid; ///< Tunnel Endpoint Identifier +} Gtpv1uTunnelDataInd; + +typedef struct { + uint8_t *buffer; + uint32_t length; + Teid_t local_S1u_teid; ///< Tunnel Endpoint Identifier + Teid_t S1u_enb_teid; ///< Tunnel Endpoint Identifier +} Gtpv1uTunnelDataReq; + +#endif /* GTPV1_U_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/ip_forward_messages_def.h b/openair-cn/COMMON/ip_forward_messages_def.h new file mode 100755 index 0000000000..68b790b34a --- /dev/null +++ b/openair-cn/COMMON/ip_forward_messages_def.h @@ -0,0 +1,6 @@ +MESSAGE_DEF(SGI_CREATE_ENDPOINT_REQUEST, MESSAGE_PRIORITY_MED, SGICreateEndpointReq, sgiCreateEndpointReq) +MESSAGE_DEF(SGI_CREATE_ENDPOINT_RESPONSE, MESSAGE_PRIORITY_MED, SGICreateEndpointResp, sgiCreateEndpointResp) +MESSAGE_DEF(SGI_UPDATE_ENDPOINT_REQUEST, MESSAGE_PRIORITY_MED, SGIUpdateEndpointReq, sgiUpdateEndpointReq) +MESSAGE_DEF(SGI_UPDATE_ENDPOINT_RESPONSE, MESSAGE_PRIORITY_MED, SGIUpdateEndpointResp, sgiUpdateEndpointResp) +MESSAGE_DEF(SGI_DELETE_ENDPOINT_REQUEST, MESSAGE_PRIORITY_MED, SGIDeleteEndpointReq, sgiDeleteEndpointReq) +MESSAGE_DEF(SGI_DELETE_ENDPOINT_RESPONSE, MESSAGE_PRIORITY_MED, SGIDeleteEndpointResp, sgiDeleteEndpointResp) diff --git a/openair-cn/COMMON/ip_forward_messages_types.h b/openair-cn/COMMON/ip_forward_messages_types.h new file mode 100755 index 0000000000..2970f8283e --- /dev/null +++ b/openair-cn/COMMON/ip_forward_messages_types.h @@ -0,0 +1,67 @@ +#ifndef SGI_FORWARD_MESSAGES_TYPES_H_ +#define SGI_FORWARD_MESSAGES_TYPES_H_ + +typedef enum SGIStatus_e { + SGI_STATUS_OK = 0, + SGI_STATUS_ERROR_CONTEXT_ALREADY_EXIST = 50, + SGI_STATUS_ERROR_CONTEXT_NOT_FOUND = 51, + SGI_STATUS_ERROR_INVALID_MESSAGE_FORMAT = 52, + SGI_STATUS_ERROR_SERVICE_NOT_SUPPORTED = 53, + SGI_STATUS_ERROR_SYSTEM_FAILURE = 54, + SGI_STATUS_ERROR_NO_RESOURCES_AVAILABLE = 55, + SGI_STATUS_ERROR_NO_MEMORY_AVAILABLE = 56, + SGI_STATUS_MAX, +} SGIStatus_t; + + +typedef struct { + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier + pdn_type_t pdn_type; ///< PDN Type + PAA_t paa; ///< PDN Address Allocation +} SGICreateEndpointReq; + +typedef struct { + SGIStatus_t status; ///< Status of endpoint creation (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier + pdn_type_t pdn_type; ///< PDN Type + PAA_t paa; ///< PDN Address Allocation +} SGICreateEndpointResp; + +typedef struct { + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + Teid_t enb_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier +} SGIUpdateEndpointReq; + +typedef struct { + SGIStatus_t status; ///< Status of endpoint creation (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + Teid_t enb_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier +} SGIUpdateEndpointResp; + + +typedef struct { + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier + pdn_type_t pdn_type; ///< PDN Type + PAA_t paa; ///< PDN Address Allocation +} SGIDeleteEndpointReq; + +typedef struct { + SGIStatus_t status; ///< Status of endpoint deletion (Failed = 0xFF or Success = 0x0) + Teid_t context_teid; ///< Tunnel Endpoint Identifier S11 + Teid_t sgw_S1u_teid; ///< Tunnel Endpoint Identifier S1-U + ebi_t eps_bearer_id; ///< EPS bearer identifier + pdn_type_t pdn_type; ///< PDN Type + PAA_t paa; ///< PDN Address Allocation +} SGIDeleteEndpointResp; + +#endif /* SGI_FORWARD_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/messages_def.h b/openair-cn/COMMON/messages_def.h new file mode 100644 index 0000000000..9c81a1b255 --- /dev/null +++ b/openair-cn/COMMON/messages_def.h @@ -0,0 +1,15 @@ +// These messages files are mandatory and must always be placed in first position +#include "intertask_messages_def.h" +#include "timer_messages_def.h" + +// Messages files used between tasks +#include "gtpv1_u_messages_def.h" +#include "ip_forward_messages_def.h" +#include "mme_app_messages_def.h" +#include "nas_messages_def.h" +#include "s11_messages_def.h" +#include "s1ap_messages_def.h" +#include "s6a_messages_def.h" +#include "sctp_messages_def.h" +#include "sgw_lite_def.h" +#include "udp_messages_def.h" diff --git a/openair-cn/COMMON/messages_types.h b/openair-cn/COMMON/messages_types.h new file mode 100644 index 0000000000..fc5048c451 --- /dev/null +++ b/openair-cn/COMMON/messages_types.h @@ -0,0 +1,24 @@ +/* + * messages_types.h + * + * Created on: Oct 14, 2013 + * Author: winckel + */ + +#ifndef MESSAGES_TYPES_H_ +#define MESSAGES_TYPES_H_ + +#include "timer_messages_types.h" + +#include "gtpv1_u_messages_types.h" +#include "ip_forward_messages_types.h" +#include "mme_app_messages_types.h" +#include "s11_messages_types.h" +#include "s1ap_messages_types.h" +#include "nas_messages_types.h" +#include "s6a_messages_types.h" +#include "sctp_messages_types.h" +#include "sgw_lite_messages_types.h" +#include "udp_messages_types.h" + +#endif /* MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/mme_app_messages_def.h b/openair-cn/COMMON/mme_app_messages_def.h new file mode 100644 index 0000000000..5060d6dc6f --- /dev/null +++ b/openair-cn/COMMON/mme_app_messages_def.h @@ -0,0 +1,3 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. + +//MESSAGE_DEF(S1AP_SCTP_NEW_MESSAGE_IND, MESSAGE_PRIORITY_MED, S1apSctpNewMessageInd, s1apSctpNewMessageInd) diff --git a/openair-cn/COMMON/mme_app_messages_types.h b/openair-cn/COMMON/mme_app_messages_types.h new file mode 100644 index 0000000000..1d636c0848 --- /dev/null +++ b/openair-cn/COMMON/mme_app_messages_types.h @@ -0,0 +1,6 @@ +#ifndef MME_APP_MESSAGES_TYPES_H_ +#define MME_APP_MESSAGES_TYPES_H_ + + + +#endif /* MME_APP_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/nas_messages_def.h b/openair-cn/COMMON/nas_messages_def.h new file mode 100644 index 0000000000..07b296697e --- /dev/null +++ b/openair-cn/COMMON/nas_messages_def.h @@ -0,0 +1,16 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. + +MESSAGE_DEF(NAS_PAGING_IND, MESSAGE_PRIORITY_MED, nas_paging_ind_t, nas_paging_ind) +MESSAGE_DEF(NAS_CONNECTION_ESTABLISHMENT_IND, MESSAGE_PRIORITY_MED, nas_conn_est_ind_t, nas_conn_est_ind) +MESSAGE_DEF(NAS_CONNECTION_ESTABLISHMENT_RSP, MESSAGE_PRIORITY_MED, nas_conn_est_rsp_t, nas_conn_est_rsp) +MESSAGE_DEF(NAS_CONNECTION_RELEASE_IND, MESSAGE_PRIORITY_MED, nas_conn_rel_ind_t, nas_conn_rel_ind) +MESSAGE_DEF(NAS_UPLINK_DATA_IND, MESSAGE_PRIORITY_MED, nas_ul_data_ind_t, nas_ul_data_ind) +MESSAGE_DEF(NAS_DOWNLINK_DATA_IND, MESSAGE_PRIORITY_MED, nas_dl_data_ind_t, nas_dl_data_ind) +MESSAGE_DEF(NAS_NON_DELIVERY_IND, MESSAGE_PRIORITY_MED, nas_non_del_ind_t, nas_non_del_ind) +MESSAGE_DEF(NAS_RAB_ESTABLISHMENT_REQ, MESSAGE_PRIORITY_MED, nas_rab_est_req_t, nas_rab_est_req) +MESSAGE_DEF(NAS_RAB_ESTABLISHMENT_RESP, MESSAGE_PRIORITY_MED, nas_rab_est_rsp_t, nas_rab_est_rsp) +MESSAGE_DEF(NAS_RAB_RELEASE_REQ, MESSAGE_PRIORITY_MED, nas_rab_rel_req_t, nas_rab_rel_req) +MESSAGE_DEF(NAS_ATTACH_REQ, MESSAGE_PRIORITY_MED, nas_attach_req_t, nas_attach_req) +MESSAGE_DEF(NAS_ATTACH_ACCEPT, MESSAGE_PRIORITY_MED, nas_attach_accept_t, nas_attach_accept) +MESSAGE_DEF(NAS_AUTHENTICATION_REQ, MESSAGE_PRIORITY_MED, nas_auth_req_t, nas_auth_req) +MESSAGE_DEF(NAS_AUTHENTICATION_RESP, MESSAGE_PRIORITY_MED, nas_auth_resp_t, nas_auth_resp) diff --git a/openair-cn/COMMON/nas_messages_types.h b/openair-cn/COMMON/nas_messages_types.h new file mode 100644 index 0000000000..bdba9516e1 --- /dev/null +++ b/openair-cn/COMMON/nas_messages_types.h @@ -0,0 +1,77 @@ +#include "as_message.h" + +#ifndef NAS_MESSAGES_TYPES_H_ +#define NAS_MESSAGES_TYPES_H_ + +typedef struct { + +} nas_paging_ind_t; + +typedef struct { + nas_establish_ind_t nas; + + /* Transparent message from s1ap to be forwarded to MME_APP or + * to S1AP if connection establishment is rejected by NAS. + */ + s1ap_initial_ue_message_t transparent; +} nas_conn_est_ind_t; + +typedef struct { + +} nas_conn_est_rsp_t; + +typedef struct { + +} nas_conn_rel_ind_t; + +typedef struct { + +} nas_ul_data_ind_t; + +typedef dl_info_transfer_req_t nas_dl_data_ind_t; + +typedef struct { + +} nas_non_del_ind_t; + +typedef struct { + +} nas_rab_est_req_t; + +typedef struct { + +} nas_rab_est_rsp_t; + +typedef struct { + +} nas_rab_rel_req_t; + +typedef struct { + /* TODO: Set the correct size */ + char apn[100]; + char imsi[16]; +#define INITIAL_REQUEST (0x1) + unsigned initial:1; + s1ap_initial_ue_message_t transparent; +} nas_attach_req_t; + +typedef struct { + char imsi[16]; + +#define NAS_FAILURE_OK 0x0 +#define NAS_FAILURE_IND 0x1 + unsigned failure:1; + int cause; + +} nas_auth_req_t; + +typedef struct { + char imsi[16]; +} nas_auth_resp_t; + +typedef struct { + + s1ap_initial_ctxt_setup_req_t transparent; +} nas_attach_accept_t; + +#endif /* NAS_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/s11_messages_def.h b/openair-cn/COMMON/s11_messages_def.h new file mode 100644 index 0000000000..9735d9eff0 --- /dev/null +++ b/openair-cn/COMMON/s11_messages_def.h @@ -0,0 +1 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. diff --git a/openair-cn/COMMON/s11_messages_types.h b/openair-cn/COMMON/s11_messages_types.h new file mode 100644 index 0000000000..701eda8354 --- /dev/null +++ b/openair-cn/COMMON/s11_messages_types.h @@ -0,0 +1,4 @@ +#ifndef S11_MESSAGES_TYPES_H_ +#define S11_MESSAGES_TYPES_H_ + +#endif /* S11_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/s1ap_messages_def.h b/openair-cn/COMMON/s1ap_messages_def.h new file mode 100644 index 0000000000..3cd56b0f2d --- /dev/null +++ b/openair-cn/COMMON/s1ap_messages_def.h @@ -0,0 +1,4 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. + +MESSAGE_DEF(S1AP_SCTP_NEW_MESSAGE_IND, MESSAGE_PRIORITY_MED, s1ap_sctp_new_msg_ind_t, s1ap_sctp_new_msg_ind) +MESSAGE_DEF(S1AP_UE_CAPABILITIES_IND, MESSAGE_PRIORITY_MED, s1ap_ue_cap_ind_t, s1ap_ue_cap_ind) diff --git a/openair-cn/COMMON/s1ap_messages_types.h b/openair-cn/COMMON/s1ap_messages_types.h new file mode 100644 index 0000000000..400eca5055 --- /dev/null +++ b/openair-cn/COMMON/s1ap_messages_types.h @@ -0,0 +1,51 @@ +#ifndef S1AP_MESSAGES_TYPES_H_ +#define S1AP_MESSAGES_TYPES_H_ + +typedef struct { + uint8_t *buffer; ///< SCTP buffer + uint32_t buf_length; ///< SCTP buffer length + int32_t assoc_id; ///< SCTP physical association ID + uint8_t stream; ///< Stream number on which data had been received + uint16_t instreams; ///< Number of input streams for the SCTP connection between peers + uint16_t outstreams; ///< Number of output streams for the SCTP connection between peers +} s1ap_sctp_new_msg_ind_t; + +typedef struct s1ap_initial_ue_message_s { + unsigned eNB_ue_s1ap_id:24; + uint32_t mme_ue_s1ap_id; + cgi_t e_utran_cgi; +} s1ap_initial_ue_message_t; + +typedef struct s1ap_initial_ctxt_setup_req_s { + unsigned eNB_ue_s1ap_id:24; + uint32_t mme_ue_s1ap_id; + + /* Key eNB */ + uint8_t keNB[32]; + + ambr_t ambr; + ambr_t apn_ambr; + + /* EPS bearer ID */ + unsigned ebi:4; + + /* QoS */ + qci_t qci; + priority_level_t prio_level; + pre_emp_vulnerability_t pre_emp_vulnerability; + pre_emp_capability_t pre_emp_capability; + + /* S-GW TEID for user-plane */ + uint32_t teid; + /* S-GW IP address for User-Plane */ + ip_address_t s_gw_address; +} s1ap_initial_ctxt_setup_req_t; + +typedef struct s1ap_ue_cap_ind_s { + unsigned eNB_ue_s1ap_id:24; + uint32_t mme_ue_s1ap_id; + uint8_t radio_capabilities[100]; + uint32_t radio_capabilities_length; +} s1ap_ue_cap_ind_t; + +#endif /* S1AP_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/s6a_messages_def.h b/openair-cn/COMMON/s6a_messages_def.h new file mode 100644 index 0000000000..bc9caf3937 --- /dev/null +++ b/openair-cn/COMMON/s6a_messages_def.h @@ -0,0 +1,5 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. +MESSAGE_DEF(S6A_UPDATE_LOCATION_REQ, MESSAGE_PRIORITY_MED, s6a_update_location_req_t, s6a_update_location_req) +MESSAGE_DEF(S6A_UPDATE_LOCATION_ANS, MESSAGE_PRIORITY_MED, s6a_update_location_ans_t, s6a_update_location_ans) +MESSAGE_DEF(S6A_AUTH_INFO_REQ, MESSAGE_PRIORITY_MED, s6a_auth_info_req_t, s6a_auth_info_req) +MESSAGE_DEF(S6A_AUTH_INFO_ANS, MESSAGE_PRIORITY_MED, s6a_auth_info_ans_t, s6a_auth_info_ans) diff --git a/openair-cn/COMMON/s6a_messages_types.h b/openair-cn/COMMON/s6a_messages_types.h new file mode 100644 index 0000000000..2b59bb8664 --- /dev/null +++ b/openair-cn/COMMON/s6a_messages_types.h @@ -0,0 +1,43 @@ +#ifndef S6A_MESSAGES_TYPES_H_ +#define S6A_MESSAGES_TYPES_H_ + +typedef struct { +#define SKIP_SUBSRIBER_DATA (0x1) + unsigned skip_subsriber_data:1; +#define INITIAL_ATTACH (0x1) + unsigned initial_attach:1; + + char imsi[IMSI_DIGITS_MAX]; + uint8_t imsi_length; + plmn_t visited_plmn; + rat_type_t rat_type; +} s6a_update_location_req_t; + +typedef struct { + char imsi[IMSI_DIGITS_MAX]; + uint8_t imsi_length; + + /* Result of the update location request procedure */ + s6a_result_t result; + subscription_data_t subscription_data; +} s6a_update_location_ans_t; + +typedef struct { + char imsi[IMSI_DIGITS_MAX]; + uint8_t imsi_length; + plmn_t visited_plmn; + /* Number of vectors to retrieve from HSS, should be equal to one */ + uint8_t nb_of_vectors; +} s6a_auth_info_req_t; + +typedef struct { + char imsi[IMSI_DIGITS_MAX]; + uint8_t imsi_length; + + /* Result of the authentication information procedure */ + s6a_result_t result; + /* Authentication info containing the vector(s) */ + authentication_info_t auth_info; +} s6a_auth_info_ans_t; + +#endif /* S6A_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/sctp_messages_def.h b/openair-cn/COMMON/sctp_messages_def.h new file mode 100644 index 0000000000..d145139f1b --- /dev/null +++ b/openair-cn/COMMON/sctp_messages_def.h @@ -0,0 +1,6 @@ +//WARNING: Do not include this header directly. Use intertask_interface.h instead. + +MESSAGE_DEF(SCTP_INIT_MSG, MESSAGE_PRIORITY_MED, SctpInit, sctpInit) +MESSAGE_DEF(SCTP_NEW_DATA_REQ, MESSAGE_PRIORITY_MED, SctpNewDataReq, sctpNewDataReq) +MESSAGE_DEF(SCTP_NEW_ASSOCIATION, MESSAGE_PRIORITY_MAX, sctp_new_peer_t, sctp_new_peer) +MESSAGE_DEF(SCTP_CLOSE_ASSOCIATION, MESSAGE_PRIORITY_MAX, sctp_close_association_t, sctp_close_association) diff --git a/openair-cn/COMMON/sctp_messages_types.h b/openair-cn/COMMON/sctp_messages_types.h new file mode 100644 index 0000000000..fc60467717 --- /dev/null +++ b/openair-cn/COMMON/sctp_messages_types.h @@ -0,0 +1,34 @@ +#ifndef SCTP_MESSAGES_TYPES_H_ +#define SCTP_MESSAGES_TYPES_H_ + +typedef struct { + uint8_t *buffer; + uint32_t bufLen; + uint32_t assocId; + uint16_t stream; +} SctpNewDataReq; + +typedef struct { + /* Request usage of ipv4 */ + unsigned ipv4:1; + /* Request usage of ipv6 */ + unsigned ipv6:1; + uint8_t nb_ipv4_addr; + uint32_t ipv4_address[10]; + uint8_t nb_ipv6_addr; + char *ipv6_address[10]; + uint16_t port; + uint32_t ppid; +} SctpInit; + +typedef struct { + uint32_t assoc_id; +} sctp_close_association_t; + +typedef struct { + uint32_t instreams; + uint32_t outstreams; + uint32_t assoc_id; +} sctp_new_peer_t; + +#endif /* SCTP_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COMMON/security_types.h b/openair-cn/COMMON/security_types.h new file mode 100644 index 0000000000..9affe8ad1c --- /dev/null +++ b/openair-cn/COMMON/security_types.h @@ -0,0 +1,183 @@ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#if !defined(HAVE_UINT128_T) +# include <gmp.h> +#endif + +#include <stdlib.h> +#include <stdint.h> +#include <inttypes.h> + +#include "queue.h" + +#ifndef SECURITY_TYPES_H_ +#define SECURITY_TYPES_H_ + +#define RAND_LENGTH_BITS (128) +#define RAND_LENGTH_OCTETS (RAND_LENGTH_BITS/8) +#define AUTH_KEY_LENGTH_BITS (128) +#define AUTH_KEY_LENGTH_OCTETS (AUTH_KEY_LENGTH_BITS/8) +#define KASME_LENGTH_BITS (256) +#define KASME_LENGTH_OCTETS (KASME_LENGTH_BITS/8) +/* In OCTETS */ +#define XRES_LENGTH_MIN (4) +#define XRES_LENGTH_MAX (16) +#define AUTN_LENGTH_BITS (128) +#define AUTN_LENGTH_OCTETS (AUTN_LENGTH_BITS/8) + +/* Some methods to convert a string to an int64_t */ +/* +#define STRING_TO_64BITS(sTRING, cONTAINER) \ + sscanf(sTRING, "%" SCN64, cONTAINER) +#define STRING_TO_U64BITS(sTRING, cONTAINER) \ + sscanf(sTRING, "%" SCNu64, cONTAINER) +*/ + +/* GCC supports 128 bits integers on certain architectures */ +#if defined(ENABLE_GMP_TYPES) +/* Use gmplib in case GCC doesn't support 128 bits integers natively */ +typedef mpz_t rand_t; +typedef mpz_t auth_key_t; +typedef mpz_t auth_res_t; +typedef mpz_t kasme_t; +typedef mpz_t autn_t; + +/* RES amd XRES can have a variable length of 4-16 octets */ +typedef struct { + ssize_t size; + auth_res_t data; +} res_t; + +/* Converts a string to 128 bits gmplib integer holder */ +# define STRING_TO_XBITS(sTRING, lENGTH, cONTAINER, rET) \ +do { \ + char temp[129]; \ + if (lENGTH > 64) { \ + rET = -1; \ + } else { \ + hexa_to_ascii(sTRING, temp, lENGTH); \ + temp[2 * lENGTH] = '\0'; \ + rET = mpz_init_set_str (cONTAINER, temp, 16); \ + } \ +} while(0) + +# define STRING_TO_128BITS(sTRING, cONTAINER, rET) \ +STRING_TO_XBITS(sTRING, 16, cONTAINER, rET) + +# define STRING_TO_256BITS(sTRING, cONTAINER, rET) \ +STRING_TO_XBITS(sTRING, 32, cONTAINER, rET) + +# define STRING_TO_RAND STRING_TO_128BITS +# define STRING_TO_AUTH_KEY STRING_TO_128BITS +# define STRING_TO_AUTH_RES STRING_TO_128BITS +# define STRING_TO_AUTN STRING_TO_128BITS +# define STRING_TO_KASME STRING_TO_256BITS +# define STRING_TO_XRES(sTRING, lENGTH, cONTAINER, rET) \ +do { \ + STRING_TO_XBITS(sTRING, lENGTH, (cONTAINER)->data, rET); \ + if (rET != -1) \ + (cONTAINER)->size = mpz_sizeinbase((cONTAINER)->data, 16); \ +} while(0) + +/* Holds an E-UTRAN authentication vector */ +typedef struct eutran_vector_s { + rand_t rand; + res_t xres; + autn_t autn; + kasme_t kasme; + + /* one UE can have multiple vectors so use STAILQ lists for easy management */ + STAILQ_ENTRY(eutran_vector_s) entries; +} eutran_vector_t; + +#else /* defined(ENABLE_GMP_TYPES) */ + +/* Converts a string to 128 bits gmplib integer holder */ +# define STRING_TO_XBITS(sTRING, lENGTH, cONTAINER, rET) \ +do { \ + memcpy(cONTAINER, sTRING, lENGTH); \ + rET = 0; \ +} while(0) + +# define STRING_TO_128BITS(sTRING, cONTAINER, rET) \ +STRING_TO_XBITS(sTRING, 16, cONTAINER, rET) + +# define STRING_TO_256BITS(sTRING, cONTAINER, rET) \ +STRING_TO_XBITS(sTRING, 32, cONTAINER, rET) + +# define STRING_TO_RAND STRING_TO_128BITS +# define STRING_TO_AUTH_KEY STRING_TO_128BITS +# define STRING_TO_AUTH_RES STRING_TO_128BITS +# define STRING_TO_AUTN STRING_TO_128BITS +# define STRING_TO_KASME STRING_TO_256BITS +# define STRING_TO_XRES(sTRING, lENGTH, cONTAINER, rET) \ +do { \ + STRING_TO_XBITS(sTRING, lENGTH, (cONTAINER)->data, rET); \ + if (rET != -1) \ + (cONTAINER)->size = lENGTH; \ +} while(0) + +/* RES amd XRES can have a variable length of 4-16 octets */ +typedef struct { + ssize_t size; + uint8_t data[XRES_LENGTH_MAX]; +} res_t; + +#define FORMAT_128BITS "%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x" +#define RAND_FORMAT FORMAT_128BITS +#define AUTN_FORMAT FORMAT_128BITS +#define KASME_FORMAT FORMAT_128BITS + +#define DISPLAY_128BITS(bUFFER) \ +bUFFER[0], bUFFER[1], bUFFER[2], bUFFER[3], bUFFER[4], bUFFER[5], bUFFER[6], bUFFER[7], \ +bUFFER[8], bUFFER[9], bUFFER[10], bUFFER[11], bUFFER[12], bUFFER[13], bUFFER[14], bUFFER[15] +#define DISPLAY_128BITS_2(bUFFER) \ +bUFFER[16], bUFFER[17], bUFFER[18], bUFFER[19], bUFFER[20], bUFFER[21], bUFFER[22], bUFFER[23], \ +bUFFER[24], bUFFER[25], bUFFER[26], bUFFER[27], bUFFER[28], bUFFER[29], bUFFER[30], bUFFER[31] + +#define RAND_DISPLAY(bUFFER) DISPLAY_128BITS(bUFFER) +#define AUTN_DISPLAY(bUFFER) DISPLAY_128BITS(bUFFER) +/* Display only first 128 bits of KASME */ +#define KASME_DISPLAY_1(bUFFER) DISPLAY_128BITS(bUFFER) +#define KASME_DISPLAY_2(bUFFER) DISPLAY_128BITS_2(bUFFER) + +/* Holds an E-UTRAN authentication vector */ +typedef struct eutran_vector_s { + uint8_t rand[RAND_LENGTH_OCTETS]; + res_t xres; + uint8_t autn[AUTN_LENGTH_OCTETS]; + uint8_t kasme[KASME_LENGTH_OCTETS]; + + /* one UE can have multiple vectors so use STAILQ lists for easy management */ + STAILQ_ENTRY(eutran_vector_s) entries; +} eutran_vector_t; + +#endif /* defined(ENABLE_GMP_TYPES) */ + +#define FC_KASME (0x10) +#define FC_KENB (0x11) +#define FC_NH (0x12) +#define FC_KENB_STAR (0x13) +/* 33401 #A.7 Algorithm for key derivation function. + * This FC should be used for: + * - NAS Encryption algorithm + * - NAS Integrity algorithm + * - RRC Encryption algorithm + * - RRC Integrity algorithm + * - User Plane Encryption algorithm + */ +#define FC_ALG_KEY_DER (0x15) +#define FC_KASME_TO_CK (0x16) + +typedef enum { + NAS_ENC_ALG = 0x01, + NAS_INT_ALG = 0x02, + RRC_ENC_ALG = 0x03, + RRC_INT_ALG = 0x04, + UP_ENC_ALG = 0x05, + UP_INT_ALG = 0x06 +} algorithm_type_dist_t; + +#endif /* SECURITY_TYPES_H_ */ diff --git a/openair-cn/COMMON/sgw_lite_def.h b/openair-cn/COMMON/sgw_lite_def.h new file mode 100644 index 0000000000..afd503dd62 --- /dev/null +++ b/openair-cn/COMMON/sgw_lite_def.h @@ -0,0 +1,6 @@ +MESSAGE_DEF(SGW_CREATE_SESSION_REQUEST, MESSAGE_PRIORITY_MED, SgwCreateSessionRequest, sgwCreateSessionRequest) +MESSAGE_DEF(SGW_CREATE_SESSION_RESPONSE, MESSAGE_PRIORITY_MED, SgwCreateSessionResponse, sgwCreateSessionResponse) +MESSAGE_DEF(SGW_MODIFY_BEARER_REQUEST, MESSAGE_PRIORITY_MED, SgwModifyBearerRequest, sgwModifyBearerRequest) +MESSAGE_DEF(SGW_MODIFY_BEARER_RESPONSE, MESSAGE_PRIORITY_MED, SgwModifyBearerResponse, sgwModifyBearerResponse) +MESSAGE_DEF(SGW_DELETE_SESSION_REQUEST, MESSAGE_PRIORITY_MED, SgwDeleteSessionRequest, sgwDeleteSessionRequest) +MESSAGE_DEF(SGW_DELETE_SESSION_RESPONSE, MESSAGE_PRIORITY_MED, SgwDeleteSessionResponse, sgwDeleteSessionResponse) diff --git a/openair-cn/COMMON/sgw_lite_messages_types.h b/openair-cn/COMMON/sgw_lite_messages_types.h new file mode 100644 index 0000000000..68a569d8b5 --- /dev/null +++ b/openair-cn/COMMON/sgw_lite_messages_types.h @@ -0,0 +1,209 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file sgw_lite_messages_types.h + * \brief S11 definitions for interaction between MME and S11 + * 3GPP TS 29.274. + * Messages are the same as for GTPv2-C but here we abstract the UDP layer + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +#include "../SGW-LITE/sgw_lite_ie_defs.h" + +#ifndef SGW_LITE_MESSAGES_TYPES_H_ +#define SGW_LITE_MESSAGES_TYPES_H_ + +/** @struct SgwCreateSessionRequest + * @brief Create Session Request + * + * The Create Session Request will be sent on S11 interface as + * part of these procedures: + * - E-UTRAN Initial Attach + * - UE requested PDN connectivity + * - Tracking Area Update procedure with Serving GW change + * - S1/X2-based handover with SGW change + */ +typedef struct { + Teid_t teid; ///< S11- S-GW Tunnel Endpoint Identifier + Imsi_t imsi; + Msisdn_t msisdn; + Mei_t mei; + Uli_t uli; + ServingNetwork_t serving_network; + rat_type_t rat_type; + FTeid_t sender_fteid_for_cp; ///< Sender F-TEID for control plane (MME) + FTeid_t pgw_address_for_cp; ///< PGW S5/S8 address for control plane or PMIP + char apn[APN_MAX_LENGTH + 1]; ///< Access Point Name + SelectionMode_t selection_mode; ///< Selection Mode + pdn_type_t pdn_type; ///< PDN Type + PAA_t paa; ///< PDN Address Allocation + /* Shall include APN Restriction but not used in our case */ + ambr_t ambr; ///< Aggregate Maximum Bit Rate + /* TODO: add Protocol Configuration options */ + FQ_CSID_t mme_fq_csid; + UETimeZone_t ue_time_zone; + UCI_t uci; ///< User CSG Information + bearer_to_create_t bearer_to_create; ///< Bearer Contexts to be created + + indication_flags_t indication_flags; + + /* S11 stack specific parameter. Not used in standalone epc mode */ + void *trxn; ///< Transaction identifier + uint32_t peer_ip; ///< MME ipv4 address for S-GW or S-GW ipv4 address for MME + uint16_t peer_port; ///< MME port for S-GW or S-GW port for MME +} SgwCreateSessionRequest; + +/** @struct SgwCreateSessionResponse + * @brief Create Session Response + * + * The Create Session Response will be sent on S11 interface as + * part of these procedures: + * - E-UTRAN Initial Attach + * - UE requested PDN connectivity + * - Tracking Area Update procedure with SGW change + * - S1/X2-based handover with SGW change + */ +typedef struct { + Teid_t teid; ///< Tunnel Endpoint Identifier + + SGWCause_t cause; + FTeid_t s11_sgw_teid; ///< Sender F-TEID for control plane + FTeid_t s5_s8_pgw_teid; ///< Sender F-TEID for control plane + PAA_t paa; ///< PDN Address Allocation + APNRestriction_t apn_restriction; + bearer_context_created_t bearer_context_created; + FQ_CSID_t pgw_fq_csid; + FQ_CSID_t sgw_fq_csid; + + /* S11 stack specific parameter. Not used in standalone epc mode */ + void *trxn; ///< Transaction identifier + uint32_t peer_ip; ///< MME ipv4 address +} SgwCreateSessionResponse; + +/** @struct SgwModifyBearerRequest + * @brief Modify Bearer Request + * + * The Modify Bearer Request will be sent on S11 interface as + * part of these procedures: + * - E-UTRAN Tracking Area Update without SGW Change + * - UE triggered Service Request + * - S1-based Handover + * - E-UTRAN Initial Attach + * - UE requested PDN connectivity + * - X2-based handover without SGWrelocation + */ +typedef struct { + Teid_t teid; ///< Tunnel Endpoint Identifier +// FTeid_t s11_sgw_teid; ///< S11- S-GW Tunnel Endpoint Identifier + /* Delay Value in integer multiples of 50 millisecs, or zero */ + DelayValue_t delay_dl_packet_notif_req; + bearer_context_to_modify_t bearer_context_to_modify; + FQ_CSID_t mme_fq_csid; + indication_flags_t indication_flags; + rat_type_t rat_type; + + /* S11 stack specific parameter. Not used in standalone epc mode */ + void *trxn; ///< Transaction identifier +} SgwModifyBearerRequest; + +/** @struct SgwModifyBearerResponse + * @brief Modify Bearer Response + * + * The Modify Bearer Response will be sent on S11 interface as + * part of these procedures: + * - E-UTRAN Tracking Area Update without SGW Change + * - UE triggered Service Request + * - S1-based Handover + * - E-UTRAN Initial Attach + * - UE requested PDN connectivity + * - X2-based handover without SGWrelocation + */ +typedef struct { + Teid_t teid; ///< Tunnel Endpoint Identifier + SGWCause_t cause; +#define MODIFY_BEARER_RESPONSE_MOD 0x0 +#define MODIFY_BEARER_RESPONSE_REM 0x1 + unsigned present:1; ///< Choice present in union choice + union { + bearer_context_modified_t bearer_modified; ///< Bearer to be modified + bearer_for_removal_t bearer_for_removal; ///< Bearer to be removed + } choice; + + /* S11 stack specific parameter. Not used in standalone epc mode */ + void *trxn; ///< Transaction identifier +} SgwModifyBearerResponse; + +typedef struct { + Teid_t teid; ///< Tunnel Endpoint Identifier + EBI_t lbi; ///< Linked EPS Bearer ID + FTeid_t sender_fteid_for_cp; ///< Sender F-TEID for control plane + + /* Operation Indication: This flag shall be set over S4/S11 interface + * if the SGW needs to forward the Delete Session Request message to + * the PGW. This flag shall not be set if the ISR associated GTP + * entity sends this message to the SGW in the Detach procedure. + * This flag shall also not be set to 1 in the SRNS Relocation Cancel + * Using S4 (6.9.2.2.4a in 3GPP TS 23.060 [4]), Inter RAT handover + * Cancel procedure with SGW change TAU with Serving GW change, + * Gn/Gb based RAU (see 5.5.2.5, 5.3.3.1, D.3.5 in 3GPP TS 23.401 [3], + * respectively), S1 Based handover Cancel procedure with SGW change. + */ + indication_flags_t indication_flags; + + /* GTPv2-C specific parameters */ + void *trxn; + uint32_t peer_ip; +} SgwDeleteSessionRequest; + +/** @struct SgwDeleteSessionResponse + * @brief Delete Session Response + * + * The Delete Session Response will be sent on S11 interface as + * part of these procedures: + * - EUTRAN Initial Attach + * - UE, HSS or MME Initiated Detach + * - UE or MME Requested PDN Disconnection + * - Tracking Area Update with SGW Change + * - S1 Based Handover with SGW Change + * - X2 Based Handover with SGW Relocation + * - S1 Based handover cancel with SGW change + */ +typedef struct { + Teid_t teid; ///< Remote Tunnel Endpoint Identifier + SGWCause_t cause; + + /* GTPv2-C specific parameters */ + void *trxn; + uint32_t peer_ip; +} SgwDeleteSessionResponse; + +#endif diff --git a/openair-cn/COMMON/tasks_def.h b/openair-cn/COMMON/tasks_def.h new file mode 100644 index 0000000000..40461db8ce --- /dev/null +++ b/openair-cn/COMMON/tasks_def.h @@ -0,0 +1,25 @@ +// This task is mandatory and must always be placed in first position +TASK_DEF(TASK_TIMER, TASK_PRIORITY_MED) + +// Other possible tasks in the process + +/// GTPV1-U task +TASK_DEF(TASK_GTPV1_U, TASK_PRIORITY_MED) +/// FW_IP task +TASK_DEF(TASK_FW_IP, TASK_PRIORITY_MED) +/// MME Applicative task +TASK_DEF(TASK_MME_APP, TASK_PRIORITY_MED) +/// NAS task +TASK_DEF(TASK_NAS, TASK_PRIORITY_MED) +/// S1AP task +TASK_DEF(TASK_S11, TASK_PRIORITY_MED) +/// S1AP task +TASK_DEF(TASK_S1AP, TASK_PRIORITY_MED) +/// S6a task +TASK_DEF(TASK_S6A, TASK_PRIORITY_MED) +/// SCTP task +TASK_DEF(TASK_SCTP, TASK_PRIORITY_MED) +/// Serving and Proxy Gateway Application task +TASK_DEF(TASK_SPGW_APP, TASK_PRIORITY_MED) +/// UDP task +TASK_DEF(TASK_UDP, TASK_PRIORITY_MED) diff --git a/openair-cn/COMMON/udp_messages_def.h b/openair-cn/COMMON/udp_messages_def.h new file mode 100644 index 0000000000..08e98b801e --- /dev/null +++ b/openair-cn/COMMON/udp_messages_def.h @@ -0,0 +1,3 @@ +MESSAGE_DEF(UDP_INIT, MESSAGE_PRIORITY_MED, udp_init_t, udp_init) +MESSAGE_DEF(UDP_DATA_REQ, MESSAGE_PRIORITY_MED, udp_data_req_t, udp_data_req) +MESSAGE_DEF(UDP_DATA_IND, MESSAGE_PRIORITY_MED, udp_data_ind_t, udp_data_ind) diff --git a/openair-cn/COMMON/udp_messages_types.h b/openair-cn/COMMON/udp_messages_types.h new file mode 100644 index 0000000000..e6a7ebd0bd --- /dev/null +++ b/openair-cn/COMMON/udp_messages_types.h @@ -0,0 +1,16 @@ +#ifndef UDP_MESSAGES_TYPES_H_ +#define UDP_MESSAGES_TYPES_H_ + +typedef struct { + uint32_t port; + char *address; +} udp_init_t; + +typedef struct { + uint8_t *buffer; + uint32_t buffer_length; + uint32_t peer_address; + uint32_t peer_port; +} udp_data_req_t, udp_data_ind_t; + +#endif /* UDP_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/COPYING b/openair-cn/COPYING new file mode 100644 index 0000000000..94a9ed024d --- /dev/null +++ b/openair-cn/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/openair-cn/ChangeLog b/openair-cn/ChangeLog new file mode 100644 index 0000000000..0db17ac628 --- /dev/null +++ b/openair-cn/ChangeLog @@ -0,0 +1,15 @@ +v0.1: +- Build system +- SCTP layer v0.1 +- S1AP layer v0.1 +v0.2: +- Updated S1AP messages to RELEASE9 v9.8 +- S1-U layer using nw-gtpv1u +v0.3: +- Updated S1AP messages to RELEASE10 v10.5 +- Added NAS interface +- Added MME APPlication +- Converted sctp_bind to sctp_bindx for multi-homing support +- Added configuration file parsing +- S6a layer v0.1 using freeDiameter +- KeNB key derivy function \ No newline at end of file diff --git a/openair-cn/DOCS/DOXYGEN/Doxyfile.in b/openair-cn/DOCS/DOXYGEN/Doxyfile.in new file mode 100644 index 0000000000..90679f9ecd --- /dev/null +++ b/openair-cn/DOCS/DOXYGEN/Doxyfile.in @@ -0,0 +1,1718 @@ +# Doxyfile 1.7.4 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = "The OAISIM MME provides an almost complete implementation of Evolved Packet Core network for LTE. This include MME, S+P-Gateways." + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = ../Documentation + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = YES + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = YES + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @top_srcdir@ \ + @top_builddir@/S1AP/s1ap_ies_defs.h + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = @top_builddir@ \ + @top_srcdir@/S1AP/MESSAGES + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = *.d + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is adviced to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to the +# mathjax.org site, so you can quickly see the result without installing +# MathJax, but it is strongly recommended to install a local copy of MathJax +# before deployment. + +MATHJAX_RELPATH = http://www.mathjax.org/mathjax + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = YES + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4 + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = NO + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called Helvetica to the output +# directory and reference it in all dot files that doxygen generates. +# When you want a differently looking font you can specify the font name +# using DOT_FONTNAME. You need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = Helvetica + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = YES + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/openair-cn/DOCS/DOXYGEN/Makefile.am b/openair-cn/DOCS/DOXYGEN/Makefile.am new file mode 100644 index 0000000000..46233d367b --- /dev/null +++ b/openair-cn/DOCS/DOXYGEN/Makefile.am @@ -0,0 +1,22 @@ +if HAVE_DOXYGEN +directory = $(top_srcdir)/DOCS/Documentation + +if HAVE_PDFLATEX + doc_DATA = $(directory)oaisim_mme.pdf +else + doc_DATA = $(directory) +endif +$(directory): doxyfile.stamp + +doxyfile.stamp: + $(DOXYGEN) Doxyfile + echo Timestamp > doxyfile.stamp + +CLEANFILES = doxyfile.stamp + +all-local: doxyfile.stamp +clean-local: + rm -f doxyfile.stamp + rm -rf $(top_srcdir)/DOCS/Documentation/html + rm -rf $(top_srcdir)/DOCS/Documentation/latex +endif diff --git a/openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.pdf b/openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a7531e18c68ef7da9ca85de38d28934a07f8aac6 GIT binary patch literal 141203 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%0A76Ha* z4)<Wp+{qT0Tp1|_%&KC`e^0W${x&jUN@+y8Ygl!1rZU}#bs;)rnYKVyHdwMFK(K>3 zmj+B0+nxwm#!@xzP#zD@f@2&Z4&<N)XT~HD1uC3#I*E>kRPU%nZVXtoug4oR4}JE- zKljwz1ihEaLuRrp{(zqnzw}KQm%u<U?%8&o*Y^8itVcA`QsGMCDA&@g^srn;;wSAu z86~{3V_J!27Pt{s6FYk7F0LeJys%S8`X-1i(SWV%VSN0>_h>ckvaxzA&?6_=s`x4+ z72H+CGv2k;JPpOPhcVYy{n?z?;lrY<OAWgDYbc(1=*@=3-e7i324V0$lBgpg5ynx| ztkiLlYOdO~XBY?<ZH3|Q^MuS2#v!@Ys~0swG03NSEUN7m#11OBif(F?nG?}~AP1gf z@gd2c-4D~iMH#V&a70wPdLxG2JPzY!gKX&r&MH@iwqDvrKC*o!iKA<hq?G#mZWd7` zE&nP!MaMRRD)3~(<a<-!J-2@jefjRK0KM9pThOQxy$AQUuUZVuKd*m~OqwY<PPaGE z#)TlqgQVuA_$M@5n!8YT`)YGF*Rr!?1w+F4`8c=K{v=dqSI1EPezu;h=`g!AmIT6^ zzoC`PYRfoS6~_Sj9f^dS!6Do!>@lVB$^!mZQ3r^m5ryh?^jb*-_=6*|$if2sL??rJ zAke-T3kKdR>l#G_29rIpQ*lI&UgQ>MpQy)wF&$$D10i_Z61&ES6(dil1(6d=j9J^G zb2J_jT`00|AyB8)ka8B`C>tY21vJB4OdAvw-NF|7F^;#XwTmSV{=oR(eYe%Xmjmi~ z#?DhQrTqXJ_#rJXd2;o6<@KZ1$0f1x+XF*Z2an#?DPspuPcnc36x45tPLtYzUkdC1 z!nO-UiicV`AG!}d>I7s8a#t~=czzD*Teq>Ffx`CzL7$$F>_DtUz|?Ogg91dMT0jYR zSMY&?1riW@ZG+6K>3~09H#q>8W3GeBgz9m&_`UKl#ctKGRX`V8Dh&B!A?qEe{|+TU z@-=9!-9#s=eOiAXA4UV`eQ5Tz=71Glh+FCd#zG-cH%#Ib&Bvqg(uZE?ffK^EL1*^o zoet+az%{Ejjxn93=IOUPbnw$=UMBJ*9wR42oiI`#SsJ}fZKf_GR8QZ5B;(2JItwo@ zjXliLOuC2rm1-R-6$crTbQ`#SsySeL*9es>qN0ta*(q-BVueB>qJGqC(k|A_mk2f2 zrf&TQChM2*W!++7vT3jV4{Qp14s_h%vb}30g}zX3yw2rqdKy@t1`Cj&H8@5inU)Hx zl6y<Cy(ArD&PgcRem47uQubvp%+6Q5wluHVJV)c5T5~6Eu8rF4_G*e@RcTP~&sqd= zoA>;N!y!fradjI<zigK4zZx;f2cEmN_wM!+9cSCcuX-t5Vb^apTFpUNMT!y1>W^C$ zjK#v9ICgKq003S}TQ~vDKA{UX5BPmgL9(N1kV?(=<W8;^wh95vztlRxOIx!zS@8VZ zrY8!MvBChWmq;?roOzX2vKedlqmg3h@@*$EY*EGTFLPK2L29^Jw*q78)jMnGEDjNx z^=Kk%uSS5%jR=?munS%u#U#*47?b7w^n?#xZQlP-@5cpZAUK^v=A9(U13|)%98N!$ zK`9Uf#gQ%H7L$71fwD6ESnEnW9bGRpmb(?1dYA(BLvUD~mRSxib=WP`KVNF^ty!*O zT8S+HcK%VH>Z*jrKZG+44RxL400H2xm^}<VlgtV1_aj6vs^-Vgg3QM9UuNNLlm4WD zhMMBrQoIzJ=8MC7BBsm@JKdItN%>6Nby)DIMyLI|hJcf(Ya^!hiVzgg8Mp21n_8le z&cwzTu+!OZ>pc*(9S}gvTtJY(%|xQd2RAR=C7P6VWI;`>l1yMMbBvhS
jt&bnJ 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 literal 0 HcmV?d00001 diff --git a/openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.tex b/openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.tex new file mode 100644 index 0000000000..be751c0d96 --- /dev/null +++ b/openair-cn/DOCS/Latex/DefaultBearer/DefaultBearer.tex @@ -0,0 +1,1007 @@ +\documentclass[6pt]{article} +\usepackage[margin=1.7cm, a2paper]{geometry} +% \documentclass[border=5pt]{standalone} +\usepackage[usenames,dvipsnames]{xcolor} +\usepackage{float} +\usepackage{tikz} +\usepackage{verbatim} +\usepackage{caption} +\usepackage{pgfplots} +\usepackage{fancyhdr} +\usepackage{lscape} + +\pagestyle{fancy} +\rfoot{Written by Sebastien ROUX \copyright 2013 - Eurecom} + +% Generate PDF with pdflatex command + +\author{Sebastien ROUX} + +\usetikzlibrary{calc,trees,positioning,arrows,chains,shapes.geometric,% + decorations.pathreplacing,decorations.pathmorphing,shapes,% + matrix,shapes.symbols,backgrounds,fit} + +\tikzset{ + background/.style={ + draw, + fill=yellow!30, + align=right, + dashed, + }, + backgroundcomment/.style={ + draw, + fill=yellow!30, + dashed, + }, + backgroundopt/.style={ + draw, + fill=blue!2, + dashed + }, + schritt/.style={ + draw, + rounded corners, + fill=blue!20, + inner xsep=2em, + }, + type/.style={ + dashed + }, + square matrix/.style={ + matrix of nodes, + draw, + column sep=-3.5cm, row sep=0.4cm, + nodes={ +% minimum height=#1, + anchor=west, + text width=#1, + align=left, + inner sep=0pt + }, + }, + square matrix/.default=5.5cm +} + +% Returns three nodes: The argument, and the projections of the argument on the left and right borders of the bounding box +\newcommand{\extendnode}[1]{ + (#1) + ($(current bounding box.north east)!(#1)!(current bounding box.south east) + (4.5,0)$) + ($(current bounding box.north west)!(#1)!(current bounding box.south west)$) +} + +\newcommand{\soneapcolor}[1]{ +% {\color{red} #1} + \color{YellowOrange}{#1} +} +\newcommand{\nascolor}[1]{ +% {\color{red} #1} + \color{Cyan}{#1} +} +\newcommand{\sctpcolor}[1]{ +% {\color{red} #1} + \color{LimeGreen}{#1} +} +\newcommand{\ssixcolor}[1]{ +% {\color{red} #1} + \color{RawSienna}{#1} +} +\newcommand{\mmecolor}[1]{ +% {\color{red} #1} + \color{Red}{#1} +} +\newcommand{\spappcolor}[1]{ +% {\color{red} #1} + \color{Mulberry}{#1} +} +\newcommand{\commandname}[1]{ + \large{#1} +} + +% argument #1: any options +\newenvironment{customlegend}[1][]{% + \begingroup + % inits/clears the lists (which might be populated from previous + % axes): + \csname pgfplots@init@cleared@structures\endcsname + \pgfplotsset{#1}% +}{% + % draws the legend: + \csname pgfplots@createlegend\endcsname + \endgroup +}% + +% definition to insert numbers +\pgfkeys{/pgfplots/number in legend/.style={% +/pgfplots/legend image code/.code={% +\node at (0.295,-0.0225){#1}; +},% +}, +} + +% makes \addlegendimage available (typically only available within an +% axis environment): +\def\addlegendimage{\csname pgfplots@addlegendimage\endcsname} + +\begin{document} +\begin{center} +\begin{figure}[H] +\begin{tikzpicture} +\tikzstyle{every node}=[font=\footnotesize] +\matrix (matrix) [row sep=0.7cm, column sep={7.5cm,between origins}, matrix of nodes] { + \node(UE) [schritt] {UE}; & \node(ENB) [schritt] {eNB}; & \node(MME) [schritt] {MME}; & \node(HSS) [schritt] {HSS}; & \node(SPGW) [schritt] {S+P-GW};\\ + \node(RRC1UE) [schritt] {RRC}; & \node(RRC1ENB) [schritt] {RRC}; \\ + \node(MAC1UE) [schritt] {MAC}; & \node(MAC1ENB) [schritt] {MAC}; \\ + \node(MAC2UE) [schritt] {MAC}; & \node(MAC2ENB) [schritt] {MAC}; \\\\ + \node(RRC2UE) [schritt] {RRC}; & \node(RRC2ENB) [schritt] {RRC}; \\ + \node(RRC3UE) [schritt] {RRC}; & \node(RRC3ENB) [schritt] {RRC}; \\\\ + \node(RRC4UE) [schritt] {RRC}; & \node(RRC4ENB) [schritt] {RRC}; \\\\ + & \node(S1AP1ENB) [schritt] {S1AP}; & \node(S1AP1MME) [schritt] {S1AP}; \\\\ + & \node(S1AP9ENB) [schritt] {S1AP}; & \node(S1AP9MME) [schritt] {S1AP}; \\ + \node(RRC15UE) [schritt] {RRC}; & \node(RRC15ENB) [schritt] {RRC}; \\ + \node(RRC16UE) [schritt] {RRC}; & \node(RRC16ENB) [schritt] {RRC}; \\ + & \node(S1AP10ENB) [schritt] {S1AP}; & \node(S1AP10MME) [schritt] {S1AP}; \\\\ + & & \node(S6A1MME) [schritt] {S6A}; & \node(S6A1HSS) [schritt] {S6A};\\ + & & \node(S6A2MME) [schritt] {S6A}; & \node(S6A2HSS) [schritt] {S6A};\\ + & \node(S1AP6ENB) [schritt] {S1AP}; & \node(S1AP6MME) [schritt] {S1AP}; \\ + \node(RRC11UE) [schritt] {RRC}; & \node(RRC11ENB) [schritt] {RRC}; \\ + \node(RRC12UE) [schritt] {RRC}; & \node(RRC12ENB) [schritt] {RRC}; \\ + & \node(S1AP7ENB) [schritt] {S1AP}; & \node(S1AP7MME) [schritt] {S1AP}; \\\\ + & & \node(S6A3MME) [schritt] {S6A}; & \node(S6A3HSS) [schritt] {S6A};\\ + & & \node(S6A4MME) [schritt] {S6A}; & \node(S6A4HSS) [schritt] {S6A};\\\\ + & & \node(S11MME1) [schritt] {S11}; & & \node(S11SPGW1) [schritt] {S11}; \\ + & & \node(S11MME2) [schritt] {S11}; & & \node(S11SPGW2) [schritt] {S11}; \\\\\\ + & \node(S1AP2ENB) [schritt] {S1AP}; & \node(S1AP2MME) [schritt] {S1AP}; \\\\ + \node(RRC5UE) [schritt] {RRC}; & \node(RRC5ENB) [schritt] {RRC}; \\ + \node(RRC6UE) [schritt] {RRC}; & \node(RRC6ENB) [schritt] {RRC}; \\ + \node(RRC13UE) [schritt] {RRC}; & \node(RRC13ENB) [schritt] {RRC}; \\ + \node(RRC14UE) [schritt] {RRC}; & \node(RRC14ENB) [schritt] {RRC}; \\ + & \node(S1AP8ENB) [schritt] {S1AP}; & \node(S1AP8MME) [schritt] {S1AP}; \\\\ + \node(RRC7UE) [schritt] {RRC}; & \node(RRC7ENB) [schritt] {RRC}; \\ + \node(RRC8UE) [schritt] {RRC}; & \node(RRC8ENB) [schritt] {RRC}; \\ + & \node(S1AP3ENB) [schritt] {S1AP}; & \node(S1AP3MME) [schritt] {S1AP}; \\\\ + \node(RRC9UE) [schritt] {RRC}; & \node(RRC9ENB) [schritt] {RRC}; \\ + & \node(S1AP4ENB) [schritt] {S1AP}; & \node(S1AP4MME) [schritt] {S1AP}; \\ + & & \node(S11MME3) [schritt] {S11}; & & \node(S11SPGW3) [schritt] {S11}; \\ + & & \node(S11MME4) [schritt] {S11}; & & \node(S11SPGW4) [schritt] {S11}; \\\\ + & \node(S1AP5ENB) [schritt] {S1AP}; & \node(S1AP5MME) [schritt] {S1AP}; \\ + \node(RRC10UE) [schritt] {RRC}; & \node(RRC10ENB) [schritt] {RRC}; \\ + \node(UELTEACTIVE)[schritt] {LTE Active}; & \node(RRCCONNECTED) [schritt] {RRC Connected}; & \node(MMELTEACTIVE) [schritt] {LTE Active}; & & \node(BEARERCREATED) [schritt] {EPC bearer active};\\ + }; + + \draw[<-] (node cs:name=RRC1UE,anchor=east) -- node(arrow1) [above, align=center]{BCCH System Information}(node cs:name=RRC1ENB,anchor=west); + \draw[->] (node cs:name=MAC1UE,anchor=east) -- node [above, align=center]{PRACH: RACH preamble}(node cs:name=MAC1ENB,anchor=west); + \draw[<-] (node cs:name=MAC2UE,anchor=east) -- node [above, align=center]{DL-SCH: RACH response}(node cs:name=MAC2ENB,anchor=west); + \draw[->] (node cs:name=RRC2UE,anchor=east) -- node(arrow2) [above, align=center]{UL-SCH: RRC Connection Request\\(Initial UE identity, Cause)}(node cs:name=RRC2ENB,anchor=west); + \draw[<-] (node cs:name=RRC3UE,anchor=east) -- node [above, align=center]{DL-SCH: RRC Connection Setup\\(SRB1 parameter)}(node cs:name=RRC3ENB,anchor=west); + \draw[->] (node cs:name=RRC4UE,anchor=east) -- node [above, align=center]{UL-SCH: RRC Connection Setup Complete\\(NAS: EMM attach request\\+ ESM PDN connectivity request)}(node cs:name=RRC4ENB,anchor=west); + \draw[->] (node cs:name=S1AP1ENB,anchor=east) -- node [above, align=center]{Initial UE message\\(NAS: EMM attach request\\+ ESM PDN connectivity request)\\eNB-UE-S1AP-ID}(node cs:name=S1AP1MME,anchor=west); + \draw[<-] (node cs:name=S1AP9ENB,anchor=east) -- node(arrow10)[above, align=center]{Downlink NAS Transport\\(NAS: Identify request)} (node cs:name=S1AP9MME,anchor=west); + \draw[<-] (node cs:name=RRC15UE,anchor=east) -- node(arrow6) [above, align=center]{DL-SCH*: DL Information Transfer\\(NAS: Identify Request)} (node cs:name=RRC15ENB,anchor=west); + \draw[->] (node cs:name=RRC16UE,anchor=east) -- node [above, align=center]{UL-SCH*: UL Information Transfer\\(NAS: Identify Response} (node cs:name=RRC16ENB,anchor=west); + \draw[->] (node cs:name=S1AP10ENB,anchor=east) -- node(arrow11)[above, align=center]{Uplink NAS Transport\\(NAS: Identify response)} (node cs:name=S1AP10MME,anchor=west); + \draw[<-] (node cs:name=S1AP2ENB,anchor=east) -- node(arrow3) [above, align=center]{Initial Context Setup Request\\(NAS: EMM attach accept\\+ ESM Activate default bearer req)\\+ Bearer params(e-RAB id, S-GW TEID)\\+ MME-UE-S1AP-ID}(node cs:name=S1AP2MME,anchor=west); + \draw[<-] (node cs:name=RRC5UE,anchor=east) -- node(arrow6) [above, align=center]{DL-SCH: Security Mode Command\\(Security Configuration)} (node cs:name=RRC5ENB,anchor=west); + \draw[->] (node cs:name=RRC6UE,anchor=east) -- node [above, align=center]{UL-SCH: Security Mode Complete}(node cs:name=RRC6ENB,anchor=west); + \draw[<-] (node cs:name=RRC7UE,anchor=east) -- node [above, align=center]{DL-SCH: RRC Connection Reconfiguration\\(Bearer Setup + NAS EMM Attach Accept\\+ ESM Activate default bearer req)}(node cs:name=RRC7ENB,anchor=west); + \draw[->] (node cs:name=RRC8UE,anchor=east) -- node [above, align=center]{UL-SCH: RRC Connection \\Reconfiguration Complete}(node cs:name=RRC8ENB,anchor=west); + \draw[->] (node cs:name=S1AP3ENB,anchor=east) -- node [above, align=center]{Initial Context Setup Response\\(eNB TEID)}(node cs:name=S1AP3MME,anchor=west); + \draw[->] (node cs:name=RRC9UE,anchor=east) -- node(arrow5) [above, align=center]{UL-SCH*: UL Information Transfer\\(NAS: EMM attach complete\\+ ESM Activate default bearer resp)}(node cs:name=RRC9ENB,anchor=west); + \draw[->] (node cs:name=S1AP4ENB,anchor=east) -- node [above, align=center]{Uplink NAS Transport + NAS\\+ (S1-U eNB TEID)}(node cs:name=S1AP4MME,anchor=west); + \draw[dashed, draw=red, ->] (node cs:name=S11MME1,anchor=east) -- node(arrow4)[above, align=center]{Create Session Request\\(EBI, APN, Mobile IP address\\AMBR, CSGI)}(node cs:name=S11SPGW1,anchor=west); + \draw[dashed, draw=red,<-] (node cs:name=S11MME2,anchor=east) -- node[above, align=center]{Create Session Response\\(S-GW TEID)}(node cs:name=S11SPGW2,anchor=west); + \draw[dashed, draw=red,->] (node cs:name=S11MME3,anchor=east) -- node[above, align=center]{Modify Bearer Request\\(S1-U eNB TEID)}(node cs:name=S11SPGW3,anchor=west); + \draw[dashed, draw=red,<-] (node cs:name=S11MME4,anchor=east) -- node[above, align=center]{Modify Bearer Response}(node cs:name=S11SPGW4,anchor=west); + \draw[<-] (node cs:name=RRC10UE,anchor=east) -- node [above, align=center]{DL-SCH*: DL Information Transfer\\+ NAS: EMM Information}(node cs:name=RRC10ENB,anchor=west); + \draw[<-] (node cs:name=S1AP5ENB,anchor=east) -- node [above, align=center]{Downlink NAS Transport\\+ NAS: EMM Information}(node cs:name=S1AP5MME,anchor=west); + \draw[<-] (node cs:name=RRC11UE,anchor=east) -- node [above, align=center]{DL-SCH*: DL Information Transfer\\+ NAS: Authentication Request}(node cs:name=RRC11ENB,anchor=west); + \draw[->] (node cs:name=RRC12UE,anchor=east) -- node [above, align=center]{UL-SCH*: UL Information Transfer\\+ NAS: Authentication Response}(node cs:name=RRC12ENB,anchor=west); + \draw[<-] (node cs:name=S1AP6ENB,anchor=east) -- node(arrow7) [above, align=center]{Downlink NAS Transport\\+ NAS: Authentication Request}(node cs:name=S1AP6MME,anchor=west); + \draw[->] (node cs:name=S1AP7ENB,anchor=east) -- node [above, align=center]{Uplink NAS Transport\\+ NAS: Authentication Response}(node cs:name=S1AP7MME,anchor=west); + \draw[<-] (node cs:name=RRC13UE,anchor=east) -- node [above, align=center]{DL-SCH: UE Capability Enquiry}(node cs:name=RRC13ENB,anchor=west); + \draw[->] (node cs:name=RRC14UE,anchor=east) -- node [above, align=center]{UL-SCH: UE Capability Information}(node cs:name=RRC14ENB,anchor=west); + \draw[->] (node cs:name=S1AP8ENB,anchor=east) -- node [above, align=center]{UE Capability Info Indication}(node cs:name=S1AP8MME,anchor=west); + \draw[<-] (node cs:name=S6A4MME,anchor=east) -- node [above, align=center]{Update Location Answer\\(APN, QCI, MSISDN, AMBR\\Mobile IP address)}(node cs:name=S6A4HSS,anchor=west); + \draw[->] (node cs:name=S6A3MME,anchor=east) -- node(arrow9) [above, align=center]{Update Location Request\\(IMSI, PLMN)}(node cs:name=S6A3HSS,anchor=west); + \draw[->] (node cs:name=S6A1MME,anchor=east) -- node(arrow8) [above, align=center]{Authentication Info Request\\(IMSI)}(node cs:name=S6A1HSS,anchor=west); + \draw[<-] (node cs:name=S6A2MME,anchor=east) -- node [above, align=center]{Authentication Info Answer\\(E-UTRAN vector:\\RAND, XRES, AUTN, KASME)}(node cs:name=S6A2HSS,anchor=west); + \label{as1}; + + \path[-] + (UE) edge (RRC1UE) + (RRC1UE) edge (MAC1UE) + (MAC1UE) edge (MAC2UE) + (MAC2UE) edge (RRC2UE) + (RRC2UE) edge (RRC3UE) + (RRC3UE) edge (RRC4UE) + (RRC4UE) edge (RRC15UE) + (RRC15UE) edge (RRC16UE) + (RRC16UE) edge (RRC11UE) + (RRC11UE) edge (RRC12UE) + (RRC12UE) edge (RRC5UE) + (RRC5UE) edge (RRC6UE) + (RRC6UE) edge (RRC13UE) + (RRC13UE) edge (RRC14UE) + (RRC14UE) edge (RRC7UE) + (RRC7UE) edge (RRC8UE) + (RRC8UE) edge (RRC9UE) + (RRC9UE) edge (RRC10UE) + (RRC10UE) edge (UELTEACTIVE) + + (ENB) edge (RRC1ENB) + (RRC1ENB) edge (MAC1ENB) + (MAC1ENB) edge (MAC2ENB) + (MAC2ENB) edge (RRC2ENB) + (RRC2ENB) edge (RRC3ENB) + (RRC3ENB) edge (RRC4ENB) + (RRC4ENB) edge (S1AP1ENB) + (S1AP1ENB) edge (S1AP9ENB) + (S1AP9ENB) edge (RRC15ENB) + (RRC15ENB) edge (RRC16ENB) + (RRC16ENB) edge (S1AP10ENB) + (S1AP10ENB) edge (S1AP6ENB) + (S1AP6ENB) edge (RRC11ENB) + (RRC11ENB) edge (RRC12ENB) + (RRC12ENB) edge (S1AP7ENB) + (S1AP7ENB) edge (S1AP2ENB) + (S1AP2ENB) edge (RRC5ENB) + (RRC5ENB) edge (RRC6ENB) + (RRC6ENB) edge (RRC13ENB) + (RRC13ENB) edge (RRC14ENB) + (RRC14ENB) edge (S1AP8ENB) + (S1AP8ENB) edge (RRC7ENB) + (RRC7ENB) edge (RRC8ENB) + (RRC8ENB) edge (S1AP3ENB) + (S1AP3ENB) edge (RRC9ENB) + (RRC9ENB) edge (S1AP4ENB) + (S1AP4ENB) edge (S1AP5ENB) + (S1AP5ENB) edge (RRC10ENB) + (RRC10ENB) edge (RRCCONNECTED) + + (MME) edge (S1AP1MME) + (S1AP1MME) edge (S1AP9MME) + (S1AP9MME) edge (S1AP10MME) + (S1AP10MME) edge (S6A1MME) + (S6A1MME) edge (S6A2MME) + (S6A2MME) edge (S1AP6MME) + (S1AP6MME) edge (S1AP7MME) + (S1AP7MME) edge (S6A3MME) + (S6A3MME) edge (S6A4MME) + (S6A4MME) edge (S11MME1) + (S11MME1) edge (S11MME2) + (S11MME2) edge (S1AP2MME) + (S1AP2MME) edge (S1AP8MME) + (S1AP8MME) edge (S1AP3MME) + (S1AP3MME) edge (S1AP4MME) + (S1AP4MME) edge (S11MME3) + (S11MME3) edge (S11MME4) + (S11MME4) edge (S1AP5MME) + (S1AP5MME) edge (MMELTEACTIVE) + + (SPGW) edge (S11SPGW1) + (S11SPGW1) edge (S11SPGW2) + (S11SPGW2) edge (S11SPGW3) + (S11SPGW3) edge (S11SPGW4) + (S11SPGW4) edge (BEARERCREATED) + + (HSS) edge (S6A1HSS) + (S6A1HSS) edge (S6A2HSS) + (S6A2HSS) edge (S6A3HSS) + (S6A3HSS) edge (S6A4HSS) + ; + + \begin{pgfonlayer}{background} + \path [use as bounding box] (current bounding box.north west) (current bounding box.south east); % Freeze current bounding box + \node [fit={\extendnode{RRC1UE} (arrow1)(MAC2ENB)}, background] { + \begin{minipage}[b][0cm]{5cm} + \hfill Random Access + \end{minipage} + }; + \node [fit={\extendnode{S1AP9ENB} (arrow10)(RRC15UE)(S1AP10MME)}, background] { + \begin{minipage}[b][0cm]{5cm} + \hfill Identification Procedure (Used when the UE is connecting for the first time and has no valid GUTI) + \end{minipage} + }; + \node [fit={\extendnode{S1AP6MME}(arrow8)(S1AP7MME)}, background] { + \begin{minipage}[b][0cm]{5cm} + \hfill Authentication procedure + \end{minipage} + }; + \node [fit={\extendnode{RRC2UE} (arrow2)(RRC4UE)}, background] { + \begin{minipage}[b][0cm]{5cm} + \hfill RRC Connection Establishment + \end{minipage} + }; + \node [fit={\extendnode{S1AP2ENB} (arrow3)(S1AP3MME)}, background] { + \begin{minipage}[b][0cm]{5cm} + \hfill Initial Context Setup + \end{minipage} + }; + \node [fit={\extendnode{S11MME1} (arrow9)(arrow4)(S11SPGW2)}, background] { + \begin{minipage}[b][0cm]{6cm} + \hfill EPC Bearer Creation (S11 abstraction) + \end{minipage} + }; + \node [fit={\extendnode{RRC9ENB} (arrow5)(S11SPGW4)}, background] { + \begin{minipage}[b][0cm]{6cm} + \hfill Default EPS bearer activation + \end{minipage} + }; + \end{pgfonlayer} + \begin{pgfonlayer}{background} + \node [fit={(RRC5UE)(arrow6)(RRC6ENB)}, backgroundopt] { + + }; + \end{pgfonlayer} + \end{tikzpicture} + \caption{Control Plane Initial Attach Procedure + Default Bearer Creation} \label{fig:Control Plane Default Bearer Creation} + \begin{tikzpicture} + \node[backgroundopt, + minimum width=5mm,minimum height=5mm,anchor=east](l1) at (0,1){}; + \node[right=0.5cm of l1.center](ct1) at (0,1){Optional procedure}; + \node[below=0.5cm of l1](l2) {*}; + \node[right=0.5cm of l2](ct2) {Sent on SRB1 if SRB2 is not established yet}; + \draw[minimum width=5mm,minimum height=5mm,below=0.3cm of l2,->,dashed, draw=red] + ($(l2.south west) - (0,0.55cm)$) -- node(l3){} ($(l2.south east) - (0,0.55cm)$); + \node[right=0.5cm of l3.north east](ct3) {Abstraction link}; + \node[draw,fit=(ct1)(l1)(ct2)(l2)(ct3)(l3)] {}; +% \node[below = 0.5cm of l2](l3) {}; +% \draw[below=0.5cm of l2, ->] (1,1) -- (0,1); + \end{tikzpicture} +\end{figure} +\end{center} + +\begin{landscape} +\begin{figure} +\begin{center} + \begin{tikzpicture}[auto] + \tikzstyle{every node}=[font=\footnotesize] + \matrix (matrix2) [row sep=0.7cm, column sep={8.3cm,between origins}, matrix of nodes] { + \node(SCTP) [schritt] {SCTP}; & \node(S1AP) [schritt] {S1AP}; & \node(NAS) [schritt] {NAS}; & \node(MMEAPP) [schritt] {MME APP}; & \node(S6A) [schritt] {S6A}; & \node(SPAPP) [schritt] {S+P-GW APP};\\\\ + \node(SCTP1) [] {}; & \node(S1AP1) [] {};\\ + & \node(S1AP2) [] {}; & \node(NAS1) [] {};\\ + & & \node(NAS2) [] {}; & \node(MMEAPP1) [] {};\\ + & & & \node(MMEAPP2) [] {}; & \node(S6A1) [] {};\\\\ + & & & \node(MMEAPP3) [] {}; & \node(S6A2) [] {};\\ + & & \node(NAS3) [] {}; & \node(MMEAPP4) [] {};\\ + & \node(S1AP3) [] {}; & \node(NAS4) [] {};\\ + \node(SCTP2) [] {}; & \node(S1AP4) [] {};\\\\ + \node(SCTP3) [] {}; & \node(S1AP5) [] {};\\ + & \node(S1AP6) [] {}; & \node(NAS5) [] {};\\ + & & \node(NAS6) [] {}; & \node(MMEAPP5) [] {};\\ + & & & \node(MMEAPP6) [] {}; & \node(S6A3) [] {};\\\\\\\\ + & & & \node(MMEAPP7) [] {}; & \node(S6A4) [] {};\\\\\\ + & & & \node(MMEAPP8) [] {}; & & \node(SPAPP1) [] {};\\\\ + & & & \node(MMEAPP9) [] {}; & & \node(SPAPP2) [] {};\\ + & & \node(NAS7) [] {}; & \node(MMEAPP10) [] {};\\ + & \node(S1AP7) [] {}; & \node(NAS8) [] {};\\ + \node(SCTP4) [] {}; & \node(S1AP8) [] {};\\\\ + \node(SCTP5) [] {}; & \node(S1AP9) [] {};\\ + & \node(S1AP10) [] {}; & & \node(MMEAPP11) [] {};\\ + \node(SCTP6) [] {}; & \node(S1AP11) [] {};\\ + & \node(S1AP12) [] {}; & \node(NAS9) [] {};\\ + & & \node(NAS10) [] {}; & \node(MMEAPP12) [] {};\\ + & & & \node(MMEAPP13) [] {}; & & \node(SPAPP3) [] {};\\\\ + & & & \node(MMEAPP14) [] {}; & & \node(SPAPP4) [] {};\\ + \node(SCTPEND) [] {}; & \node(S1APEND) [] {}; & \node(NASEND) [] {}; & \node(MMEAPPEND) [] {}; & \node(S6AEND) [] {}; & \node(SPAPPEND) [] {};\\ + }; + + \path[-] + (SCTP) edge (SCTPEND) + (S1AP) edge (S1APEND) + (NAS) edge (NASEND) + (MMEAPP) edge (MMEAPPEND) + (S6A) edge (S6A4) + (SPAPP) edge (SPAPPEND) + ; + + \draw[->] (node cs:name=SCTP1,anchor=center) -- node(arrow1)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP1,anchor=center); + \draw[->] (node cs:name=S1AP2,anchor=center) -- node(arrow2)[above, align=center]{ + \commandname{Initial UE message} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU, TAI} + \\\soneapcolor{RRC Establishment Cause, E-UTRAN CGI, Current time} + \\\soneapcolor{\emph{S-TMSI, CSG Id, GUMMEI, Cell Access Mode},} + \\\soneapcolor{\emph{GW Transport Layer Address, Relay Node Indicator}}}(node cs:name=NAS1,anchor=center); + \draw[->] (node cs:name=NAS2,anchor=center) -- node(arrow3)[above, align=center]{ + \commandname{Attach Request} + \\\nascolor{Default APN: NULL, UE network cap,} + \\\nascolor{EPS attach type, KSI, \emph{GUTI, IMEI}, IMSI} + \\\nascolor{Request type: Initial, PDN Type}}(node cs:name=MMEAPP1,anchor=center); + \draw[->] (node cs:name=MMEAPP2,anchor=center) -- node(arrow4)[above, align=center]{ + \commandname{Authentication Information Request} + \\\soneapcolor{PLMN Id, }\nascolor{IMSI,} + \\\ssixcolor{Destination Host, Destination Realm} + \\\mmecolor{\emph{Supported Features}, Number of vectors=1, } + \\\mmecolor{Immediate Response}}(node cs:name=S6A1,anchor=center); + \draw[->] (node cs:name=S6A2,anchor=center) -- node(arrow5)[above, align=center]{ + \commandname{Authentication Information Answer} + \\\ssixcolor{Result Code, \emph{Supported Features}} + \\\ssixcolor{E-UTRAN Vector: RAND, XRES, AUTN, KASME}}(node cs:name=MMEAPP3,anchor=center); + \draw[->] (node cs:name=MMEAPP4,anchor=center) -- node(arrow6)[above, align=center]{ + \commandname{Authentication Request}}(node cs:name=NAS3,anchor=center); + \draw[->] (node cs:name=NAS4,anchor=center) -- node(arrow7)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP3,anchor=center); + \draw[->] (node cs:name=S1AP4,anchor=center) -- node(arrow8)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length}}(node cs:name=SCTP2,anchor=center); + \draw[->] (node cs:name=SCTP3,anchor=center) -- node(arrow9)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP5,anchor=center); + \draw[->] (node cs:name=S1AP6,anchor=center) -- node(arrow10)[above, align=center]{ + \commandname{Uplink NAS Transport} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{NAS PDU, E-CGI, TAI}}(node cs:name=NAS5,anchor=center); + \draw[->] (node cs:name=NAS6,anchor=center) -- node(arrow11)[above, align=center]{ + \commandname{Authentication Response}}(node cs:name=MMEAPP5,anchor=center); + \draw[->] (node cs:name=MMEAPP6,anchor=center) -- node(arrow12)[above, align=center]{ + \commandname{Update Location Request} + \\\nascolor{IMSI, Initial Attach, RAT Type, UE SRVCC Capability} + \\\nascolor{Terminal Information: IMEISV} + \\\soneapcolor{PLMN Id} + \\\ssixcolor{\emph{Supported Features}} + \\\mmecolor{S6A flag, Don't skip subscriber data}}(node cs:name=S6A3,anchor=center); + \draw[->] (node cs:name=S6A4,anchor=center) -- node(arrow13)[above, align=center]{ + \commandname{Update Location Answer} + \\\ssixcolor{Result Code = DIAMETER\_SUCCESS, Subscription Data:} + \\\mmecolor{\{ Subscriber Status, Network Access Mode, RAU TAU timer} + \\\spappcolor{AMBR, MSISDN, APN Configuration Profile} + \\\spappcolor{[Default-APN Id, APN-Configuration$<$1:n$>$(UE IP$<$0:2$>$,} + \\\spappcolor{Service Selection, QOS profile, APN-AMBR,} + \\\spappcolor{PDN GW address)]\}}}(node cs:name=MMEAPP7,anchor=center); + \draw[->] (node cs:name=MMEAPP8,anchor=center) -- node(arrow14)[above, align=center]{ + \commandname{Create Session Request} + \\\nascolor{IMSI, RAT Type, Initial Attach, UE time zone} + \\\soneapcolor{ECGI, TAI, CSG Id} + \\\ssixcolor{APN, PDN type, Selection Mode, PAA, APN-AMBR} + \\\mmecolor{Bearer to create$<$1$>$: EBI, QOS, S-GW F-TEID, TFT}}(node cs:name=SPAPP1,anchor=center); + \draw[->] (node cs:name=SPAPP2,anchor=center) -- node(arrow15)[above, align=center]{ + \commandname{Create Session Response} + \\\mmecolor{Bearer Creation Result} + \\\nascolor{PAA, APN-AMBR, QoS, TFT, EBI} + \\\soneapcolor{S1-U S-GW TEID, S-GW Address}}(node cs:name=MMEAPP9,anchor=center); + \draw[->] (node cs:name=MMEAPP10,anchor=center) -- node(arrow16)[above, align=center]{ + \commandname{Attach Accepted + Default Bearer}}(node cs:name=NAS7,anchor=center); + \draw[->] (node cs:name=NAS8,anchor=center) -- node(arrow17)[above, align=center]{ + \commandname{Initial Context Setup Request} + \\\nascolor{NAS PDU, eNB UE S1AP ID, MME UE S1AP ID} + \\\ssixcolor{AMBR, APN-AMBR, QoS, S-GW Address, } + \\\ssixcolor{S1-U S-GW TEID, KeNB} + \\\ssixcolor{security cap (encryption/integrity)}}(node cs:name=S1AP7,anchor=center); + \draw[->] (node cs:name=S1AP8,anchor=center) -- node(arrow18)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length} + \\\soneapcolor{S1-MME eNB IP address}}(node cs:name=SCTP4,anchor=center); + \draw[->] (node cs:name=SCTP5,anchor=center) -- node(arrow19)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP9,anchor=center); + \draw[->] (node cs:name=S1AP10,anchor=center) -- node(arrow20)[above, align=center]{ + \commandname{UE Capability Indication} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{UE Radio Capability}}(node cs:name=MMEAPP11,anchor=center); + \draw[->] (node cs:name=SCTP6,anchor=center) -- node(arrow21)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP11,anchor=center); + \draw[->] (node cs:name=S1AP12,anchor=center) -- node(arrow22)[above, align=center]{ + \commandname{Initial Context Setup Response} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{E-RAB: ID, Tranport Address, GTP-TEID}}(node cs:name=NAS9,anchor=center); + \draw[->] (node cs:name=NAS10,anchor=center) -- node(arrow23)[above, align=center]{ + \commandname{Attach Complete} + \\\nascolor{Default Bearer Creation Result(UE side)}}(node cs:name=MMEAPP12,anchor=center); + \draw[->] (node cs:name=MMEAPP13,anchor=center) -- node(arrow24)[above, align=center]{ + \commandname{Modify Bearer Request} + \\\nascolor{EBI,} + \\\soneapcolor{S1-U eNB (TEID + Address)}}(node cs:name=SPAPP3,anchor=center); + \draw[->] (node cs:name=SPAPP4,anchor=center) -- node(arrow25)[above, align=center]{ + \commandname{Modify Bearer Response} + \\\spappcolor{Result} + \\\mmecolor{EBI, Cause, S1 SGW F-TEID}}(node cs:name=MMEAPP14,anchor=center); + + \node[above=3mm of arrow4, backgroundcomment] (opt1) {Used only when UE context is not known in MME}; + \begin{pgfonlayer}{background} + \node[fit=(arrow4)(arrow5)(opt1), backgroundopt] {}; + \end{pgfonlayer} + \node[right=of arrow12, backgroundcomment, text width=6cm] {Skip subscriber data flag set when MME already knows UE APN Configuration}; + + \node(opt2) at ($(arrow6)!0.5!(arrow11)$) [backgroundcomment, text width=6cm] {This procedure should be initiated only when UE is not authenticated or for an initial attach}; + \begin{pgfonlayer}{background} + \node[fit=(arrow6)(arrow9)(arrow8)(arrow11)(opt2), backgroundopt] {}; + \end{pgfonlayer} + + \end{tikzpicture} + \end{center} + \caption{MME detailed behaviour: Default Bearer Creation} \label{fig:MME detailed behaviour} + \begin{tikzpicture} + \matrix (matrix3) [square matrix] { + \node[](l1) {\mmecolor{MME}}; & \node[](ct1) {MME application or default MME parameter};\\ + \node[](l2) {\soneapcolor{S1AP}}; & \node[](ct2) {S1AP provided parameter};\\ + \node[](l3) {\nascolor{NAS}}; & \node[](ct3) {NAS provided parameter};\\ + \node[](l4) {\ssixcolor{S6A}}; & \node[](ct4) {HSS provided parameter};\\ + \node[](l5) {\spappcolor{S11}}; & \node[](ct5) {S+P-GW provided parameter};\\ + \node[](l6) {\sctpcolor{SCTP}}; & \node[](ct6) {SCTP provided parameter};\\ + \node[](l7) {\emph{Optional}}; & \node[](ct7) {Optional parameter};\\ + }; + +% \node[draw,fit=(ct1)(l1)(ct2)(l2)(ct3)(l3)(l4)(ct4)(l5)(ct5)] {}; + % \node[below = 0.5cm of l2](l3) {}; + % \draw[below=0.5cm of l2, ->] (1,1) -- (0,1); + \end{tikzpicture} + \end{figure} + \end{landscape} + + \begin{landscape} + \begin{figure} + \begin{center} + \begin{tikzpicture} + \tikzstyle{every node}=[font=\footnotesize] + \matrix (matrix3) [row sep=0.7cm, column sep={8cm,between origins}, matrix of nodes] { + \node(SCTP) [schritt] {SCTP}; & \node(S1AP) [schritt] {S1AP}; & \node(NAS) [schritt] {NAS}; & \node(MMEAPP) [schritt] {MME APP}; & \node(S6A) [schritt] {S6A}; & \node(SPAPP) [schritt] {S+P-GW APP};\\\\ + \node(SCTP1) [] {}; & \node(S1AP1) [] {};\\ + & \node(S1AP2) [] {}; & \node(NAS1) [] {};\\ + & & \node(NAS2) [] {}; & \node(MMEAPP1) [] {};\\ + & & & \node(MMEAPP2) [] {}; & \node(S6A1) [] {};\\\\ + & & & \node(MMEAPP3) [] {}; & \node(S6A2) [] {};\\ + & & \node(NAS3) [] {}; & \node(MMEAPP4) [] {};\\ + & \node(S1AP3) [] {}; & \node(NAS4) [] {};\\ + \node(SCTP2) [] {}; & \node(S1AP4) [] {};\\ + \node(SCTPEND) [] {}; & \node(S1APEND) [] {}; & \node(NASEND) [] {}; & \node(MMEAPPEND) [] {}; & \node(S6AEND) [] {}; & \node(SPAPPEND) [] {};\\ + }; + + \path[-] + (SCTP) edge (SCTPEND) + (S1AP) edge (S1APEND) + (NAS) edge (NASEND) + (MMEAPP) edge (MMEAPPEND) + (S6A) edge (S6AEND) + (SPAPP) edge (SPAPPEND) + ; + + \draw[->] (node cs:name=SCTP1,anchor=center) -- node(arrow1)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP1,anchor=center); + \draw[->] (node cs:name=S1AP2,anchor=center) -- node(arrow2)[above, align=center]{ + \commandname{Initial UE message} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU, TAI} + \\\soneapcolor{RRC Establishment Cause, E-UTRAN CGI, Current time} + \\\soneapcolor{\emph{S-TMSI, CSG Id, GUMMEI, Cell Access Mode},} + \\\soneapcolor{\emph{GW Transport Layer Address, Relay Node Indicator}}}(node cs:name=NAS1,anchor=center); + \draw[->] (node cs:name=NAS2,anchor=center) -- node(arrow3)[above, align=center]{ + \commandname{Attach Request} + \\\nascolor{Default APN: NULL, UE network cap,} + \\\nascolor{EPS attach type, KSI, \emph{GUTI, IMEI}, IMSI} + \\\nascolor{Request type: Initial, PDN Type}}(node cs:name=MMEAPP1,anchor=center); + \draw[->] (node cs:name=MMEAPP2,anchor=center) -- node(arrow4)[above, align=center]{ + \commandname{Authentication Information Request} + \\\soneapcolor{PLMN Id, }\nascolor{IMSI,} + \\\ssixcolor{Destination Host, Destination Realm} + \\\mmecolor{\emph{Supported Features}, Number of vectors=1, } + \\\mmecolor{Immediate Response}}(node cs:name=S6A1,anchor=center); + \draw[->] (node cs:name=S6A2,anchor=center) -- node(arrow5)[above, align=center]{ + \commandname{Authentication Information Answer} + \\\ssixcolor{Result Code $\neq$ DIAMETER\_SUCCESS}} + (node cs:name=MMEAPP3,anchor=center); + \draw[->] (node cs:name=MMEAPP4,anchor=center) -- node(arrow6)[above, align=center]{ + \commandname{Failure Indication} + \\\mmecolor{Diameter to NAS mapped cause value} + \\\mmecolor{(See 3GPP TS 29.272 Table A.1)}} + (node cs:name=NAS3,anchor=center); + \draw[->] (node cs:name=NAS4,anchor=center) -- node(arrow7)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}} + (node cs:name=S1AP3,anchor=center); + \draw[->] (node cs:name=S1AP4,anchor=center) -- node(arrow8)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length}} + (node cs:name=SCTP2,anchor=center); + \end{tikzpicture} + \end{center} + \caption{MME detailed behaviour: Default Bearer Rejected (S6A Authentication Failure)} \label{fig:MME detailed behaviour: Default Bearer Rejected (S6A Failure)} + + \begin{center} + \begin{tikzpicture} + \tikzstyle{every node}=[font=\footnotesize] + \matrix (matrix4) [row sep=0.7cm, column sep={8cm,between origins}, matrix of nodes] { + \node(SCTP) [schritt] {SCTP}; & \node(S1AP) [schritt] {S1AP}; & \node(NAS) [schritt] {NAS}; & \node(MMEAPP) [schritt] {MME APP}; & \node(S6A) [schritt] {S6A}; & \node(SPAPP) [schritt] {S+P-GW APP};\\\\ + \node(SCTP1) [] {}; & \node(S1AP1) [] {};\\ + & \node(S1AP2) [] {}; & \node(NAS1) [] {};\\ + & & \node(NAS2) [] {}; & \node(MMEAPP1) [] {};\\ + & & & \node(MMEAPP2) [] {}; & \node(S6A1) [] {};\\\\ + & & & \node(MMEAPP3) [] {}; & \node(S6A2) [] {};\\ + & & \node(NAS3) [] {}; & \node(MMEAPP4) [] {};\\ + & \node(S1AP3) [] {}; & \node(NAS4) [] {};\\ + \node(SCTP2) [] {}; & \node(S1AP4) [] {};\\\\ + \node(SCTP3) [] {}; & \node(S1AP5) [] {};\\ + & \node(S1AP6) [] {}; & \node(NAS5) [] {};\\ + & & \node(NAS6) [] {}; & \node(MMEAPP5) [] {};\\ + & & & \node(MMEAPP6) [] {}; & \node(S6A3) [] {};\\\\ + & & & \node(MMEAPP7) [] {}; & \node(S6A4) [] {};\\ + & & \node(NAS7) [] {}; & \node(MMEAPP10) [] {};\\ + & \node(S1AP7) [] {}; & \node(NAS8) [] {};\\ + \node(SCTP4) [] {}; & \node(S1AP8) [] {};\\ + \node(SCTPEND) [] {}; & \node(S1APEND) [] {}; & \node(NASEND) [] {}; & \node(MMEAPPEND) [] {}; & \node(S6AEND) [] {}; & \node(SPAPPEND) [] {};\\ + }; + + \path[-] + (SCTP) edge (SCTPEND) + (S1AP) edge (S1APEND) + (NAS) edge (NASEND) + (MMEAPP) edge (MMEAPPEND) + (S6A) edge (S6A4) + (SPAPP) edge (SPAPPEND) + ; + + \draw[->] (node cs:name=SCTP1,anchor=center) -- node(arrow1)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP1,anchor=center); + \draw[->] (node cs:name=S1AP2,anchor=center) -- node(arrow2)[above, align=center]{ + \commandname{Initial UE message} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU, TAI} + \\\soneapcolor{RRC Establishment Cause, E-UTRAN CGI, Current time } + \\\soneapcolor{\emph{S-TMSI, CSG Id, GUMMEI, Cell Access Mode},} + \\\soneapcolor{\emph{GW Transport Layer Address, Relay Node Indicator}}}(node cs:name=NAS1,anchor=center); + \draw[->] (node cs:name=NAS2,anchor=center) -- node(arrow3)[above, align=center]{ + \commandname{Attach Request} + \\\nascolor{Default APN: NULL, UE network cap,} + \\\nascolor{EPS attach type, KSI, \emph{GUTI, IMEI}, IMSI} + \\\nascolor{Request type: Initial, PDN Type}}(node cs:name=MMEAPP1,anchor=center); + \draw[->] (node cs:name=MMEAPP2,anchor=center) -- node(arrow4)[above, align=center]{ + \commandname{Authentication Information Request} + \\\soneapcolor{PLMN Id, }\nascolor{IMSI,} + \\\ssixcolor{Destination Host, Destination Realm} + \\\mmecolor{\emph{Supported Features}, Number of vectors=1, } + \\\mmecolor{Immediate Response}}(node cs:name=S6A1,anchor=center); + \draw[->] (node cs:name=S6A2,anchor=center) -- node(arrow5)[above, align=center]{ + \commandname{Authentication Information Answer} + \\\ssixcolor{Result Code, \emph{Supported Features}} + \\\ssixcolor{E-UTRAN Vector: RAND, XRES, AUTN, KASME}}(node cs:name=MMEAPP3,anchor=center); + \draw[->] (node cs:name=MMEAPP4,anchor=center) -- node(arrow6)[above, align=center]{ + \commandname{Authentication Request}}(node cs:name=NAS3,anchor=center); + \draw[->] (node cs:name=NAS4,anchor=center) -- node(arrow7)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP3,anchor=center); + \draw[->] (node cs:name=S1AP4,anchor=center) -- node(arrow8)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length}}(node cs:name=SCTP2,anchor=center); + \draw[->] (node cs:name=SCTP3,anchor=center) -- node(arrow9)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP5,anchor=center); + \draw[->] (node cs:name=S1AP6,anchor=center) -- node(arrow10)[above, align=center]{ + \commandname{Uplink NAS Transport} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{NAS PDU, E-CGI, TAI}}(node cs:name=NAS5,anchor=center); + \draw[->] (node cs:name=NAS6,anchor=center) -- node(arrow11)[above, align=center]{ + \commandname{Authentication Response}}(node cs:name=MMEAPP5,anchor=center); + \draw[->] (node cs:name=MMEAPP6,anchor=center) -- node(arrow12)[above, align=center]{ + \commandname{Update Location Request} + \\\nascolor{IMSI, Initial Attach, RAT Type, UE SRVCC Capability} + \\\nascolor{Terminal Information: IMEISV} + \\\soneapcolor{PLMN Id} + \\\ssixcolor{\emph{Supported Features}, Destination Host/Realm} + \\\mmecolor{S6A flag, Don't skip subscriber data}}(node cs:name=S6A3,anchor=center); + \draw[->] (node cs:name=S6A4,anchor=center) -- node(arrow13)[above, align=center]{ + \commandname{Update Location Answer} + \\\ssixcolor{Result Code $\neq$ DIAMETER\_SUCCESS}}(node cs:name=MMEAPP7,anchor=center); + \draw[->] (node cs:name=MMEAPP10,anchor=center) -- node(arrow16)[above, align=center]{ + \commandname{Failure Indication} + \\\mmecolor{Diameter to NAS mapped cause value} + \\\mmecolor{(See 3GPP TS 29.272 Table A.1)}}(node cs:name=NAS7,anchor=center); + \draw[->] (node cs:name=NAS8,anchor=center) -- node(arrow17)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP7,anchor=center); + \draw[->] (node cs:name=S1AP8,anchor=center) -- node(arrow18)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length} + \\\soneapcolor{S1-MME eNB IP address}}(node cs:name=SCTP4,anchor=center); + + \end{tikzpicture} + \end{center} + \caption{MME detailed behaviour: Default Bearer Rejected (S6A Update Location Failure)} \label{fig:MME detailed behaviour: Default Bearer Rejected (S6A Update Location Failure)} + \end{figure} +\end{landscape} + +\begin{landscape} +\begin{figure} + \begin{center} + \begin{tikzpicture} + \tikzstyle{every node}=[font=\footnotesize] + \matrix (matrix5) [row sep=0.7cm, column sep={9cm,between origins}, matrix of nodes] { + \node(SCTP) [schritt] {SCTP}; & \node(S1AP) [schritt] {S1AP}; & \node(NAS) [schritt] {NAS}; & \node(MMEAPP) [schritt] {MME APP}; & \node(S6A) [schritt] {S6A}; & \node(SPAPP) [schritt] {S+P-GW APP};\\\\ + \node(SCTP1) [] {}; & \node(S1AP1) [] {};\\ + & \node(S1AP2) [] {}; & \node(NAS1) [] {};\\ + & & \node(NAS2) [] {}; & \node(MMEAPP1) [] {};\\ + & & & \node(MMEAPP2) [] {}; & \node(S6A1) [] {};\\\\ + & & & \node(MMEAPP3) [] {}; & \node(S6A2) [] {};\\ + & & \node(NAS3) [] {}; & \node(MMEAPP4) [] {};\\ + & \node(S1AP3) [] {}; & \node(NAS4) [] {};\\ + \node(SCTP2) [] {}; & \node(S1AP4) [] {};\\\\ + \node(SCTP3) [] {}; & \node(S1AP5) [] {};\\ + & \node(S1AP6) [] {}; & \node(NAS5) [] {};\\ + & & \node(NAS6) [] {}; & \node(MMEAPP5) [] {};\\ + & & & \node(MMEAPP6) [] {}; & \node(S6A3) [] {};\\\\\\\\ + & & & \node(MMEAPP7) [] {}; & \node(S6A4) [] {};\\\\\\ + & & & \node(MMEAPP8) [] {}; & & \node(SPAPP1) [] {};\\\\ + & & & \node(MMEAPP9) [] {}; & & \node(SPAPP2) [] {};\\ + & & \node(NAS7) [] {}; & \node(MMEAPP10) [] {};\\ + & \node(S1AP7) [] {}; & \node(NAS8) [] {};\\ + \node(SCTP4) [] {}; & \node(S1AP8) [] {};\\\\ + \node(SCTPEND) [] {}; & \node(S1APEND) [] {}; & \node(NASEND) [] {}; & \node(MMEAPPEND) [] {}; & \node(S6AEND) [] {}; & \node(SPAPPEND) [] {};\\ + }; + + \path[-] + (SCTP) edge (SCTPEND) + (S1AP) edge (S1APEND) + (NAS) edge (NASEND) + (MMEAPP) edge (MMEAPPEND) + (S6A) edge (S6A4) + (SPAPP) edge (SPAPPEND) + ; + + \draw[->] (node cs:name=SCTP1,anchor=center) -- node(arrow1)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP1,anchor=center); + \draw[->] (node cs:name=S1AP2,anchor=center) -- node(arrow2)[above, align=center]{ + \commandname{Initial UE message} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU, TAI} + \\\soneapcolor{RRC Establishment Cause, E-UTRAN CGI, Current time,} + \\\soneapcolor{\emph{S-TMSI, CSG Id, GUMMEI, Cell Access Mode},} + \\\soneapcolor{\emph{GW Transport Layer Address, Relay Node Indicator}}}(node cs:name=NAS1,anchor=center); + \draw[->] (node cs:name=NAS2,anchor=center) -- node(arrow3)[above, align=center]{ + \commandname{Attach Request} + \\\nascolor{Default APN: NULL, UE network cap,} + \\\nascolor{EPS attach type, KSI, \emph{GUTI, IMEI}, IMSI} + \\\nascolor{Request type: Initial, PDN Type}}(node cs:name=MMEAPP1,anchor=center); + \draw[->] (node cs:name=MMEAPP2,anchor=center) -- node(arrow4)[above, align=center]{ + \commandname{Authentication Information Request} + \\\soneapcolor{PLMN Id, }\nascolor{IMSI,} + \\\ssixcolor{Destination Host, Destination Realm} + \\\mmecolor{\emph{Supported Features}, Number of vectors=1, } + \\\mmecolor{Immediate Response}}(node cs:name=S6A1,anchor=center); + \draw[->] (node cs:name=S6A2,anchor=center) -- node(arrow5)[above, align=center]{ + \commandname{Authentication Information Answer} + \\\ssixcolor{Result Code, \emph{Supported Features}} + \\\ssixcolor{E-UTRAN Vector: RAND, XRES, AUTN, KASME}}(node cs:name=MMEAPP3,anchor=center); + \draw[->] (node cs:name=MMEAPP4,anchor=center) -- node(arrow6)[above, align=center]{ + \commandname{Authentication Request}}(node cs:name=NAS3,anchor=center); + \draw[->] (node cs:name=NAS4,anchor=center) -- node(arrow7)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP3,anchor=center); + \draw[->] (node cs:name=S1AP4,anchor=center) -- node(arrow8)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length}}(node cs:name=SCTP2,anchor=center); + \draw[->] (node cs:name=SCTP3,anchor=center) -- node(arrow9)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP5,anchor=center); + \draw[->] (node cs:name=S1AP6,anchor=center) -- node(arrow10)[above, align=center]{ + \commandname{Uplink NAS Transport} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{NAS PDU, E-CGI, TAI}}(node cs:name=NAS5,anchor=center); + \draw[->] (node cs:name=NAS6,anchor=center) -- node(arrow11)[above, align=center]{ + \commandname{Authentication Response}}(node cs:name=MMEAPP5,anchor=center); + \draw[->] (node cs:name=MMEAPP6,anchor=center) -- node(arrow12)[above, align=center]{ + \commandname{Update Location Request} + \\\nascolor{IMSI, Initial Attach, RAT Type, UE SRVCC Capability} + \\\nascolor{Terminal Information: IMEISV} + \\\soneapcolor{PLMN Id} + \\\ssixcolor{\emph{Supported Features}} + \\\mmecolor{S6A flag, Don't skip subscriber data}}(node cs:name=S6A3,anchor=center); + \draw[->] (node cs:name=S6A4,anchor=center) -- node(arrow13)[above, align=center]{ + \commandname{Update Location Answer} + \\\ssixcolor{Result Code = DIAMETER\_SUCCESS, Subscription Data:} + \\\mmecolor{\{ Subscriber Status, Network Access Mode, RAU TAU timer} + \\\spappcolor{AMBR, MSISDN, APN Configuration Profile} + \\\spappcolor{[Default-APN Id, APN-Configuration$<$1:n$>$(UE IP$<$0:2$>$,} + \\\spappcolor{Service Selection, QOS profile, APN-AMBR,} + \\\spappcolor{PDN GW address)]\}}}(node cs:name=MMEAPP7,anchor=center); + \draw[->] (node cs:name=MMEAPP8,anchor=center) -- node(arrow14)[above, align=center]{ + \commandname{Create Session Request} + \\\nascolor{IMSI, RAT Type, Initial Attach, UE time zone} + \\\soneapcolor{ECGI, TAI, CSG Id} + \\\ssixcolor{APN, PDN type, Selection Mode, PAA, APN-AMBR} + \\\mmecolor{Bearer to create$<$1$>$: EBI, QOS, S-GW F-TEID, TFT}}(node cs:name=SPAPP1,anchor=center); + \draw[->] (node cs:name=SPAPP2,anchor=center) -- node(arrow15)[above, align=center]{ + \commandname{Create Session Response} + \\\mmecolor{Cause $\neq$ Attach Accepted}}(node cs:name=MMEAPP9,anchor=center); + \draw[->] (node cs:name=MMEAPP10,anchor=center) -- node(arrow16)[above, align=center]{ + \commandname{Failure Indication} + \\\mmecolor{S11 to NAS mapped cause value} + \\\mmecolor{(See 3GPP TS 29.274 Table 8.4.1)}}(node cs:name=NAS7,anchor=center); + \draw[->] (node cs:name=NAS8,anchor=center) -- node(arrow17)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP7,anchor=center); + \draw[->] (node cs:name=S1AP8,anchor=center) -- node(arrow18)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length} + \\\soneapcolor{S1-MME eNB IP address}}(node cs:name=SCTP4,anchor=center); + + \end{tikzpicture} + \end{center} + \caption{MME detailed behaviour: Default Bearer Rejected (S-GW Failure)} \label{fig:MME detailed behaviour: Default Bearer Rejected (S-GW Failure)} + + \begin{tikzpicture} + \matrix (matrixl3) [square matrix] { + \node[](l1) {\mmecolor{MME}}; & \node[](ct1) {MME application or default MME parameter};\\ + \node[](l2) {\soneapcolor{S1AP}}; & \node[](ct2) {S1AP provided parameter};\\ + \node[](l3) {\nascolor{NAS}}; & \node[](ct3) {NAS provided parameter};\\ + \node[](l4) {\ssixcolor{S6A}}; & \node[](ct4) {HSS provided parameter};\\ + \node[](l5) {\spappcolor{S11}}; & \node[](ct5) {S+P-GW provided parameter};\\ + \node[](l6) {\sctpcolor{SCTP}}; & \node[](ct6) {SCTP provided parameter};\\ + \node[](l7) {\emph{Optional}}; & \node[](ct7) {Optional parameter};\\ + }; + + % \node[draw,fit=(ct1)(l1)(ct2)(l2)(ct3)(l3)(l4)(ct4)(l5)(ct5)] {}; + % \node[below = 0.5cm of l2](l3) {}; + % \draw[below=0.5cm of l2, ->] (1,1) -- (0,1); + \end{tikzpicture} + \end{figure} + \end{landscape} + + \begin{landscape} +\begin{figure} + \begin{center} + \begin{tikzpicture} + \tikzstyle{every node}=[font=\footnotesize] + \matrix (matrix6) [row sep=0.7cm, column sep={8.3cm,between origins}, matrix of nodes] { + \node(SCTP) [schritt] {SCTP}; & \node(S1AP) [schritt] {S1AP}; & \node(NAS) [schritt] {NAS}; & \node(MMEAPP) [schritt] {MME APP}; & \node(S6A) [schritt] {S6A}; & \node(SPAPP) [schritt] {S+P-GW APP};\\\\ + \node(SCTP1) [] {}; & \node(S1AP1) [] {};\\ + & \node(S1AP2) [] {}; & \node(NAS1) [] {};\\ + & & \node(NAS2) [] {}; & \node(MMEAPP1) [] {};\\ + & & & \node(MMEAPP2) [] {}; & \node(S6A1) [] {};\\\\ + & & & \node(MMEAPP3) [] {}; & \node(S6A2) [] {};\\ + & & \node(NAS3) [] {}; & \node(MMEAPP4) [] {};\\ + & \node(S1AP3) [] {}; & \node(NAS4) [] {};\\ + \node(SCTP2) [] {}; & \node(S1AP4) [] {};\\\\ + \node(SCTP3) [] {}; & \node(S1AP5) [] {};\\ + & \node(S1AP6) [] {}; & \node(NAS5) [] {};\\ + & & \node(NAS6) [] {}; & \node(MMEAPP5) [] {};\\ + & & & \node(MMEAPP6) [] {}; & \node(S6A3) [] {};\\\\\\\\ + & & & \node(MMEAPP7) [] {}; & \node(S6A4) [] {};\\\\\\ + & & & \node(MMEAPP8) [] {}; & & \node(SPAPP1) [] {};\\\\ + & & & \node(MMEAPP9) [] {}; & & \node(SPAPP2) [] {};\\ + & & \node(NAS7) [] {}; & \node(MMEAPP10) [] {};\\ + & \node(S1AP7) [] {}; & \node(NAS8) [] {};\\ + \node(SCTP4) [] {}; & \node(S1AP8) [] {};\\\\ + \node(SCTP6) [] {}; & \node(S1AP11) [] {};\\ + & \node(S1AP12) [] {}; & & \node(MMEAPP12) [] {};\\ + & & & \node(MMEAPP13) [] {}; & & \node(SPAPP3) [] {};\\\\ + & & & \node(MMEAPP14) [] {}; & & \node(SPAPP4) [] {};\\ + \node(SCTPEND) [] {}; & \node(S1APEND) [] {}; & \node(NASEND) [] {}; & \node(MMEAPPEND) [] {}; & \node(S6AEND) [] {}; & \node(SPAPPEND) [] {};\\ + }; + + \path[-] + (SCTP) edge (SCTPEND) + (S1AP) edge (S1APEND) + (NAS) edge (NAS8) + (MMEAPP) edge (MMEAPPEND) + (S6A) edge (S6A4) + (SPAPP) edge (SPAPPEND) + ; + + \draw[->] (node cs:name=SCTP1,anchor=center) -- node(arrow1)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP1,anchor=center); + \draw[->] (node cs:name=S1AP2,anchor=center) -- node(arrow2)[above, align=center]{ + \commandname{Initial UE message} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU, TAI} + \\\soneapcolor{RRC Establishment Cause, E-UTRAN CGI, Current time} + \\\soneapcolor{\emph{S-TMSI, CSG Id, GUMMEI, Cell Access Mode},} + \\\soneapcolor{\emph{GW Transport Layer Address, Relay Node Indicator}}}(node cs:name=NAS1,anchor=center); + \draw[->] (node cs:name=NAS2,anchor=center) -- node(arrow3)[above, align=center]{ + \commandname{Attach Request} + \\\nascolor{Default APN: NULL, UE network cap,} + \\\nascolor{EPS attach type, KSI, \emph{GUTI, IMEI}, IMSI} + \\\nascolor{Request type: Initial, PDN Type}}(node cs:name=MMEAPP1,anchor=center); + \draw[->] (node cs:name=MMEAPP2,anchor=center) -- node(arrow4)[above, align=center]{ + \commandname{Authentication Information Request} + \\\soneapcolor{PLMN Id, }\nascolor{IMSI,} + \\\ssixcolor{Destination Host, Destination Realm} + \\\mmecolor{\emph{Supported Features}, Number of vectors=1, } + \\\mmecolor{Immediate Response}}(node cs:name=S6A1,anchor=center); + \draw[->] (node cs:name=S6A2,anchor=center) -- node(arrow5)[above, align=center]{ + \commandname{Authentication Information Answer} + \\\ssixcolor{Result Code, \emph{Supported Features}} + \\\ssixcolor{E-UTRAN Vector: RAND, XRES, AUTN, KASME}}(node cs:name=MMEAPP3,anchor=center); + \draw[->] (node cs:name=MMEAPP4,anchor=center) -- node(arrow6)[above, align=center]{ + \commandname{Authentication Request}}(node cs:name=NAS3,anchor=center); + \draw[->] (node cs:name=NAS4,anchor=center) -- node(arrow7)[above, align=center]{ + \commandname{Downlink NAS transport} + \\\nascolor{eNB UE S1AP ID, MME UE S1AP ID, NAS PDU}}(node cs:name=S1AP3,anchor=center); + \draw[->] (node cs:name=S1AP4,anchor=center) -- node(arrow8)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length}}(node cs:name=SCTP2,anchor=center); + \draw[->] (node cs:name=SCTP3,anchor=center) -- node(arrow9)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP5,anchor=center); + \draw[->] (node cs:name=S1AP6,anchor=center) -- node(arrow10)[above, align=center]{ + \commandname{Uplink NAS Transport} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{NAS PDU, E-CGI, TAI}}(node cs:name=NAS5,anchor=center); + \draw[->] (node cs:name=NAS6,anchor=center) -- node(arrow11)[above, align=center]{ + \commandname{Authentication Response}}(node cs:name=MMEAPP5,anchor=center); + \draw[->] (node cs:name=MMEAPP6,anchor=center) -- node(arrow12)[above, align=center]{ + \commandname{Update Location Request} + \\\nascolor{IMSI, Initial Attach, RAT Type, UE SRVCC Capability} + \\\nascolor{Terminal Information: IMEISV} + \\\soneapcolor{PLMN Id} + \\\ssixcolor{\emph{Supported Features}} + \\\mmecolor{S6A flag, Don't skip subscriber data}}(node cs:name=S6A3,anchor=center); + \draw[->] (node cs:name=S6A4,anchor=center) -- node(arrow13)[above, align=center]{ + \commandname{Update Location Answer} + \\\ssixcolor{Result Code = DIAMETER\_SUCCESS, Subscription Data:} + \\\mmecolor{\{ Subscriber Status, Network Access Mode, RAU TAU timer} + \\\spappcolor{AMBR, MSISDN, APN Configuration Profile} + \\\spappcolor{[Default-APN Id, APN-Configuration$<$1:n$>$(UE IP$<$0:2$>$,} + \\\spappcolor{Service Selection, QOS profile, APN-AMBR,} + \\\spappcolor{PDN GW address)]\}}}(node cs:name=MMEAPP7,anchor=center); + \draw[->] (node cs:name=MMEAPP8,anchor=center) -- node(arrow14)[above, align=center]{ + \commandname{Create Session Request} + \\\nascolor{IMSI, RAT Type, Initial Attach, UE time zone} + \\\soneapcolor{ECGI, TAI, CSG Id} + \\\ssixcolor{APN, PDN type, Selection Mode, PAA, APN-AMBR} + \\\mmecolor{Bearer to create$<$1$>$: EBI, QOS, S-GW F-TEID, TFT}}(node cs:name=SPAPP1,anchor=center); + \draw[->] (node cs:name=SPAPP2,anchor=center) -- node(arrow15)[above, align=center]{ + \commandname{Create Session Response} + \\\mmecolor{Bearer Creation Result} + \\\nascolor{PAA, APN-AMBR, QoS, TFT, EBI} + \\\soneapcolor{S1-U S-GW TEID, S-GW Address for UP}}(node cs:name=MMEAPP9,anchor=center); + \draw[->] (node cs:name=MMEAPP10,anchor=center) -- node(arrow16)[above, align=center]{ + \commandname{Attach Accepted + Default Bearer}}(node cs:name=NAS7,anchor=center); + \draw[->] (node cs:name=NAS8,anchor=center) -- node(arrow17)[above, align=center]{ + \commandname{Initial Context Setup Request} + \\\nascolor{NAS PDU, eNB UE S1AP ID, MME UE S1AP ID} + \\\ssixcolor{AMBR, APN-AMBR, QoS, S-GW Address, } + \\\ssixcolor{S1-U S-GW TEID, KeNB,} + \\\ssixcolor{security cap (encryption/integrity)}}(node cs:name=S1AP7,anchor=center); + \draw[->] (node cs:name=S1AP8,anchor=center) -- node(arrow18)[above, align=center]{ + \commandname{Send Data Req} + \\\soneapcolor{OUT Stream, Association ID, Payload, Payload Length} + \\\soneapcolor{S1-MME eNB IP address}}(node cs:name=SCTP4,anchor=center); + \draw[->] (node cs:name=SCTP6,anchor=center) -- node(arrow21)[above, align=center]{ + \commandname{New Data Indication} + \\\sctpcolor{IN Stream, Association ID, Payload, Payload Length} + \\\sctpcolor{S1-MME eNB IP address}}(node cs:name=S1AP11,anchor=center); + \draw[->] (node cs:name=S1AP12,anchor=center) -- node(arrow22)[above, align=center]{ + \commandname{Initial Context Setup Failure} + \\\soneapcolor{eNB UE S1AP ID, MME UE S1AP ID, } + \\\soneapcolor{Cause, \emph{Criticality Diagnostics}}}(node cs:name=MMEAPP12,anchor=center); + \draw[->] (node cs:name=MMEAPP13,anchor=center) -- node(arrow24)[above, align=center]{ + \commandname{Delete Session Request} + \\\mmecolor{Linked EPS Bearer Id}}(node cs:name=SPAPP3,anchor=center); + \draw[->] (node cs:name=SPAPP4,anchor=center) -- node(arrow25)[above, align=center]{ + \commandname{Delete Session Response} + \\\spappcolor{Result}}(node cs:name=MMEAPP14,anchor=center); + + \end{tikzpicture} + \end{center} + \caption{MME detailed behaviour: Default Bearer Rejected (eNB Reject or Failure)} \label{fig:MME detailed behaviour: Default Bearer Rejected (eNB Reject or Failure)} + + \begin{tikzpicture} + \matrix (matrixl3) [square matrix] { + \node[](l1) {\mmecolor{MME}}; & \node[](ct1) {MME application or default MME parameter};\\ + \node[](l2) {\soneapcolor{S1AP}}; & \node[](ct2) {S1AP provided parameter};\\ + \node[](l3) {\nascolor{NAS}}; & \node[](ct3) {NAS provided parameter};\\ + \node[](l4) {\ssixcolor{S6A}}; & \node[](ct4) {HSS provided parameter};\\ + \node[](l5) {\spappcolor{S11}}; & \node[](ct5) {S+P-GW provided parameter};\\ + \node[](l6) {\sctpcolor{SCTP}}; & \node[](ct6) {SCTP provided parameter};\\ + \node[](l7) {\emph{Optional}}; & \node[](ct7) {Optional parameter};\\ + }; + + % \node[draw,fit=(ct1)(l1)(ct2)(l2)(ct3)(l3)(l4)(ct4)(l5)(ct5)] {}; + % \node[below = 0.5cm of l2](l3) {}; + % \draw[below=0.5cm of l2, ->] (1,1) -- (0,1); + \end{tikzpicture} + \end{figure} + \end{landscape} +\end{document} diff --git a/openair-cn/DOCS/Latex/EPC/EPC.pdf b/openair-cn/DOCS/Latex/EPC/EPC.pdf new file mode 100644 index 0000000000000000000000000000000000000000..598796e12838ba5d4c0f2486d16f09c301c871fe GIT binary patch literal 243263 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 literal 0 HcmV?d00001 diff --git a/openair-cn/DOCS/Latex/EPC/EPC.tex b/openair-cn/DOCS/Latex/EPC/EPC.tex new file mode 100644 index 0000000000..f1df0a6a37 --- /dev/null +++ b/openair-cn/DOCS/Latex/EPC/EPC.tex @@ -0,0 +1,774 @@ +\documentclass[a4paper,oneside]{report} +\usepackage{pgfplots} +\ifx\HCode\UnDef\else\def\pgfsysdriver{pgfsys-tex4ht.def}\fi +\usepackage{verbatim} +\usepackage{listings} +\usepackage{tikz,graphicx} +\usepackage{caption} +\usepackage{float} +\usepackage{hyperref} +\usepackage{subfiles} +\usepackage{nomencl} +\usepackage{chngcntr} +\makenomenclature + +\usepackage{makeidx} +\makeindex + +\counterwithout{figure}{chapter} + +\usetikzlibrary{external,calc,trees,positioning,arrows,chains,shapes.geometric,% +decorations.pathreplacing,decorations.pathmorphing,shapes,% +matrix,fit,shapes.symbols,backgrounds,fit} +\captionsetup[figure]{labelformat=simple} + +\renewcommand{\figurename}{Figure} +% Returns three nodes: The argument, and the projections of the argument on the left and right borders of the bounding box +\newcommand{\extendnode}[1]{ + (#1) + ($(current bounding box.north east)!(#1)!(current bounding box.south east)$) + ($(current bounding box.north west)!(#1)!(current bounding box.south west)$) +} + +\usetikzlibrary{calc,trees,positioning,arrows,chains,shapes.geometric,% +decorations.pathreplacing,decorations.pathmorphing,shapes,% +matrix,shapes.symbols,backgrounds,fit,intersections} + +\title{OAI EPC current development} +\author{Sebastien ROUX\\Eurecom\\sebastien.roux@eurecom.fr} + +\definecolor{javared}{rgb}{0.6,0,0} % for strings +\definecolor{javagreen}{rgb}{0.25,0.5,0.35} % comments +\definecolor{ckeyw}{rgb}{0,0,0.8} % keywords +\definecolor{ccomment}{rgb}{0.6,0.6,0.6} % javadoc + +\lstset{ + language=C, + basicstyle=\ttfamily, + keywordstyle=\color{ckeyw}\bfseries, + stringstyle=\color{javared}, + commentstyle=\color{ccomment}, + morecomment=[s][\color{ccomment}]{/**}{*/}, + numbers=left, + numberstyle=\tiny\color{black}, + stepnumber=1, + numbersep=10pt, + tabsize=4, + showspaces=false, + showstringspaces=false, + breaklines +} + + +\tikzset{ + table nodes/.style={ + rectangle, + rounded corners=0.6mm, + draw=black, + align=center, + minimum height=7mm, + minimum width=22mm, + text depth=0.5ex, + text height=2ex, + % inner xsep=0pt, + outer sep=0pt, + }, + table/.style={ + matrix of nodes, + % row sep=-\pgflinewidth, + % column sep=-\pgflinewidth, + rectangle, + nodes={ + table nodes + }, + execute at empty cell={\node[draw=none]{};} + }, + cps/.style={ + draw=black, + fill=blue!20, + rounded corners=0.6mm, + }, + ups/.style={ + draw=black, + fill=yellow!30, + rounded corners=0.6mm, + }, + stdlinux/.style={ + draw=black, + fill=green!10, + rounded corners=0.6mm, + }, + rect/.style={ + rectangle, + draw, + }, + schritt/.style={ + draw, + rounded corners, + fill=blue!20, + inner xsep=2em, + }, + t0/.style={draw,fill=blue!20}, + t1/.style={draw,fill=blue!40}, + background/.style={ + draw, + fill=yellow!30, + align=center, + dashed, + }, + background2/.style={ + draw, + fill=green!15, + align=center, + }, + connector/.style={ + -latex, + font=\scriptsize + }, + rectangle connector/.style={ + connector, + to path={(\tikztostart) -| (\tikztotarget) }, + pos=0.5 + }, + rectangle connector/.default=-2cm, + straight connector/.style={ + connector, + to path=--(\tikztotarget) \tikztonodes + }, + queue/.style={ + draw, + fill=yellow!30, + cylinder, + aspect=0.7, + minimum height=1cm, + minimum width=0.7cm + }, +} +\renewcommand{\nomname}{List of Abbreviations} +\renewcommand{\thefigure}{\Alph{figure}} + +\begin{document} +\maketitle +\tableofcontents +\printnomenclature[2cm] + +\chapter*{MME and S+P-Gateway} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{MME and S+P-Gateway} + +% \nomenclature{MME}{Mobility Management Entity} +% \nomenclature{S-GW}{Serving Gateway} +% \nomenclature{P-GW}{PDN Gateway} +\begin{figure}[H] +\begin{center} +\begin{tikzpicture} +\tikzstyle{every node}=[font=\footnotesize] +\matrix (table) [row sep=0.5cm, column sep={3.2cm,between origins}, table,text width=3mm,name=table] { + & & &\\ + & & &\\ + & & &\\ + & & &\\ + & & &\\ +}; +\node(MMEAPP)[cps,draw,fit=(table-1-1)(table-1-2),table nodes]{MME Application}; +\node(SPGW)[cps,draw,fit=(table-1-3)(table-1-4),table nodes]{S+P-GW Application}; +\node(NAS)[cps,draw,fit=(table-2-2),table nodes]{NAS}; +\node(S6A)[dashed,cps,draw,fit=(table-3-1),table nodes]{S6a/Diameter}; +\node(S1AP)[cps,draw,fit=(table-3-2),table nodes]{S1-MME/S1AP}; +\node(S1U)[ups,draw,fit=(table-3-3),table nodes]{S1-U/GTPU}; +\node(SGI)[dashed,ups,draw,fit=(table-3-4),table nodes]{SGi}; +\node(SCTP)[stdlinux,draw,fit=(table-4-1)(table-4-2),table nodes]{SCTP}; +\node(UDP)[stdlinux,draw,fit=(table-4-3),table nodes]{UDP}; +\node(IP)[stdlinux,draw,fit=(table-5-1)(table-5-2)(table-5-3)(table-5-4),table nodes]{IP}; + +\draw[<->, dashed, draw=red] (MMEAPP) -- node(arrow1)[above, align=center]{S11}(SPGW); +\draw[<-,dashed] (S1U) -- (SPGW.south-|S1U); +\draw[<-,dashed] (SGI) -- (SPGW.south-|SGI); +\draw[-] (S6A) -- (MMEAPP.south-|S6A); +\draw[-] (NAS) -- (MMEAPP.south-|NAS); +\draw[-] (S1AP) -- (NAS); +\draw[-] (S1U) -- (SGI); +\draw[-] (S1U) -- (UDP); +\draw[-] (S1AP) -- (SCTP.north-|S1AP); +\draw[-] (S6A) -- (SCTP.north-|S6A); +\draw[-] (SCTP) -- (IP.north-|SCTP); +\draw[-] (UDP) -- (IP.north-|UDP); +\draw[-] (SGI) -- (IP.north-|SGI); +\draw[-] (MMEAPP.south) |- (S1AP.west); + +\draw($(table.north west) + (-2mm,1mm)$) rectangle ($(table.south east) + (2mm,-1mm)$); + +\node[cps, minimum width=5mm,minimum height=5mm,below=of IP.south west,anchor=west](l1){}; +\node[right=2mm of l1](ct1) {Control Plane}; +\node[ups,minimum width=5mm,minimum height=5mm,below=0.3cm of l1](l2){}; +\node[below=0.3cm of ct1, right=2mm of l2](ct2) {User Plane}; +\node[stdlinux,minimum width=5mm,minimum height=5mm,below=0.3cm of l2](l3){}; +\node[below=0.3cm of ct2, right=2mm of l3](ct3) {Linux IP Stack}; +\draw[minimum width=5mm,minimum height=5mm,below=0.3cm of l3,<->,dashed, draw=red] +($(l3.south west) - (0,0.55cm)$) -- node(l4){} ($(l3.south east) - (0,0.55cm)$); +\node[right=2mm of l4.north east](ct4) {Abstraction link}; +\draw[minimum width=5mm,minimum height=5mm,below=0.3cm of l4,->,dashed] +($(l4.south west) - (0,0.25cm)$) -- node(l5){} ($(l4.south east) - (0,0.25cm)$); +\node[right=2mm of l5.north east](ct5) {Control}; +\node[draw,fit=(ct1)(l1)(ct2)(l2)(ct3)(l3)(ct4)(l4)(ct5)(l5)] {}; + +\end{tikzpicture} +\caption{MME and S+P-GW architecture} \label{fig:MMEoverall} +\end{center} +\end{figure} + +Figure \ref{fig:MMEoverall} shows the targeted implementation of Eurecom +EPC. + +\chapter*{S1AP layer} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{S1AP layer} + +\nomenclature{S1AP}{S1 Application Protocol}S1AP layer relies on +\nomenclature{ASN.1}{Abstract Syntax Notation.1}ASN.1 messages +description. Generating C code from the specification +implies three steps: +\begin{enumerate} +\item Modify .asn files to match tools limitation. +\item Generate \nomenclature{IE}{Informations Elements}IEs with the help of the asn1c free tool. +\item Use the provided script which generates \nomenclature{PDU}{Protocol Data Unit}PDU codec\footnote{Encode/Decode}. +\end{enumerate} + +\chapter*{Inter-task interface} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{Inter-task interface} + +\section{Concurrency} + +Code divided in layers should be able to be executed in parallel to use the full +\nomenclature{CPU}{Control Processing Unit}CPUs power. We can achieve better performance +by using some mechanisms that runs part of code in parallel on UNIX platforms: +\begin{itemize} +\item Multi-process: no link between processes, usage of sockets or pipes is mandatory. +\item Forks: code is duplicated and data are stored in different spaces. +\item Threads: only code is duplicated, data space is shared between processes +\end{itemize} +Data synchronization is the first issue to think about when using such mechanisms. + +\section{Overall description} + +A single \nomenclature{API}{Application Programming Interface}API +(called ITTI\footnote{InTer-Task Interface}) is used to manage messages +exchanged between the tasks which are running on separate threads. +This will lead in better usage of multi-core environments. +\begin{figure}[h] + \begin{center} + \begin{tikzpicture} + \node[](t1) { Task A }; + \node[below=of t1,yshift=7mm,font=\tiny](s1) { send msg to task }; + \node[queue,rotate=90,below=of t1.south,anchor=top](c1) {}; + \node[right=of t1,xshift=15mm](t2) { Task B }; + \node[below=of t2,yshift=7mm,font=\tiny](r2) { recv msg from task }; + \node[queue,rotate=90,below=of t2.south,anchor=top](c2) {}; + \node[dashed,fit=(c1)(t1)(s1),draw](T1){}; + \node[dashed,fit=(c2)(t2)(r2),draw](T2){}; + \node[draw](ITTI) at ($(T1)!0.5!(T2) + (0, -2.3)$){ITTI interface}; + \draw[->] (T1) |- (ITTI); + \draw[->] (ITTI.east) -| (c2.bottom); + \draw[->] (c2.east) -- (r2); + \node[queue,rotate=90,minimum width=5mm,minimum height=7mm,right=of c2,anchor=top,yshift=-15mm](c3) {}; + \node[dashed,rectangle,minimum width=5mm,minimum height=5mm,draw,below=7mm of c3,anchor=east](c4) {}; + \node[right=4mm of c3.shape center](x3){Message queue}; + \node[right=4mm of c4.center](x4){Thread}; + \node[draw,fit=(c3)(x3)(x4)(c4)](T4){}; + \end{tikzpicture} + \caption{Overall process} \label{fig:Overall process} + \end{center} +\end{figure} +Figure \ref{fig:Overall process} describes the basic fonctionnement of the inter-task interface. +A message sent from +Task A is en-queued to the message queue belonging to the target task. Note that +tasks can send messages to themselves. Another API (See Figure \ref{fig:Broadcasting process}) defines broadcast messaging +where any task can send a broadcast message to every other task. +\begin{figure}[H] + \begin{center} + \begin{tikzpicture} + \node[](t1) { Task A }; + \node[below=of t1,yshift=7mm,font=\tiny](s1) { send broadcast msg }; + \node[queue,rotate=90,below=of t1.south,anchor=top](c1) {}; + + \node[right=of t1,xshift=35mm](t2) { Task B }; + \node[below=of t2,yshift=7mm,font=\tiny](r2) { recv msg from task }; + \node[queue,rotate=90,below=of t2.south,anchor=top](c2) {}; + + \node[right=of t2,xshift=15mm](tn) { Task N }; + \node[below=of tn,yshift=7mm,font=\tiny](rn) { recv msg from task }; + \node[queue,rotate=90,below=of tn.south,anchor=top](cn) {}; + \node[dashed,fit=(c1)(t1)(s1),draw](T1){}; + \node[dashed,fit=(c2)(t2)(r2),draw](T2){}; + \node[dashed,fit=(cn)(tn)(rn),draw](TN){}; + + \node[](ITTI) at ($(T2)!0.5!(TN)$){...}; + \node[draw](ITTI) at ($(T1)!0.5!(T2) + (0, -2.3)$){ITTI interface}; + \draw[->] (T1) |- (ITTI); + \draw[->] (ITTI.east) -| (c2.bottom); + \draw[->] (ITTI.east) -| (cn.bottom); + \draw[->] (c2.east) -- (r2); + \draw[->] (cn.east) -- (rn); + \node[queue,rotate=90,minimum width=5mm,minimum height=7mm,below=23mm of T1](c3) {}; + \node[dashed,rectangle,minimum width=5mm,minimum height=5mm,draw,below=7mm of c3,anchor=east](c4) {}; + \node[right=4mm of c3.shape center](x3){Message queue}; + \node[right=4mm of c4.center](x4){Thread}; + \node[draw,fit=(c3)(x3)(x4)(c4)](T4){}; + \end{tikzpicture} + \caption{Broadcasting process} \label{fig:Broadcasting process} + \end{center} +\end{figure} +Once a task received a new message and if the task is in sleep mode (i.e. not handling +any message), the task is waken up and the message is de-queued. We can imagine a limit +in number of parallel tasks, for example N+1 CPU's. Architectures using hyper-threading +mechanism can have this value extended to 2 x CPU's. +Every task is running in a separated pthread, awaiting for new messages to handle. + +\section{Signals from kernel} + +Handling of signals from kernel is the more critical part as a signal can be raised +at any moment and will interrupt one of the running thread. Used signals should be restricted +to a single task that will handle them (using the POSIX sigmask function) . Moreover, it isn't +thread-safe to use mutexes inside a signal handler, a synchronization flag should be used to +notify the signal handler task. This task will then send the appropriate message +to the right task. For example, handling of signals can be done in the main thread or by a background task +scheduled periodically. +To overcome these issues, sigtimedwait and sigwaitinfo API functions can be used +to wait for a signal to happen. Signals will be received in the thread context, as far as +other threads block these signals. + +\section{Priority handling} + +Usage of message prioritization enables tasks to send critical messages with a faster +delivery time regarding other messages en-queued for the target task. +For now only seven priority levels can be applied when defining tasks: +\begin{itemize} +\item TASK\_PRIORITY\_MAX +\item TASK\_PRIORITY\_MAX\_LEAST +\item TASK\_PRIORITY\_MED\_PLUS +\item TASK\_PRIORITY\_MED +\item TASK\_PRIORITY\_MED\_LEAST +\item TASK\_PRIORITY\_MIN\_PLUS +\item TASK\_PRIORITY\_MIN +\end{itemize} +For now message priority does not involve any suitable scheduler: every time a message is de-queued, +message priority of other messages is incremented by one. + +\section{Message scheduling} +Currently, there is no software limit on the maximum number of threads executed in parallel. +When a task sends a message, it is en-queued in the right message queue, belonging to +the target task. The queue is a double-linked list. A mutex prevents other tasks +from modifying this queue while a task is en-queueing or removing a message. + +\section{Message definition} +Messages are defined using a single macro that adds the message to the ids enumeration +and maps data of the message to the union of messages. +\begin{lstlisting} +MESSAGE_DEF(S1AP_SCTP_NEW_MESSAGE_IND, TASK_PRIORITY_MED, S1apSctpNewMessageInd s1apSctpNewMessageInd) +\end{lstlisting} +and the associated data: +\begin{lstlisting} +typedef struct { + uint8_t *buffer; ///< SCTP buffer + uint32_t bufLen; ///< SCTP buffer length + int32_t assocId; ///< SCTP physical association ID + uint8_t stream; ///< Stream number on which data had been received + uint16_t instreams; ///< Number of input streams for the SCTP connection between peers + uint16_t outstreams; ///< Number of output streams for the SCTP connection between peers +} S1apSctpNewMessageInd; +\end{lstlisting} +\section{Task message handling} +\begin{lstlisting} +void* s1ap_mme_thread(void *args) { + while(1) { + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + receive_msg(TASK_S1AP, &receivedMessage); + assert(receivedMessage != NULL); + switch(receivedMessage->messageId) { + case S1AP_SCTP_NEW_MESSAGE_IND: + { + //Some processing + } break; + default: + { + S1AP_DEBUG("Unkwnon message ID %d\n", receivedMessage->messageId); + } break; + } + free(receivedMessage); + receivedMessage = NULL; + } + return NULL; +} +\end{lstlisting} +\section{Messages logging} +\begin{figure}[H] + \begin{center} + \begin{tikzpicture} + \node[](p1) { Process }; + \node[below=5mm of p1](i1) { ITTI }; + \node[queue,right=of i1,rotate=90,anchor=base](q1) {}; + \node[draw,fit=(i1)(q1)](s1) { }; + \node[fit=(p1)(i1)(q1)(s1),draw](T1){}; + \node[queue,fill=red!30,right=of s1.east,yshift=-5mm](c1) { TCP socket }; + \node[right=of c1](r1){ Remote host n }; + \node[fit=(r1),draw](R2){}; + \node[queue,fill=red!30,right=of s1.east,yshift=5mm](c2) { TCP socket }; + \node[right=of c2](r1){ Remote host 1 }; + \node[fit=(r1),draw](R1){}; + \draw[-] (q1.base) -- ++ (1,0) -| ++ (0,.6) -- (c2.west); + \draw[-] (c2) -- (R1); + \draw[-] (q1.base) -- ++ (1,0) -| ++ (0,-.4) -- (c1.west); + \draw[-] (c1) -- (R2); + \end{tikzpicture} + \caption{Remote debugging} \label{fig:Remote debugging} + \end{center} +\end{figure} +Logging of inter-tasks messages can be setup using an external tool that will be +connected to the ITTI. Based on an array of dumped messages, they are serialized +to produce an array of byte sent over a socket. A remote tool can then decode +messages and display fields, message number, time.\\ +Additionaly, logs from standard output can be printed over the debug tool. +Multi-user debugging on only one running process can be achieved using this interface. +Messages to dump should be queued for a pure asynchronous communication between the +dump task and the remote hosts. +Another interesting feature could be to send a message to a task from an host, +allowing run-time re-configuration. +The C pre-processor can be used to generate messages definition (using +\nomenclature{XML}{Extensible Markup Language}XML templates +for example).\\ +\section{Limitations} +Data pointers belonging to one task should never be passed to another task. +The presented mechanism does not prevent a task from being locked. In such a case, +the blocked task will no more handle messages incoming from other tasks. + +\section{Benefits} +\begin{itemize} + \item Only a single entry point between all tasks (easy inter-task communication tracking and debugging). + \item Usage of message queues enables parallelization of layers. + \item Message prioritization and scheduling. + \item Protection of data between threads is done by the API at an higher level. +\end{itemize} + +\section{To do} +\begin{itemize} + \item Implement a priority based scheduler. Currently the queue of messages works as a FIFO. + \item Limit the number of tasks thread that can be run in parallel +\end{itemize} + +\chapter*{Signal API} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{Signal API} + +On LINUX platforms, processes will receive signals comming from Kernel. +A single blocking entry point handles all used signals that are requested by the +MME. The main application thread is reserved to signal handling as this thread will +be blocked till a new signal is ready for handling.\\ +Using this method prevents threads from being interrupted by signals handler which +can interrupt the thread at any time and as a consequence create some misbehaving +in threads contexts. +Following is a sample list of signals handled: +\begin{itemize} + \item SIGABRT This is signal is sent to the process when abort() function is called + within the process and kill the process. Process can for example display the stack + once this signal is received. + \item SIGRTMIN This signal is used by the timer API and is raised everytime a + timer has expired. +\end{itemize} +Till now there is no way for tasks to request a new signal. + +\chapter*{Timer API} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{Timer API} + +Timer API doesn't consist of a task (i.e. tasks cannot send messages to it). +Handling of UNIX signal associated to the timers is a Real-time signal with an id (SIGRTMIN) +depending on the platform. Management of this signal is done by the signal interface +and developpers should not care about handling timer signals incoming from Kernel. +Once a timer has expired the task which has requested it will receive the TIMER\_HAS\_EXPIRED +signal. +Note that timer\_id is of type long and thus its size is platform specific. + +\section{Timer types} + +\begin{itemize} + \item TIMER\_ONE\_SHOT After expiry and its associated signal, the timer is removed. + \item TIMER\_PERIODIC The timer is automatically reloaded on each expiry while the task +which has setup this timer doesn't cancel it. +\end{itemize} + +\section{Requesting a new signal} +Any task can request a new signal by invoking the following API: +\begin{lstlisting} +int timer_setup( + uint32_t interval_sec, + uint32_t interval_us, + task_id_t task_id, + timer_type_t type, + long *timer_id); +\end{lstlisting} + +Note that timer id is a unique identifier to distinguish timers. + +\section{Disable and remove a timer} + +Disable and remove the timer referenced by timer\_id. +\begin{lstlisting} +int timer_remove(long timer_id); +\end{lstlisting} + +\section{Timer signal expiry} + +Once the signal dispatcher receives the SIGRTMIN signal, a new signal is sent +to the task which has requested the timer. Contrary to signal request, timer +expiry notification is achieved using the intertask mechanism. +The signal data associated to this event follows: +\begin{lstlisting} +typedef struct { + long timer_id; +} timer_has_expired_t; +\end{lstlisting} + +\chapter*{Compiling core EPC} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{Compiling core EPC} + +The core EPC software has been tested on Ubuntu 12.04LTS x86 and ia64. +Before compiling the core EPC, some packages should be installed on the platform. + +\section{Dependencies} + +\begin{itemize} + \item libsctp-dev + \item libpthread-dev + \item automake and autoconf + \item libtoolize + \item gcc, g++, make + \item flex and bison + \item openssl-dev + \item asn1c (see section \ref{sec:asn1c}) + \item libnettle (see section \ref{sec:libnettle}) + \item freediameter (see section \ref{sec:freediameter}) and gnutls 3.1.0 + (see section \ref{sec:gnutls}) +\end{itemize} +Command-line to install the required packages: +\begin{lstlisting} +sudo apt-get install cmake make gcc flex bison \ +libsctp1 libsctp-dev libidn2-0-dev libidn11-dev \ +libmysqlclient-dev libxml2-dev swig python-dev \ +cmake-curses-gui valgrind guile-2.0-dev \ +libgmp-dev libgcrypt11-dev gdb unzip \ +libtasn1-3-dev g++ autoconf automake \ +openssl-dev -y +\end{lstlisting} + +\subsection{ASN1c} +\label{sec:asn1c} + +\subsection{libnettle} +\label{sec:libnettle} + +The nettle library is used by freediameter for certificate encryption and by core +EPC for key derivation. +\begin{lstlisting} +wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz +gunzip nettle-2.5.tar.gz +tar -xvf nettle-2.5.tar +cd nettle-2.5/ +./configure --disable-openssl --enable-shared +make +make check +sudo make install +\end{lstlisting} +The commands provided above will download the required packages sources, configure +and install them on the system. +Note that any packages which is not in the Ubuntu repository is installed by default +in /usr/local instead of /usr. +This behaviour can be overriden at configuration time by providing --prefix=/usr to +the configuration script (configure). + +\subsection{gnutls} +\label{sec:gnutls} + +The GNUTls library is only used by freediameter for certificate handling and as a +consequence should be installed before trying to compile the freediameter library. +\begin{lstlisting} +wget ftp://ftp.gnutls.org/gcrypt/gnutls/v3.1/gnutls-3.1.0.tar.xz +tar -xvf gnutls-3.1.0.tar.xz +cd gnutls-3.1.0/ +./configure LDFLAGS='-L/usr/local/lib' +make +sudo make install +\end{lstlisting} +Note: when dependencies are installed in /usr/local instead of /usr, +LDFLAGS has to be overriden with the path to libraries when configuring the package: +LDFLAGS='-L/usr/local/lib'. + +\subsection{freediameter} +\label{sec:freediameter} +Freediameter is the package that provides diameter capabilities to the MME/HSS. +On top of this stack, S6A avp dictionnary is used to enable a compliant S6A interface. +\begin{lstlisting} +wget http://www.freediameter.net/hg/freeDiameter/archive/1.1.5.tar.gz +tar -xvf 1.1.5.tar.gz +cd freeDiameter-1.1.5 +patch -p1 < ../../freediameter-1.1.5.patch +mkdir build +cd build +cmake ../ +make +make test +sudo make install +\end{lstlisting} +If you want ot install this package in /usr instead of /usr/local,\\ +-DCMAKE\_INSTALL\_PREFIX:PATH=/usr should be passed to cmake at configuration. + +\chapter*{System configuration} \stepcounter{chapter} +\addcontentsline{toc}{chapter}{System configuration} + +Currently there is two ways to configure the system: +\begin{itemize} + \item Compilation configuration + \item Boot-up configuration +\end{itemize} +In the first type of configuration, the single system configuration structure +is filled in with default values that can be found in the mme\_default\_values.h +header file.\\ +When Boot-up configuration is used, a configuration file is passed to the process +by using the either -c filename.conf or --conf=filename.conf. This file is then parsed +by the bison interpreter and values are replaced in the global system configuration +structure. + +\section{Global MME parameters} + +\subsection{Relative MME capacity} +Even though this parameter is not used by the MME for controlling the MME load +balancing within a pool (at least for now), the parameter has to be to forwarded +to the eNBs during association procedure. +This parameter is encoded on 8bits, acceptable values going from 0 to 255. +(Default value = 15) +\begin{lstlisting} +RELATIVE_CAPACITY = 10; +\end{lstlisting} + +\subsection{Maximum number of UE} +\label{sec:Maximum number of UE} +This limit is present here only for debug purposes and is used to restrict +the number of served UE the MME can handle. In real network another mechanism +will trigger an MME overload for certain eNBs and will restrict certain types of +traffic. Such a mechanism would imply the Relative MME capacity. +\begin{lstlisting} +MAXUE = 100; +\end{lstlisting} + +\subsection{Maximum number of eNB} +Refer to \ref{sec:Maximum number of UE}. +\begin{lstlisting} +MAXENB = 10; +\end{lstlisting} + +\subsection{Tracking Area Identity} +\nomenclature{TAI}{Tracking Area Identity}TAI is the concatenation of +\nomenclature{MCC}{Mobile Country Code}MCC, \nomenclature{MNC}{Mobile Network Code}MNC and +\nomenclature{TAC}{Tracking Area Code}TAC. +The TAC uniquely identifies a PLMN within a Cell Id. +\begin{lstlisting} +PLMN = mcc.mnc:tac; +\end{lstlisting} +Multiple values can be given using a comma separator. Example: +\begin{lstlisting} +PLMN = 208.38:0,209.130:4,208.35:8; +\end{lstlisting} + +\subsection{MME Code} +A list of a maximum of 256 values can be provided. +\nomenclature{MMEC}{MME Code}MME Code is encoded on 8 bits, +so acceptable range is: 0 to 255. +Example: +\begin{lstlisting} +MME_CODE = 30,56,1,8; +\end{lstlisting} + +\subsection{MME Group Id} +A list of a maximum of 65356 values can be provided. +\nomenclature{MMEGID}{MME Group Id}MME Group Id is encoded on 16 bits, +so acceptable range is: 0 to 65535. +Example: +\begin{lstlisting} +MME_GID = 3,4,5,30,8,9,50021; +\end{lstlisting} + +\section{Intertask parameters} +\subsection{Queue size per task} +To restrict the number of messages in queues or to detect a possible MME overload, +an upper bound for the queue size can be defined like this: +\begin{lstlisting} +ITTI_QUEUE_SIZE = 2000000; +\end{lstlisting} +This parameter is expressed in bytes. Note that all messages exchanged by tasks +have the same size. + +\section{SCTP parameters} +\subsection{IN/OUT streams number} +The number of input/output streams can be configured to limit the number of streams +used for UE-associated signalling. Note that stream with id = 0 is reserved for +non-UE associated signalling. At least two streams should be used by the MME. +(Default value = 64/64 streams) +\begin{lstlisting} +SCTP_INSTREAMS = 32; +SCTP_OUTSTREAMS = 32; +\end{lstlisting} + +\section{S1AP parameters} +\subsection{Outcome timer} +Once an outcome is sent from MME to eNB, the MME locally starts a timer to abort +the procedure and release UE contexts if the expected answer to this outcome is not +received at the expiry of this timer.\\ +This timer is expressed in seconds. (Default value = 5 seconds) +\begin{lstlisting} +S1AP_OUTCOME_TIMER = 10; +\end{lstlisting} + +\section{Network interfaces parameters} + +Three paramters can be tuned in the configuration file: +\begin{itemize} + \item Interface Name: The related interface will be bind to this interface name + \item IP address: Currently only IPv4 address is allowed + \item IP netwmask: Netmask for the LAN +\end{itemize} +These three paramters can be setup for five different interfaces used: +\begin{itemize} + \item SGW interface for S11 + \item SGW interface for S1U/S12/S4 in user plane + \item SGW interface for S5/S8 in user plane + \item PGW interface for S5/S8 + \item PGW interface for SGi + \item MME interface for S1-MME in control plane +\end{itemize} +Example of configuration: +\begin{lstlisting} +# ------- Interfaces definitions +SGW_INTERFACE_NAME_FOR_S11 = "s11sgw"; +SGW_IP_ADDRESS_FOR_S11 = "192.168.10.1"; +SGW_IP_NETMASK_FOR_S11 = 24; + +SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP = "upsgw0"; +SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP = "192.168.1.1"; +SGW_IP_NETMASK_FOR_S1U_S12_S4_UP = 24; + +SGW_INTERFACE_NAME_FOR_S5_S8_UP = "upsgw1"; +SGW_IP_ADDRESS_FOR_S5_S8_UP = "192.168.5.2"; +SGW_IP_NETMASK_FOR_S5_S8_UP = 24; + +PGW_INTERFACE_NAME_FOR_S5_S8 = "uppgw0"; +PGW_IP_ADDRESS_FOR_S5_S8 = "192.168.5.1"; +PGW_IP_NETMASK_FOR_S5_S8 = 24; + +PGW_INTERFACE_NAME_FOR_SGI = "eth1"; +PGW_IP_ADDR_FOR_SGI = "192.168.12.30"; +PGW_IP_NETMASK_FOR_SGI = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "cpmme0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.11.1"; +MME_IP_NETMASK_FOR_S1_MME = 24; +\end{lstlisting} + +\end{document} diff --git a/openair-cn/DOCS/Latex/EPC/Makefile b/openair-cn/DOCS/Latex/EPC/Makefile new file mode 100644 index 0000000000..449b39d66f --- /dev/null +++ b/openair-cn/DOCS/Latex/EPC/Makefile @@ -0,0 +1,9 @@ +MYFILE=EPC + +all: + pdflatex $(MYFILE).tex + pdflatex $(MYFILE).tex + makeindex $(MYFILE).nlo -s nomencl.ist -o $(MYFILE).nls + pdflatex $(MYFILE).tex + +.PHONY: all diff --git a/openair-cn/DOCS/Makefile.am b/openair-cn/DOCS/Makefile.am new file mode 100644 index 0000000000..fdd2ce296f --- /dev/null +++ b/openair-cn/DOCS/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = DOXYGEN \ No newline at end of file diff --git a/openair-cn/GTPV1-U/Makefile.am b/openair-cn/GTPV1-U/Makefile.am new file mode 100644 index 0000000000..f586bf88e5 --- /dev/null +++ b/openair-cn/GTPV1-U/Makefile.am @@ -0,0 +1,31 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/include \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/shared \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE \ + -I$(top_srcdir)/UTILS/TIMER + +noinst_LTLIBRARIES = libgtpv1u.la + +libgtpv1u_la_LDFLAGS = -all-static + +libgtpv1u_la_SOURCES = \ + gtpv1u_task.c gtpv1u.h \ + gtpv1u_teid_pool.c \ + nw-gtpv1u/shared/NwTypes.h \ + nw-gtpv1u/shared/NwUtils.h \ + nw-gtpv1u/shared/NwGtpv1uError.h \ + nw-gtpv1u/shared/NwLog.h \ + nw-gtpv1u/shared/NwGtpv1uIe.h \ + nw-gtpv1u/shared/NwGtpv1uMsg.h \ + nw-gtpv1u/shared/NwGtpv1u.h \ + nw-gtpv1u/include/NwGtpv1uPrivate.h \ + nw-gtpv1u/include/NwGtpv1uLog.h \ + nw-gtpv1u/include/NwGtpv1uTrxn.h \ + nw-gtpv1u/include/NwGtpv1uTunnelEndPoint.h \ + nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c \ + nw-gtpv1u/src/NwGtpv1uTrxn.c \ + nw-gtpv1u/src/NwGtpv1uMsg.c \ + nw-gtpv1u/src/NwGtpv1u.c \ No newline at end of file diff --git a/openair-cn/GTPV1-U/Makefile.eNB b/openair-cn/GTPV1-U/Makefile.eNB new file mode 100644 index 0000000000..149a6f6bb4 --- /dev/null +++ b/openair-cn/GTPV1-U/Makefile.eNB @@ -0,0 +1,49 @@ +all: libgtpv1u.a + +libgtpv1u_OBJECTS = \ + nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.o \ + nw-gtpv1u/src/NwGtpv1uTrxn.o \ + nw-gtpv1u/src/NwGtpv1uMsg.o \ + nw-gtpv1u/src/NwGtpv1u.o \ + gtpv1u_eNB.o \ + gtpv1u_teid_pool.o \ + + +CFLAGS = \ + -I./nw-gtpv1u/shared \ + -I./nw-gtpv1u/include \ + -I../UTILS \ + -I../UTILS/HASHTABLE \ + -I../UDP \ + -I$(OPENAIR2_DIR) \ + -DUSER_MODE \ + -DENABLE_USE_MME \ + -DUSER_MODE \ + -DNB_ANTENNAS_RX=2 -DNB_ANTENNAS_TXRX=2 -DNB_ANTENNAS_TX=2 \ + -g \ + -O2 \ + -Wall \ + -Werror=implicit-function-declaration + +-include .deps/*.d +-include .deps/nw-gtpv1u/src/*.d + +$(libgtpv1u_OBJECTS): %.o : %.c + @echo "Compiling $<" + @$(CC) -c $(CFLAGS) -o $@ $< + @if ! test -d ".deps/nw-gtpv1u/src/" ; then mkdir -p .deps/nw-gtpv1u/src/; fi + @$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d + @mv -f .deps/$*.d .deps/$*.d.tmp + @sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d + @sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d + @rm -f .deps/$*.d.tmp + +libgtpv1u.a: $(libgtpv1u_OBJECTS) + @echo Creating GTP-U archive + @$(AR) rcvs $@ $(libgtpv1u_OBJECTS) + +clean: + rm -f libgtpv1u.a + rm -rf .deps/ + rm -f $(libgtpv1u_OBJECTS) \ No newline at end of file diff --git a/openair-cn/GTPV1-U/gtpv1u.h b/openair-cn/GTPV1-U/gtpv1u.h new file mode 100644 index 0000000000..50d694acc1 --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u.h @@ -0,0 +1,51 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef GTPV1_U_H_ +#define GTPV1_U_H_ + +/* When gtpv1u is compiled for eNB use MACRO from UTILS/log.h, + * otherwise use standard fprintf as logger. + */ +#if defined(ENB_MODE) +# define GTPU_DEBUG(x, args...) LOG_D(GTPU, x, ##args) +# define GTPU_INFO(x, args...) LOG_I(GTPU, x, ##args) +# define GTPU_WARN(x, args...) LOG_W(GTPU, x, ##args) +# define GTPU_ERROR(x, args...) LOG_E(GTPU, x, ##args) +#else +# define GTPU_DEBUG(x, args...) fprintf(stdout, "[GTPU][D]"x, ##args) +# define GTPU_INFO(x, args...) fprintf(stdout, "[GTPU][I]"x, ##args) +# define GTPU_WARN(x, args...) fprintf(stdout, "[GTPU][W]"x, ##args) +# define GTPU_ERROR(x, args...) fprintf(stderr, "[GTPU][E]"x, ##args) +#endif + +uint32_t gtpv1u_new_teid(void); + +#endif /* GTPV1_U_H_ */ diff --git a/openair-cn/GTPV1-U/gtpv1u_eNB.c b/openair-cn/GTPV1-U/gtpv1u_eNB.c new file mode 100644 index 0000000000..5fc1fb34fa --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u_eNB.c @@ -0,0 +1,520 @@ +#include <stdio.h> +#include <errno.h> + + +#include "NwGtpv1u.h" +#include "NwGtpv1uMsg.h" +#include "NwLog.h" + +#include "log.h" + +#include "gtpv1u_eNB_defs.h" + +#include "udp_primitives_client.h" +#include "UTIL/LOG/log.h" +#include "COMMON/platform_types.h" + +#ifdef GTPU_IN_KERNEL +#include <netinet/in.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#endif + + +extern unsigned char pdcp_data_req (module_id_t module_id, u32_t frame, u8_t eNB_flag, rb_id_t rab_id, u32 muiP, u32 confirmP, sdu_size_t sdu_buffer_size, unsigned char* sdu_buffer, u8 is_data_pdu); + + +inline NwGtpv1uRcT gtpv1u_eNB_log_request(NwGtpv1uLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT *file, + NwU32T line, + NwCharT *logStr) +{ + logIt(GTPU, logLevel, "%s\n", logStr); + return NW_GTPV1U_OK; +} + +/* Callback called when a gtpv1u message arrived on UDP interface */ +NwGtpv1uRcT gtpv1u_process_stack_req( + NwGtpv1uUlpHandleT hUlp, + NwGtpv1uUlpApiT *pUlpApi) +{ + switch(pUlpApi->apiType) { + /* Here there are two type of messages handled: + * - T-PDU + * - END-MARKER + */ + case NW_GTPV1U_ULP_API_RECV_TPDU: { + uint8_t buffer[4096]; + uint32_t buffer_len; + + /* Nw-gptv1u stack has processed a PDU. we can schedule it to PDCP + * for transmission. + */ + if (NW_GTPV1U_OK != nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg, + buffer, &buffer_len)) { + GTPU_ERROR("Error while retrieving T-PDU"); + } + GTPU_DEBUG("Received T-PDU from gtpv1u stack %u with size %d", + pUlpApi->apiInfo.recvMsgInfo.teid, buffer_len); + + pdcp_data_req(0, // module_id, + 0, // frame + 1, // enb flag + 5, // rb id + 0, // mui + 0, // confirm + buffer_len, + buffer, + 1); + } + break; + default: { + GTPU_ERROR("Received undefined UlpApi (%02x) from gtpv1u stack!\n", + pUlpApi->apiType); + } + } + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT gtpv1u_eNB_udp_req(NwGtpv1uUdpHandleT udpHandle, + NwU8T *dataBuf, + NwU32T dataSize, + NwU32T peerIpAddr, + NwU16T peerPort) +{ + udp_data_t *udp_data_p; + + if (udpHandle == 0) { + return NW_GTPV1U_FAILURE; + } + + udp_data_p = (udp_data_t *)udpHandle; + + LOG_D(GTPU, "New udp req triggered with sd %d, data size %u\n", + udp_data_p->sd, dataSize); + + if (udp_send_to(udp_data_p->sd, peerPort, peerIpAddr, dataBuf, dataSize) < 0) { + return NW_GTPV1U_FAILURE; + } + + return NW_GTPV1U_OK; +} + +int data_recv_callback(uint16_t port, + uint32_t address, + uint8_t *buffer, + uint32_t length, + void *arg_p) +{ + gtpv1u_data_t *gtpv1u_data_p; + + if (arg_p == NULL) { + return -1; + } + + gtpv1u_data_p = (gtpv1u_data_t *)arg_p; + + return nwGtpv1uProcessUdpReq(gtpv1u_data_p->gtpv1u_stack, + buffer, + length, + port, + address); +} + +int gtpv1u_create_tunnel_endpoint(gtpv1u_data_t *gtpv1u_data_p, uint8_t ue_id, + uint8_t rab_id, char *sgw_ip_addr, uint16_t port) +{ + uint32_t teid; + uint8_t max_attempt = 100; + NwGtpv1uRcT rc; + NwGtpv1uUlpApiT ulp_req; + struct gtpv1u_ue_data_s *new_ue_p; + struct gtpv1u_ue_data_s *temp; + struct gtpv1u_bearer_s *bearer; + hashtbl_rc_t hash_rc; + + if (rab_id > MAX_BEARERS_PER_UE) { + LOG_E(GTPU, "Could not use rab_id %d > max %d\n", + rab_id, MAX_BEARERS_PER_UE); + return -1; + } + + + if ((hash_rc = hashtbl_get(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, (void**)&new_ue_p)) == HASH_TABLE_OK) { + /* A context for this UE already exist in the tree, use it */ + /* We check that the tunnel is not already configured */ + if (new_ue_p->bearers[rab_id].state != BEARER_DOWN) { + LOG_E(GTPU, "Cannot create new end-point over already existing tunnel\n"); + return -1; + } + } else { + /* Context doesn't exist, create it */ + if (rab_id != 0) { + /* UE should first establish Default bearer before trying to setup + * additional bearers. + */ + LOG_E(GTPU, "UE context is not known and rab_id != 0\n"); + return -1; + } + new_ue_p = calloc(1, sizeof(struct gtpv1u_ue_data_s)); + new_ue_p->ue_id = ue_id; + + hash_rc = hashtbl_insert(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, new_ue_p); + + if ((hash_rc != HASH_TABLE_OK) && (hash_rc != HASH_TABLE_INSERT_OVERWRITTEN_DATA)) { + LOG_E(GTPU, "Failed to insert new UE context\n"); + free(new_ue_p); + return -1; + } + } + + bearer = &new_ue_p->bearers[rab_id]; + + /* Configure the bearer */ + bearer->state = BEARER_IN_CONFIG; + bearer->sgw_ip_addr = inet_addr(sgw_ip_addr); + bearer->port = port; + + /* Create the new stack api request */ + memset(&ulp_req, 0, sizeof(NwGtpv1uUlpApiT)); + ulp_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT; + + /* Try to create new tunnel-endpoint. + * If teid generated is already present in the stack, just peek another random + * teid. This could be ok for small number of tunnel but more errors could be + * thrown if we reached high number of tunnels. + * TODO: find a solution for teid + */ + do { + /* Request for a new random TEID */ + teid = gtpv1u_new_teid(); + ulp_req.apiInfo.createTunnelEndPointInfo.teid = teid; + + rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack, &ulp_req); + + if (rc == NW_GTPV1U_OK) { +// LOG_D(GTPU, "Successfully created new tunnel endpoint for teid 0x%x\n", +// teid); + bearer->teid_eNB = teid; +// gtpv1u_initial_req(gtpv1u_data_p, teid, GTPV1U_UDP_PORT, +// inet_addr("192.168.56.101")); + LOG_I(GTPU, "Created eNB tunnel endpoint %u for ue id %u, rab id %u\n", teid, ue_id, rab_id); + return 0; + } else { + LOG_W(GTPU, "Teid %u already in use... %s\n", + teid, (max_attempt > 1) ? "Trying another one" : "Last chance"); + } + } while(max_attempt-- && rc != NW_GTPV1U_OK); + + bearer->state = BEARER_DOWN; + LOG_I(GTPU, "Failed to created eNB tunnel endpoint %u for ue id %u, rab id %u, bearer down\n", teid, ue_id, rab_id); + + return -1; +} + +int gtpv1u_initial_req(gtpv1u_data_t *gtpv1u_data_p, uint32_t teid, + uint16_t port, uint32_t address) +{ + NwGtpv1uUlpApiT ulp_req; + NwGtpv1uRcT rc; + + memset(&ulp_req, 0, sizeof(NwGtpv1uUlpApiT)); + + ulp_req.apiType = NW_GTPV1U_ULP_API_INITIAL_REQ; + ulp_req.apiInfo.initialReqInfo.teid = teid; + ulp_req.apiInfo.initialReqInfo.peerPort = port; + ulp_req.apiInfo.initialReqInfo.peerIp = address; + + rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack, &ulp_req); + if (rc == NW_GTPV1U_OK) { + LOG_D(GTPU, "Successfully sent initial req for teid %u\n", teid); + } else { + LOG_W(GTPU, "Could not send initial req for teid %u\n", teid); + } + return (rc == NW_GTPV1U_OK) ? 0 : -1; +} + +int gtpv1u_new_data_req(gtpv1u_data_t *gtpv1u_data_p, + uint8_t ue_id, uint8_t rab_id, + uint8_t *buffer, uint32_t buf_len) +{ +#ifdef GTPU_IN_KERNEL + struct sockaddr_in dummy_dest_addr; + socklen_t socklen = sizeof(struct sockaddr_in); +#endif + NwGtpv1uUlpApiT stack_req; + NwGtpv1uRcT rc; + struct gtpv1u_ue_data_s ue; + struct gtpv1u_ue_data_s *ue_inst_p; + struct gtpv1u_bearer_s *bearer_p; + hashtbl_rc_t hash_rc; + + memset(&ue, 0, sizeof(struct gtpv1u_ue_data_s)); + + ue.ue_id = ue_id; + + assert(gtpv1u_data_p != NULL); + assert(rab_id <= MAX_BEARERS_PER_UE); + + /* Check that UE context is present in ue map. */ + hash_rc = hashtbl_get(gtpv1u_data_p->ue_mapping, (uint64_t)ue_id, (void**)&ue_inst_p); + + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS ) { + LOG_E(GTPU, "[UE %d] Trying to send data on non-existing UE context\n", ue_id); + return -1; + } + + bearer_p = &ue_inst_p->bearers[rab_id]; + + /* Ensure the bearer in ready. + * TODO: handle the cases where the bearer is in HANDOVER state. + * In such case packets should be placed in FIFO. + */ + if (bearer_p->state != BEARER_UP) { + LOG_W(GTPU, "Trying to send data over bearer with state(%u) != BEARER_UP\n", + bearer_p->state); +#warning LG: HACK WHILE WAITING FOR NAS, normally return -1 + if (bearer_p->state != BEARER_IN_CONFIG) + return -1; + } +#ifdef GTPU_IN_KERNEL + dummy_dest_addr.sin_family = AF_INET; + dummy_dest_addr.sin_port = 5001; + dummy_dest_addr.sin_addr.s_addr = inet_addr("178.179.180.181"); + if (sendto(gtpv1u_data_p->sock_desc[rab_id], (void *)buffer, buf_len, 0, (struct sockaddr *)&dummy_dest_addr, socklen) < 0) { + LOG_E(GTPU, "Error during send to socket %d : (%s:%d)\n", gtpv1u_data_p->sock_desc[rab_id], strerror(errno), errno); + return -1; + } else { + LOG_D(GTPU, "send to UDP socket %d, packet should be handled by iptables\n", gtpv1u_data_p->sock_desc[rab_id]); + } +#else + + memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT)); + + stack_req.apiType = NW_GTPV1U_ULP_API_SEND_TPDU; + // LG HACK stack_req.apiInfo.sendtoInfo.teid = bearer_p->teid_sgw; + stack_req.apiInfo.sendtoInfo.teid = 1;// LG HACK + stack_req.apiInfo.sendtoInfo.ipAddr = bearer_p->sgw_ip_addr; + + rc = nwGtpv1uGpduMsgNew(gtpv1u_data_p->gtpv1u_stack, + //bearer_p->teid_sgw, + 1, // LG FORCING 1 instead of bearer_p->teid_sgw + NW_FALSE, + gtpv1u_data_p->seq_num++, + buffer, + buf_len, + &(stack_req.apiInfo.sendtoInfo.hMsg)); + + if (rc != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uGpduMsgNew failed: 0x%x\n", rc); + return -1; + } + rc = nwGtpv1uProcessUlpReq(gtpv1u_data_p->gtpv1u_stack, + &stack_req); + if (rc != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uProcessUlpReq failed: 0x%x\n", rc); + return -1; + } + rc = nwGtpv1uMsgDelete(gtpv1u_data_p->gtpv1u_stack, + stack_req.apiInfo.sendtoInfo.hMsg); + if (rc != NW_GTPV1U_OK) { + LOG_E(GTPU, "nwGtpv1uMsgDelete failed: 0x%x\n", rc); + return -1; + } +#endif + LOG_E(GTPU, "%s() return code OK\n", __FUNCTION__); + return 0; +} + +#ifdef GTPU_IN_KERNEL + +#undef GTPV1U_PACKET_RX_RING +/// The number of frames in the ring +// This number is not set in stone. Nor are block_size, block_nr or frame_size +#define CONF_RING_FRAMES 128 + +/// Offset of data from start of frame +#define PKT_OFFSET (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + \ + TPACKET_ALIGN(sizeof(struct sockaddr_ll))) + +int gtpv1u_eNB_create_sockets(gtpv1u_data_t *gtpv1u_data_p) +{ + int value, mark; + const int *val_p=&value; + struct ifreq ifr; +#ifdef GTPV1U_PACKET_RX_RING + struct tpacket_req tp; +#endif + int i; + + if (gtpv1u_data_p == NULL) { + return -1; + } + + GTPU_DEBUG("Creating socket for GTPV1U on %s if index %u\n", gtpv1u_data_p->interface_name, gtpv1u_data_p->interface_index); + + for (mark = 0; mark <= 15; mark++) { + + gtpv1u_data_p->sock_desc[mark] = socket( PF_INET , SOCK_DGRAM, 0); + if (gtpv1u_data_p->sock_desc[mark] < 0) { + GTPU_ERROR("Error during socket creation (%s:%d)\n",strerror(errno), errno); + goto error; + } + +// // socket options, tell the kernel we provide the IP structure +// if(setsockopt(sgi_data_p->sd[rab_id], IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) +// { +// SGI_IF_ERROR("Error during socket setsockopt IP_HDRINCL (%s:%d)\n", strerror(errno), errno); +// goto error; +// } +// +// + // setting socket option to use MARK value + //value = rab_id + SGI_MIN_EPS_BEARER_ID; + value = mark; + if (setsockopt (gtpv1u_data_p->sock_desc[mark], SOL_SOCKET, SO_MARK, val_p, sizeof (value)) < 0) + { + GTPU_ERROR("error notifying kernel about MARK"); + goto error; + } + GTPU_DEBUG("Created socket %d for rab_id %d (for any UE context)\n", gtpv1u_data_p->sock_desc[mark], value); + +#ifdef SGI_PACKET_RX_RING + // tell kernel to export data through mmap()ped ring + tp.tp_block_size = CONF_RING_FRAMES * getpagesize(); + tp.tp_block_nr = 1; + tp.tp_frame_size = getpagesize(); + tp.tp_frame_nr = CONF_RING_FRAMES; + + if (setsockopt(gtpv1u_data_p->sock_desc[mark], SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp))) { + GTPU_ERROR("setsockopt() ring\n"); + goto error; + } + + // open ring + gtpv1u_data_p->sock_mmap_ring[mark] = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sgi_data_p->sd[mark], 0); + if (!gtpv1u_data_p->sock_mmap_ring[mark]) { + GTPU_ERROR("Failed to mmap socket (%s:%d)\n", strerror(errno), errno); + goto error; + } + /* Setup our ringbuffer */ + gtpv1u_data_p->malloc_ring[mark] = malloc(tp.tp_frame_nr * sizeof(struct iovec)); + for(i=0; i<tp.tp_frame_nr; i++) { + gtpv1u_data_p->malloc_ring[mark][i].iov_base=(void *)((long)gtpv1u_data_p->sock_mmap_ring[mark])+(i*tp.tp_frame_size); + gtpv1u_data_p->malloc_ring[mark][i].iov_len=tp.tp_frame_size; + } + +#endif + + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), gtpv1u_data_p->interface_name); + if (setsockopt (gtpv1u_data_p->sock_desc[mark], SOL_SOCKET, SO_BINDTODEVICE,(void *)&ifr, sizeof(ifr)) < 0) + { + GTPU_ERROR("error notifying kernel about MARK"); + goto error; + } + GTPU_DEBUG("Created socket %d for rab_id %d (for any UE context)\n", gtpv1u_data_p->sock_desc[mark], value); + } + return 0; +error: + GTPU_ERROR("ERROR (%s)\n", strerror(errno)); + for (mark = 0; mark <= 15; mark++) { + if (gtpv1u_data_p->sock_desc[mark] > 0) { + close(gtpv1u_data_p->sock_desc[mark]); + } + gtpv1u_data_p->sock_desc[mark] = -1; + } + return -1; +} +#endif + +int gtpv1u_eNB_init(gtpv1u_data_t *gtpv1u_data_p) +{ + NwGtpv1uRcT rc; + NwGtpv1uLogMgrEntityT log; + NwGtpv1uUdpEntityT udp; + NwGtpv1uUlpEntityT ulp; + + if (gtpv1u_data_p == NULL) { + return -1; + } + + //(gtpv1u_data_p was allocated with calloc (zeroed)) + +// GTPU_INFO("Initializing GTPU stack for eNB %u\n", +// gtpv1u_data_p->eNB_id); + + /* Initialize UE tree */ + //RB_INIT(>pv1u_data_p->gtpv1u_ue_map_head); + +#ifdef GTPU_IN_KERNEL +#warning hardcoded ENB GTPV1U interface name + gtpv1u_data_p->interface_name = "upenb0"; + gtpv1u_data_p->interface_index = if_nametoindex(gtpv1u_data_p->interface_name); + + gtpv1u_eNB_create_sockets(gtpv1u_data_p); +#endif + /* Initialize UE hashtable */ + gtpv1u_data_p->ue_mapping = hashtbl_create (256, NULL, NULL); + if (gtpv1u_data_p->ue_mapping == NULL) { + perror("hashtbl_create"); + GTPU_ERROR("Initializing TASK_GTPV1_U task interface: ERROR\n"); + return -1; + } + + if (udp_create_connection(gtpv1u_data_p->ip_addr, GTPV1U_UDP_PORT, + >pv1u_data_p->udp_data, data_recv_callback, (void *)gtpv1u_data_p) < 0) { + return -1; + } + + /* Initializing GTPv1-U stack */ + if ((rc = nwGtpv1uInitialize(>pv1u_data_p->gtpv1u_stack)) != NW_GTPV1U_OK) { + GTPU_ERROR("Failed to setup nwGtpv1u stack %x\n", rc); + return -1; + } + + /* Set up the log interface and register the log entity */ + log.logReqCallback = gtpv1u_eNB_log_request; + + if ((rc = nwGtpv1uSetLogMgrEntity(gtpv1u_data_p->gtpv1u_stack, + &log)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetLogMgrEntity: %x\n", rc); + return -1; + } + + udp.hUdp = (NwGtpv1uUdpHandleT) >pv1u_data_p->udp_data; + udp.udpDataReqCallback = gtpv1u_eNB_udp_req; + + if ((rc = nwGtpv1uSetUdpEntity(gtpv1u_data_p->gtpv1u_stack, + &udp)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetUdpEntity: %x\n", rc); + return -1; + } + + /* Set the ULP API callback. Called once message have been processed by the + * nw-gtpv1u stack. + */ + ulp.ulpReqCallback = gtpv1u_process_stack_req; + + if ((rc = nwGtpv1uSetUlpEntity(gtpv1u_data_p->gtpv1u_stack, + &ulp)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetUlpEntity: %x\n", rc); + return -1; + } + + if ((rc = nwGtpv1uSetLogLevel(gtpv1u_data_p->gtpv1u_stack, + NW_LOG_LEVEL_DEBG)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetLogLevel: %x\n", rc); + return -1; + } + + gtpv1u_create_tunnel_endpoint(gtpv1u_data_p, 0, 0, "192.168.1.1", 2152); + +// GTPU_INFO("Initializing GTPU stack for eNB %u: DONE\n", +// gtpv1u_data_p->eNB_id); + + return 0; +} diff --git a/openair-cn/GTPV1-U/gtpv1u_eNB_defs.h b/openair-cn/GTPV1-U/gtpv1u_eNB_defs.h new file mode 100644 index 0000000000..657ada3815 --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u_eNB_defs.h @@ -0,0 +1,86 @@ +#include "NwGtpv1u.h" +#include "gtpv1u.h" +#include "udp_primitives_client.h" +#include "hashtable.h" + +//TEST LG #define GTPU_IN_KERNEL + +//#include "tree.h" + +#ifndef GTPV1U_ENB_DEFS_H_ +#define GTPV1U_ENB_DEFS_H_ + +#define GTPV1U_UDP_PORT (2152) + +#define MAX_BEARERS_PER_UE (11) + +typedef enum { + BEARER_DOWN = 0, + BEARER_IN_CONFIG, + BEARER_UP, + BEARER_DL_HANDOVER, + BEARER_UL_HANDOVER, + BEARER_MAX, +} bearer_state_t; + +typedef struct gtpv1u_bearer_s { + /* TEID used in dl and ul */ + uint32_t teid_eNB; ///< eNB TEID + uint32_t teid_sgw; ///< Remote TEID + uint32_t sgw_ip_addr; + uint16_t port; + NwGtpv1uStackSessionHandleT stack_session; + bearer_state_t state; +} gtpv1u_bearer_t; + +typedef struct gtpv1u_ue_data_s { + /* UE identifier for oaisim stack */ + uint8_t ue_id; + + /* Unique identifier used between PDCP and GTP-U to distinguish UEs */ + uint32_t instance_id; + + /* Bearer related data. + * Note that the first LCID available for data is 3 and we fixed the maximum + * number of e-rab per UE to be 11. The real rb id will 3 + rab_id (0..10). + */ + gtpv1u_bearer_t bearers[MAX_BEARERS_PER_UE]; + + //RB_ENTRY(gtpv1u_ue_data_s) gtpv1u_ue_node; +} gtpv1u_ue_data_t; + +typedef struct gtpv1u_data_s{ + /* nwgtpv1u stack internal data */ + NwGtpv1uStackHandleT gtpv1u_stack; + /* RB tree of UEs */ + hash_table_t *ue_mapping; + + //RB_HEAD(gtpv1u_ue_map, gtpv1u_ue_data_s) gtpv1u_ue_map_head; + /* Local IP address to use */ + char *ip_addr; + /* UDP internal data */ + udp_data_t udp_data; + + uint16_t seq_num; + uint8_t restart_counter; + +#ifdef GTPU_IN_KERNEL + char *interface_name; + int interface_index; + + struct iovec *malloc_ring; + void *sock_mmap_ring[16]; + int sock_desc[16]; // indexed by marking +#endif +} gtpv1u_data_t; + +int gtpv1u_new_data_req(gtpv1u_data_t *gtpv1u_data_p, + uint8_t ue_id, uint8_t rab_id, + uint8_t *buffer, uint32_t buf_len); + +int gtpv1u_initial_req(gtpv1u_data_t *gtpv1u_data_p, uint32_t teid, + uint16_t port, uint32_t address); + +int gtpv1u_eNB_init(gtpv1u_data_t *gtpv1u_data_p); + +#endif /* GTPV1U_ENB_DEFS_H_ */ diff --git a/openair-cn/GTPV1-U/gtpv1u_sgw_defs.h b/openair-cn/GTPV1-U/gtpv1u_sgw_defs.h new file mode 100644 index 0000000000..86768577e7 --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u_sgw_defs.h @@ -0,0 +1,78 @@ +#ifndef GTPV1U_SGW_DEFS_H_ +#define GTPV1U_SGW_DEFS_H_ + +#include "mme_config.h" +#include "NwGtpv1u.h" +#include "gtpv1u.h" +#include "hashtable.h" +#include "common_types.h" + +#define GTPV1U_UDP_PORT (2152) + +#define MAX_BEARERS_PER_UE (11) + +typedef enum { + BEARER_DOWN = 0, + BEARER_IN_CONFIG, + BEARER_UP, + BEARER_DL_HANDOVER, + BEARER_UL_HANDOVER, + BEARER_MAX, +} bearer_state_t; + +#define BUFFER_TO_NwU32T(buf, x) \ +do { \ + x = ((NwU32T)((buf)[0]) ) | \ + ((NwU32T)((buf)[1]) << 8) | \ + ((NwU32T)((buf)[2]) << 16) | \ + ((NwU32T)((buf)[3]) << 24); \ +} while(0) + + + +typedef struct gtpv1u_teid2enb_info_s { + /* TEID used in dl and ul */ + uint32_t teid_enb; ///< Remote eNB TEID + ip_address_t enb_ip_addr; + bearer_state_t state; + uint16_t port; /// LG ??? +} gtpv1u_teid2enb_info_t; + +/*struct gtpv1u_ue_data_s { + // UE identifier for oaisim stack + uint8_t ue_id; + + // Unique identifier used between PDCP and GTP-U to distinguish UEs + uint32_t instance_id; + + // Bearer related data. + // Note that the first LCID available for data is 3 and we fixed the maximum + // number of e-rab per UE to be 11. The real rb id will 3 + rab_id (0..10). + // + struct gtpv1u_bearer_s bearers[MAX_BEARERS_PER_UE]; + + RB_ENTRY(gtpv1u_ue_data_s) gtpv1u_ue_node; +};*/ + +typedef struct { + /* nwgtpv1u stack internal data */ + NwGtpv1uStackHandleT gtpv1u_stack; + /* RB tree of UEs */ + //RB_HEAD(gtpv1u_ue_map, gtpv1u_ue_data_s) gtpv1u_ue_map_head; + /* Local IP address to use */ + uint32_t sgw_ip_address_for_S1u_S12_S4_up; + char *ip_addr; + /* UDP internal data */ + //udp_data_t udp_data; + + uint16_t seq_num; + uint8_t restart_counter; + //gtpv1u_teid2enb_info_t* teid2enb_mapping[]; + hash_table_t *S1U_mapping; + +} gtpv1u_data_t; + + +int gtpv1u_init(const mme_config_t *mme_config); + +#endif /* GTPV1U_SGW_DEFS_H_ */ diff --git a/openair-cn/GTPV1-U/gtpv1u_task.c b/openair-cn/GTPV1-U/gtpv1u_task.c new file mode 100644 index 0000000000..6ffdee3df9 --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u_task.c @@ -0,0 +1,553 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "mme_config.h" + +#include "assertions.h" +#include "intertask_interface.h" +#include "timer.h" + +#include "gtpv1u.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uMsg.h" +#include "NwLog.h" +#include "gtpv1u_sgw_defs.h" + +//static NwGtpv1uStackHandleT gtpv1u_stack = 0; +static gtpv1u_data_t gtpv1u_sgw_data; + +static int gtpv1u_send_init_udp(uint16_t port_number); +static int gtpv1u_create_s1u_tunnel(Gtpv1uCreateTunnelReq *create_tunnel_reqP); +static int gtpv1u_delete_s1u_tunnel(Teid_t context_teidP, Teid_t S1U_teidP); +static int gtpv1u_update_s1u_tunnel(Gtpv1uUpdateTunnelReq *reqP); +static void *gtpv1u_thread(void *args); + +NwGtpv1uRcT gtpv1u_send_udp_msg( + NwGtpv1uUdpHandleT udpHandle, + NwU8T *buffer, + NwU32T buffer_len, + NwU32T peerIpAddr, + NwU32T peerPort); + +NwGtpv1uRcT gtpv1u_log_request( + NwGtpv1uLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT *file, + NwU32T line, + NwCharT *logStr); + +NwGtpv1uRcT gtpv1u_process_stack_req( + NwGtpv1uUlpHandleT hUlp, + NwGtpv1uUlpApiT *pUlpApi); + +static int gtpv1u_send_init_udp(uint16_t port_number) +{ + // Create and alloc new message + MessageDef *message_p; + struct in_addr addr; + + message_p = alloc_new_message(TASK_GTPV1_U, UDP_INIT); + if (message_p == NULL) { + return -1; + } + + message_p->msg.udp_init.port = port_number; + //LG message_p->msg.udp_init.address = "0.0.0.0"; //ANY address + + addr.s_addr = gtpv1u_sgw_data.sgw_ip_address_for_S1u_S12_S4_up; + message_p->msg.udp_init.address = inet_ntoa(addr); + GTPU_DEBUG("Tx UDP_INIT IP addr %s\n", message_p->msg.udp_init.address); + + return send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); +} + +NwGtpv1uRcT gtpv1u_log_request(NwGtpv1uLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT *file, + NwU32T line, + NwCharT *logStr) +{ + GTPU_DEBUG("%s\n", logStr); + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT gtpv1u_send_udp_msg( + NwGtpv1uUdpHandleT udpHandle, + NwU8T *buffer, + NwU32T buffer_len, + NwU32T peerIpAddr, + NwU32T peerPort) +{ + // Create and alloc new message + MessageDef *message_p; + udp_data_req_t *udp_data_req_p; + + message_p = alloc_new_message(TASK_GTPV1_U, UDP_DATA_REQ); + + udp_data_req_p = &message_p->msg.udp_data_req; + + udp_data_req_p->peer_address = peerIpAddr; + udp_data_req_p->peer_port = peerPort; + udp_data_req_p->buffer = buffer; + udp_data_req_p->buffer_length = buffer_len; + + return send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); +} + +/* Callback called when a gtpv1u message arrived on UDP interface */ +NwGtpv1uRcT gtpv1u_process_stack_req( + NwGtpv1uUlpHandleT hUlp, + NwGtpv1uUlpApiT *pUlpApi) +{ + switch(pUlpApi->apiType) { + /* Here there are two type of messages handled: + * - T-PDU + * - END-MARKER + */ + case NW_GTPV1U_ULP_API_RECV_TPDU: { + uint8_t buffer[4096]; + uint32_t buffer_len; + MessageDef *message_p; + Gtpv1uTunnelDataInd *data_ind_p; + + /* Nw-gptv1u stack has processed a PDU. we can forward it to IPV4 + * task for transmission. + */ + if (NW_GTPV1U_OK != nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg, + buffer, (NwU32T *)&buffer_len)) { + GTPU_ERROR("Error while retrieving T-PDU"); + } + GTPU_DEBUG("Received TPDU from gtpv1u stack %u with size %d", pUlpApi->apiInfo.recvMsgInfo.teid, buffer_len); + + message_p = alloc_new_message(TASK_GTPV1_U, GTPV1U_TUNNEL_DATA_IND); + if (message_p == NULL) { + return -1; + } + data_ind_p = &message_p->msg.gtpv1uTunnelDataInd; + data_ind_p->buffer = malloc(sizeof(uint8_t) * buffer_len); + data_ind_p->local_S1u_teid = pUlpApi->apiInfo.recvMsgInfo.teid; + if (data_ind_p->buffer == NULL) { + GTPU_ERROR("Failed to allocate new buffer\n"); + free(message_p); + } else { + memcpy(data_ind_p->buffer, buffer, buffer_len); + data_ind_p->length = buffer_len; + if (send_msg_to_task(TASK_FW_IP, INSTANCE_DEFAULT, message_p) < 0) { + GTPU_ERROR("Failed to send message to task\n"); + free(message_p); + } + } + } + break; + + case NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT:{ + } + break; + + default: { + GTPU_ERROR("Received undefined UlpApi (%02x) from gtpv1u stack!\n", + pUlpApi->apiType); + } + } + return NW_GTPV1U_OK; +} + +static int gtpv1u_create_s1u_tunnel(Gtpv1uCreateTunnelReq *create_tunnel_reqP) +{ + /* Create a new nw-gtpv1-u stack req using API */ + NwGtpv1uUlpApiT stack_req; + NwGtpv1uRcT rc; + /* Local tunnel end-point identifier */ + uint32_t s1u_teid; + gtpv1u_teid2enb_info_t *gtpv1u_teid2enb_info; + MessageDef *message_p; + hashtbl_rc_t hash_rc; + + GTPU_DEBUG("Rx GTPV1U_CREATE_TUNNEL_REQ Context %d\n", create_tunnel_reqP->context_teid); + memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT)); + + stack_req.apiType = NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT; + + do { + s1u_teid = gtpv1u_new_teid(); + GTPU_DEBUG("gtpv1u_create_s1u_tunnel() %u\n", s1u_teid); + stack_req.apiInfo.createTunnelEndPointInfo.teid = s1u_teid; + stack_req.apiInfo.createTunnelEndPointInfo.hUlpSession = 0; + stack_req.apiInfo.createTunnelEndPointInfo.hStackSession = 0; + + rc = nwGtpv1uProcessUlpReq(gtpv1u_sgw_data.gtpv1u_stack, &stack_req); + GTPU_DEBUG(".\n"); + } while (rc != NW_GTPV1U_OK); + + gtpv1u_teid2enb_info = malloc (sizeof(gtpv1u_teid2enb_info_t)); + memset(gtpv1u_teid2enb_info, 0, sizeof(gtpv1u_teid2enb_info_t)); + gtpv1u_teid2enb_info->state = BEARER_IN_CONFIG; + +#warning !!! hack because missing modify session request, so force enb address + gtpv1u_teid2enb_info->enb_ip_addr.pdn_type = IPv4; + gtpv1u_teid2enb_info->enb_ip_addr.address.ipv4_address[0] = 192; + gtpv1u_teid2enb_info->enb_ip_addr.address.ipv4_address[1] = 168; + gtpv1u_teid2enb_info->enb_ip_addr.address.ipv4_address[2] = 1; + gtpv1u_teid2enb_info->enb_ip_addr.address.ipv4_address[3] = 2; + gtpv1u_teid2enb_info->state = BEARER_IN_CONFIG; + + + message_p = alloc_new_message(TASK_GTPV1_U, GTPV1U_CREATE_TUNNEL_RESP); + message_p->msg.gtpv1uCreateTunnelResp.S1u_teid = s1u_teid; + message_p->msg.gtpv1uCreateTunnelResp.context_teid = create_tunnel_reqP->context_teid; + message_p->msg.gtpv1uCreateTunnelResp.eps_bearer_id = create_tunnel_reqP->eps_bearer_id; + + hash_rc = hashtbl_is_key_exists(gtpv1u_sgw_data.S1U_mapping, s1u_teid); + + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + hash_rc = hashtbl_insert(gtpv1u_sgw_data.S1U_mapping, s1u_teid, gtpv1u_teid2enb_info); + message_p->msg.gtpv1uCreateTunnelResp.status = 0; + } else { + message_p->msg.gtpv1uCreateTunnelResp.status = 0xFF; + } + + GTPU_DEBUG("Tx GTPV1U_CREATE_TUNNEL_RESP Context %u teid %u eps bearer id %u status %d\n", + message_p->msg.gtpv1uCreateTunnelResp.context_teid, + message_p->msg.gtpv1uCreateTunnelResp.S1u_teid, + message_p->msg.gtpv1uCreateTunnelResp.eps_bearer_id, + message_p->msg.gtpv1uCreateTunnelResp.status); + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + + + +static int gtpv1u_delete_s1u_tunnel(Teid_t context_teidP, Teid_t S1U_teidP) +{ + /* Local tunnel end-point identifier */ + MessageDef *message_p; + + GTPU_DEBUG("Rx GTPV1U_DELETE_TUNNEL Context %u S1U teid %u\n", context_teidP, S1U_teidP); + message_p = alloc_new_message(TASK_GTPV1_U, GTPV1U_DELETE_TUNNEL_RESP); + + message_p->msg.gtpv1uDeleteTunnelResp.S1u_teid = S1U_teidP; + message_p->msg.gtpv1uDeleteTunnelResp.context_teid = context_teidP; + + if (hashtbl_remove(gtpv1u_sgw_data.S1U_mapping, S1U_teidP) == HASH_TABLE_OK ) { + message_p->msg.gtpv1uDeleteTunnelResp.status = 0; + } else { + message_p->msg.gtpv1uDeleteTunnelResp.status = -1; + } + GTPU_DEBUG("Tx SGW_S1U_ENDPOINT_CREATED Context %u teid %u status %d\n", context_teidP, S1U_teidP, message_p->msg.gtpv1uDeleteTunnelResp.status); + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + + +static int gtpv1u_update_s1u_tunnel(Gtpv1uUpdateTunnelReq *reqP) +{ + hashtbl_rc_t hash_rc; + gtpv1u_teid2enb_info_t *gtpv1u_teid2enb_info; + MessageDef *message_p; + + GTPU_DEBUG("Rx GTPV1U_UPDATE_TUNNEL_REQ Context %u, S-GW S1U teid %u, eNB S1U teid %u\n", + reqP->context_teid, + reqP->sgw_S1u_teid, + reqP->enb_S1u_teid); + message_p = alloc_new_message(TASK_GTPV1_U, GTPV1U_UPDATE_TUNNEL_RESP); + + hash_rc = hashtbl_get(gtpv1u_sgw_data.S1U_mapping, reqP->sgw_S1u_teid, (void**)>pv1u_teid2enb_info); + + if (hash_rc == HASH_TABLE_OK) { + gtpv1u_teid2enb_info->teid_enb = reqP->enb_S1u_teid; + gtpv1u_teid2enb_info->enb_ip_addr = reqP->enb_ip_address_for_S1u; + gtpv1u_teid2enb_info->state = BEARER_UP; + gtpv1u_teid2enb_info->port = GTPV1U_UDP_PORT; + message_p->msg.gtpv1uUpdateTunnelResp.status = 0; ///< Status (Failed = 0xFF or Success = 0x0) + } else { + GTPU_ERROR("Mapping not found\n"); + message_p->msg.gtpv1uUpdateTunnelResp.status = 0xFF; ///< Status (Failed = 0xFF or Success = 0x0) + } + message_p->msg.gtpv1uUpdateTunnelResp.context_teid = reqP->context_teid; + message_p->msg.gtpv1uUpdateTunnelResp.sgw_S1u_teid = reqP->sgw_S1u_teid; + message_p->msg.gtpv1uUpdateTunnelResp.enb_S1u_teid = reqP->enb_S1u_teid; + message_p->msg.gtpv1uUpdateTunnelResp.eps_bearer_id = reqP->eps_bearer_id; + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + + +static NwGtpv1uRcT gtpv1u_start_timer_wrapper( + NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void *timeoutArg, + NwGtpv1uTimerHandleT *hTmr) +{ + + NwGtpv1uRcT rc = NW_GTPV1U_OK; + long timer_id; + + if (tmrType == NW_GTPV1U_TMR_TYPE_ONE_SHOT) { + timer_setup(timeoutSec, + timeoutUsec, + TASK_GTPV1_U, + INSTANCE_DEFAULT, + TIMER_ONE_SHOT, + timeoutArg, + &timer_id); + } else { + timer_setup(timeoutSec, + timeoutUsec, + TASK_GTPV1_U, + INSTANCE_DEFAULT, + TIMER_PERIODIC, + timeoutArg, + &timer_id); + } + + return rc; +} + +static NwGtpv1uRcT gtpv1u_stop_timer_wrapper( + NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwGtpv1uTimerHandleT hTmr) +{ + + NwGtpv1uRcT rc = NW_GTPV1U_OK; + + return rc; +} + +static void *gtpv1u_thread(void *args) +{ + intertask_interface_mark_task_ready(TASK_GTPV1_U); + while(1) { + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + MessageDef *received_message_p = NULL; + receive_msg(TASK_GTPV1_U, &received_message_p); + DevAssert(received_message_p != NULL); + + switch(received_message_p->header.messageId) { + case GTPV1U_CREATE_TUNNEL_REQ: { + gtpv1u_create_s1u_tunnel(&received_message_p->msg.gtpv1uCreateTunnelReq); + } + break; + + case GTPV1U_DELETE_TUNNEL_REQ: { + gtpv1u_delete_s1u_tunnel(received_message_p->msg.gtpv1uDeleteTunnelReq.context_teid, received_message_p->msg.gtpv1uDeleteTunnelReq.S1u_teid); + } + break; + + case GTPV1U_UPDATE_TUNNEL_REQ: { + gtpv1u_update_s1u_tunnel(&received_message_p->msg.gtpv1uUpdateTunnelReq); + } + break; + + // DATA COMING FROM UDP + case UDP_DATA_IND: { + udp_data_ind_t *udp_data_ind_p; + udp_data_ind_p = &received_message_p->msg.udp_data_ind; + nwGtpv1uProcessUdpReq(gtpv1u_sgw_data.gtpv1u_stack, + udp_data_ind_p->buffer, + udp_data_ind_p->buffer_length, + udp_data_ind_p->peer_port, + udp_data_ind_p->peer_address); + free(udp_data_ind_p->buffer); + } + break; + + // DATA TO BE SENT TO UDP + case GTPV1U_TUNNEL_DATA_REQ: { + Gtpv1uTunnelDataReq *data_req_p; + NwGtpv1uUlpApiT stack_req; + NwGtpv1uRcT rc; + hashtbl_rc_t hash_rc; + gtpv1u_teid2enb_info_t *gtpv1u_teid2enb_info; + + data_req_p = &received_message_p->msg.gtpv1uTunnelDataReq; + //ipv4_send_data(ipv4_data_p->sd, data_ind_p->buffer, data_ind_p->length); + + memset(&stack_req, 0, sizeof(NwGtpv1uUlpApiT)); + + /* + * typedef struct + { + NW_IN NwU32T teid; + NW_IN NwU32T ipAddr; + NW_IN NwU8T flags; + NW_IN NwGtpv1uMsgHandleT hMsg; + } NwGtpv1uSendtoInfoT;*/ + + hash_rc = hashtbl_get(gtpv1u_sgw_data.S1U_mapping, (uint64_t)data_req_p->local_S1u_teid, (void**)>pv1u_teid2enb_info); + + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + GTPU_ERROR("nwGtpv1uProcessUlpReq failed: while getting teid %u in hashtable S1U_mapping\n", data_req_p->local_S1u_teid); + } else { + stack_req.apiType = NW_GTPV1U_ULP_API_SEND_TPDU; + stack_req.apiInfo.sendtoInfo.teid = data_req_p->local_S1u_teid; + BUFFER_TO_NwU32T(gtpv1u_teid2enb_info->enb_ip_addr.address.ipv4_address, stack_req.apiInfo.sendtoInfo.ipAddr); + + /*nwGtpv1uGpduMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU32T teid, + NW_IN NwU8T seqNumFlag, + NW_IN NwU16T seqNum, + NW_IN NwU8T *tpdu, + NW_IN NwU16T tpduLength, + NW_OUT NwGtpv1uMsgHandleT *phMsg)*/ + rc = nwGtpv1uGpduMsgNew(gtpv1u_sgw_data.gtpv1u_stack, + 00,// TO DO bearer_p->port, but not needed when looking at processing + NW_FALSE, + gtpv1u_sgw_data.seq_num++, + data_req_p->buffer, + data_req_p->length, + &(stack_req.apiInfo.sendtoInfo.hMsg)); + + if (rc != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uGpduMsgNew failed: 0x%x\n", rc); + } else { + rc = nwGtpv1uProcessUlpReq(gtpv1u_sgw_data.gtpv1u_stack, &stack_req); + if (rc != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uProcessUlpReq failed: 0x%x\n", rc); + } + rc = nwGtpv1uMsgDelete(gtpv1u_sgw_data.gtpv1u_stack, + stack_req.apiInfo.sendtoInfo.hMsg); + if (rc != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uMsgDelete failed: 0x%x\n", rc); + } + } + } + /* Buffer is no longer needed, free it */ + free(data_req_p->buffer); + } + break; + case TIMER_HAS_EXPIRED: + nwGtpv1uProcessTimeout(&received_message_p->msg.timer_has_expired.arg); + break; + default: { + GTPU_ERROR("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } + break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int gtpv1u_init(const mme_config_t *mme_config_p) +{ + int ret; + NwGtpv1uRcT rc; + NwGtpv1uUlpEntityT ulp; + NwGtpv1uUdpEntityT udp; + NwGtpv1uLogMgrEntityT log; + NwGtpv1uTimerMgrEntityT tmr; + + GTPU_DEBUG("Initializing GTPV1U interface\n"); + + memset(>pv1u_sgw_data, 0, sizeof(gtpv1u_sgw_data)); + + gtpv1u_sgw_data.S1U_mapping = hashtbl_create (8192, NULL, NULL); + if (gtpv1u_sgw_data.S1U_mapping == NULL) { + perror("hashtbl_create"); + GTPU_ERROR("Initializing TASK_GTPV1_U task interface: ERROR\n"); + return -1; + } + + gtpv1u_sgw_data.sgw_ip_address_for_S1u_S12_S4_up = mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up; + + /* Initializing GTPv1-U stack */ + if ((rc = nwGtpv1uInitialize(>pv1u_sgw_data.gtpv1u_stack)) != NW_GTPV1U_OK) { + GTPU_ERROR("Failed to setup nwGtpv1u stack %x\n", rc); + return -1; + } + + if ((rc = nwGtpv1uSetLogLevel(gtpv1u_sgw_data.gtpv1u_stack, + NW_LOG_LEVEL_DEBG)) != NW_GTPV1U_OK) { + GTPU_ERROR("Failed to setup loglevel for stack %x\n", rc); + return -1; + } + + /* Set the ULP API callback. Called once message have been processed by the + * nw-gtpv1u stack. + */ + ulp.ulpReqCallback = gtpv1u_process_stack_req; + + if ((rc = nwGtpv1uSetUlpEntity(gtpv1u_sgw_data.gtpv1u_stack, &ulp)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetUlpEntity: %x", rc); + return -1; + } + + /* nw-gtpv1u stack requires an udp callback to send data over UDP. + * We provide a wrapper to UDP task. + */ + udp.udpDataReqCallback = gtpv1u_send_udp_msg; + + if ((rc = nwGtpv1uSetUdpEntity(gtpv1u_sgw_data.gtpv1u_stack, &udp)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetUdpEntity: %x", rc); + return -1; + } + + log.logReqCallback = gtpv1u_log_request; + + if ((rc = nwGtpv1uSetLogMgrEntity(gtpv1u_sgw_data.gtpv1u_stack, &log)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetLogMgrEntity: %x", rc); + return -1; + } + + /* Timer interface is more complicated as both wrappers doesn't send a message + * to the timer task but call the timer API functions start/stop timer. + */ + tmr.tmrMgrHandle = 0; + tmr.tmrStartCallback = gtpv1u_start_timer_wrapper; + tmr.tmrStopCallback = gtpv1u_stop_timer_wrapper; + + if ((rc = nwGtpv1uSetTimerMgrEntity(gtpv1u_sgw_data.gtpv1u_stack, &tmr)) != NW_GTPV1U_OK) { + GTPU_ERROR("nwGtpv1uSetTimerMgrEntity: %x", rc); + return -1; + } + + if (intertask_interface_create_task(TASK_GTPV1_U, >pv1u_thread, NULL) < 0) { + GTPU_ERROR("gtpv1u phtread_create: %s", strerror(errno)); + return -1; + } + + ret = gtpv1u_send_init_udp(mme_config_p->gtpv1u_config.port_number); + if (ret < 0) { + return ret; + } + + GTPU_DEBUG("Initializing GTPV1U interface: DONE\n"); + + return ret; +} diff --git a/openair-cn/GTPV1-U/gtpv1u_teid_pool.c b/openair-cn/GTPV1-U/gtpv1u_teid_pool.c new file mode 100644 index 0000000000..cf182d7fda --- /dev/null +++ b/openair-cn/GTPV1-U/gtpv1u_teid_pool.c @@ -0,0 +1,20 @@ +#include <stdlib.h> +#include <stdint.h> + +#include "gtpv1u.h" + +#define GTPV1U_LINEAR_TEID_ALLOCATION 1 + +#ifdef GTPV1U_LINEAR_TEID_ALLOCATION +static uint32_t g_gtpv1u_teid = 0; +#endif + +uint32_t gtpv1u_new_teid(void) +{ +#ifdef GTPV1U_LINEAR_TEID_ALLOCATION + g_gtpv1u_teid = g_gtpv1u_teid + 1; + return g_gtpv1u_teid; +#else + return random() + random() % (RAND_MAX - 1) + 1; +#endif +} diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/AUTHORS b/openair-cn/GTPV1-U/nw-gtpv1u/AUTHORS new file mode 100644 index 0000000000..b068a40fdd --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/AUTHORS @@ -0,0 +1 @@ +Amit Chawre diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/COPYING b/openair-cn/GTPV1-U/nw-gtpv1u/COPYING new file mode 100644 index 0000000000..d27832d6c1 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 2010-2011 Amit Chawre <http://www.amitchawre.net/contact.html> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/ChangeLog b/openair-cn/GTPV1-U/nw-gtpv1u/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/NEWS b/openair-cn/GTPV1-U/nw-gtpv1u/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/README b/openair-cn/GTPV1-U/nw-gtpv1u/README new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uLog.h b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uLog.h new file mode 100644 index 0000000000..03a701ae8d --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uLog.h @@ -0,0 +1,83 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV1U_LOG_H__ +#define __NW_GTPV1U_LOG_H__ + +#include <stdio.h> +#include "NwLog.h" + +/** + * @file NwGtpv1uLog.h + * @brief This header contains logging related definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Log Macro Definition + *--------------------------------------------------------------------------*/ + +#define NW_LOG(_gtpv1uHandle, _logLevel, ...) \ + do { \ + if(((NwGtpv1uStackT*)(_gtpv1uHandle))->logLevel >= _logLevel) \ + { \ + char _logBuf[1024]; \ + snprintf(_logBuf, 1024, __VA_ARGS__); \ + ((NwGtpv1uStackT*)(_gtpv1uHandle))->logMgr.logReqCallback(((NwGtpv1uStackT*)_gtpv1uHandle)->logMgr.logMgrHandle, _logLevel, __FILE__, __LINE__, _logBuf);\ + } \ + } while(0) + +#define NW_ENTER(_gtpv1uHandle) \ + do { \ + NW_LOG(_gtpv1uHandle, NW_LOG_LEVEL_DEBG, "Entering '%s'", __func__);\ + } while(0) + +#define NW_LEAVE(_gtpv1uHandle) \ + do { \ + NW_LOG(_gtpv1uHandle, NW_LOG_LEVEL_DEBG, "Leaving '%s'", __func__);\ + } while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_TYPES_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uPrivate.h b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uPrivate.h new file mode 100644 index 0000000000..5b9d4bdaee --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uPrivate.h @@ -0,0 +1,230 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV1U_PRIVATE_H__ +#define __NW_GTPV1U_PRIVATE_H__ + +#include "tree.h" +#include "queue.h" + +#include "NwTypes.h" +#include "NwGtpv1uError.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uMsg.h" + + +/** + * @file NwGtpv1uPrivate.h + * @brief This header file contains nw-gtpv1u private definitions not to be + * exposed to user application. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NW_GTPV1U_MALLOC(_stack, _size, _mem, _type) \ + do { \ + if(((NwGtpv1uStackT*)(_stack))->memMgr.memAlloc && ((NwGtpv1uStackT*)(_stack))->memMgr.memFree )\ + { \ + _mem = (_type) ((NwGtpv1uStackT*) (_stack))->memMgr.memAlloc(((NwGtpv1uStackT*) (_stack))->memMgr.hMemMgr, _size, __FILE__, __LINE__);\ + } \ + else \ + { \ + _mem = (_type) malloc (_size); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------* + * G T P U S T A C K O B J E C T T Y P E D E F I N I T I O N * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------* + * GRPS Tunneling Protocol Stack Class Definition + *--------------------------------------------------------------------------*/ + +/** + * gtpv1u stack class definition + */ + +typedef struct NwGtpv1uStack +{ + NwU32T id; + NwU32T seq; + NwGtpv1uUlpEntityT ulp; + NwGtpv1uUdpEntityT udp; + NwGtpv1uMemMgrEntityT memMgr; + NwGtpv1uTimerMgrEntityT tmrMgr; + NwGtpv1uLogMgrEntityT logMgr; + NwU32T logLevel; + RB_HEAD( NwGtpv1uOutstandingTxSeqNumTrxnMap, NwGtpv1uTrxn) outstandingTxSeqNumMap; + RB_HEAD( NwGtpv1uOutstandingRxSeqNumTrxnMap, NwGtpv1uTrxn) outstandingRxSeqNumMap; + RB_HEAD(NwGtpv1uTunnelEndPointTMap, NwGtpv1uTunnelEndPoint) sessionMap; + RB_HEAD(NwGtpv1uTunnelEndPointIdentifierMap, NwGtpv1uTunnelEndPoint) teidMap; +} NwGtpv1uStackT; + +/** + * GTP Tunnel End Point class definition + */ + +typedef struct NwGtpv1uTunnelEndPoint +{ + NwU32T teid; /**< Gtpu Tunnel End Point Identifier */ + NwU32T peerAddr; /**< Peer IP address for the session */ + NwGtpv1uStackT* pStack; /**< Pointer to the parent stack */ + NwGtpv1uUlpSessionHandleT hUlpSession; /**< ULP session handle for the session */ + RB_ENTRY (NwGtpv1uTunnelEndPoint) sessionMapRbtNode; /**< RB Tree Data Structure Node */ + struct NwGtpv1uTunnelEndPoint *next; +} NwGtpv1uTunnelEndPointT; + + +/*--------------------------------------------------------------------------* + * Timeout Info Type Definition + *--------------------------------------------------------------------------*/ + +/** + * gtpv1u timeout info + */ + +typedef struct NwGtpv1uTimeoutInfo +{ + NwGtpv1uStackHandleT hStack; + void* timeoutArg; + NwGtpv1uRcT (*timeoutCallbackFunc)(void*); +} NwGtpv1uTimeoutInfoT; + +/** + * Start a transaction response timer + * + * @param[in] thiz Pointer to stack instance + * @param[in] timeoutArg Arg to timeout function. + * @param[out] phTmr Pointer to timer handle. + * @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpStartTrxnPeerRspTimer(NwGtpv1uStackT* thiz, NwGtpv1uTimeoutInfoT* timeoutInfo, NwGtpv1uTimerHandleT* phTmr); + +/** + * Stop a transaction response timer + * + * @param[in] thiz Pointer to stack instance + * @param[out] phTmr Pointer to timer handle. + * @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpStopTrxnPeerRspTimer(NwGtpv1uStackT* thiz, NwGtpv1uTimerHandleT* phTmr); + + +#define NW_GTPV1U_MAX_MSG_LEN (4096) /**< Maximum supported gtpv1u packet length including header */ + +/** + * NwGtpv1uMsgT holds gtpv1u messages to/from the peer. + */ +typedef struct NwGtpv1uMsg +{ + NwU8T version; + NwU8T protocolType; + NwU8T extHdrFlag; + NwU8T seqNumFlag; + NwU16T npduNumFlag; + NwU32T msgType; + NwU16T msgLen; + NwU32T teid; + NwU16T seqNum; + NwU8T npduNum; + NwU8T nextExtHdrType; + NwU8T msgBuf[NW_GTPV1U_MAX_MSG_LEN]; + struct NwGtpv1uMsg* next; +} NwGtpv1uMsgT; + + +/*--------------------------------------------------------------------------* + * R6/R4 Transaction Context Type Definition + *--------------------------------------------------------------------------*/ + +/** + * Transaction structure + */ + +typedef struct NwGtpv1uTrxn +{ + NwU32T seqNum; + NwU32T peerIp; + NwU32T peerPort; + NwU8T maxRetries; + NwU8T t3Timer; + NwGtpv1uTimerHandleT hRspTmr; + NwGtpv1uTimeoutInfoT peerRspTimeoutInfo; + NwGtpv1uStackT* pStack; + NwGtpv1uTunnelEndPointT* pSession; + NwU32T hUlpTrxn; + NwGtpv1uMsgT* pMsg; + RB_ENTRY (NwGtpv1uTrxn) outstandingTxSeqNumMapRbtNode; /**< RB Tree Data Structure Node */ + RB_ENTRY (NwGtpv1uTrxn) outstandingRxSeqNumMapRbtNode; /**< RB Tree Data Structure Node */ + struct NwGtpv1uTrxn* next; +} NwGtpv1uTrxnT; + + +/** + * GTPv2 message header structure + */ + +#pragma pack(1) + +typedef struct NwGtpv1uMsgHeader +{ + NwU8T PN:1; + NwU8T S:1; + NwU8T E:1; + NwU8T spare:1; + NwU8T PT:1; + NwU8T version:3; + NwU8T msgType; + NwU16T msgLength; + NwU32T teid; +} NwGtpv1uMsgHeaderT; + +#pragma pack() + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV1U_PRIVATE_H__ */ +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTrxn.h b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTrxn.h new file mode 100644 index 0000000000..9d4979229c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTrxn.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +/** + * @file NwGtpv1uTrxn.h + * @author Amit Chawre + * @brief + * + * This header file contains required definitions and functions + * prototypes used by gtpv1u transactions. + * + **/ + + +#ifndef __NW_GTPV1U_TRXN_H__ +#define __NW_GTPV1U_TRXN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv1uRcT +nwGtpv1uTrxnNew( NW_IN NwGtpv1uStackT* thiz, + NW_OUT NwGtpv1uTrxnT **ppTrxn); + + +NwGtpv1uRcT +nwGtpv1uTrxnWithSeqNew( NW_IN NwGtpv1uStackT* thiz, + NW_IN NwU32T seqNum, + NW_OUT NwGtpv1uTrxnT **ppTrxn); + +NwGtpv1uRcT +nwGtpv1uTrxnDelete( NW_INOUT NwGtpv1uTrxnT **ppTrxn); + +NwGtpv1uRcT +nwGtpv1uTrxnNew( NW_IN NwGtpv1uStackT* thiz, + NW_OUT NwGtpv1uTrxnT **ppTrxn); + +NwGtpv1uRcT +nwGtpv1uTrxnDelete( NW_INOUT NwGtpv1uTrxnT **pthiz); + +NwGtpv1uRcT +nwGtpv1uTrxnCreateAndSendMsg( NW_IN NwGtpv1uStackT* thiz, + NW_IN NwGtpv1uTrxnT *pTrxn, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwGtpv1uMsgT *pMsg); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV1U_TRXN_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTunnelEndPoint.h b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTunnelEndPoint.h new file mode 100644 index 0000000000..c876a2fc3e --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/include/NwGtpv1uTunnelEndPoint.h @@ -0,0 +1,85 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwGtpv1uError.h" +#include "NwGtpv1uPrivate.h" +#include "NwGtpv1uMsg.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uLog.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef __NW_GTPV1U_CONNECTION_H__ +#define __NW_GTPV1U_CONNECTION_H__ + +/** + Constructor + + @return Pointer to session on success, NULL n failure. + */ + +NwGtpv1uTunnelEndPointT* +nwGtpTunnelEndPointNew(struct NwGtpv1uStack* pStack); + +/** + Destructor + + @param[in] thiz: Pointer to session + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpTunnelEndPointDestroy(struct NwGtpv1uStack* pStack, NwGtpv1uTunnelEndPointT* thiz); + +NwGtpv1uRcT +nwGtpSessionSendMsgApiToUlpEntity(NwGtpv1uTunnelEndPointT* thiz, + NwGtpv1uMsgT *pMsg); + +#ifdef __cplusplus +} +#endif + +#endif +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1u.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1u.h new file mode 100644 index 0000000000..fbfeb8279c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1u.h @@ -0,0 +1,578 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV1U_H__ +#define __NW_GTPV1U_H__ + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include "NwTypes.h" +#include "NwGtpv1uError.h" + + +/** + * @file NwGtpv1u.h + * @author Amit Chawre + * @brief + * + * This header file contains all required definitions and functions + * prototypes for using nw-gtpv1u library. + * + **/ + +#define NW_GTPU_VERSION (0x01) +#define NW_GTP_PROTOCOL_TYPE_GTP (0x01) +#define NW_GTP_PROTOCOL_TYPE_GTP_PRIME (0x00) + +/*--------------------------------------------------------------------------* + * S H A R E D A P I M A C R O S * + *--------------------------------------------------------------------------*/ + +#define NW_GTP_ECHO_REQ (1) +#define NW_GTP_ECHO_RSP (2) +#define NW_GTP_ERROR_INDICATION (26) +#define NW_GTP_SUPPORTED_EXTENSION_HEADER_INDICATION (31) +#define NW_GTP_END_MARKER (254) +#define NW_GTP_GPDU (255) + +/*--------------------------------------------------------------------------- + * Opaque Gtpv2 Stack Handles + *--------------------------------------------------------------------------*/ + +typedef NwPtrT NwGtpv1uStackHandleT; /**< Gtpv2 Stack Handle */ +typedef NwPtrT NwGtpv1uUlpHandleT; /**< Gtpv2 Stack Ulp Entity Handle */ +typedef NwPtrT NwGtpv1uUdpHandleT; /**< Gtpv2 Stack Udp Entity Handle */ +typedef NwPtrT NwGtpv1uMemMgrHandleT; /**< Gtpv2 Stack Mem Manager Handle */ +typedef NwPtrT NwGtpv1uTimerMgrHandleT; /**< Gtpv2 Stack Timer Manager Handle */ +typedef NwPtrT NwGtpv1uLogMgrHandleT; /**< Gtpv2 Stack Log Mnagaer Handle */ +typedef NwPtrT NwGtpv1uTimerHandleT; /**< Gtpv2 Stack Timer Handle */ +typedef NwPtrT NwGtpv1uMsgHandleT; /**< Gtpv2 Msg Handle */ + +typedef struct NwGtpv1uStackConfig +{ + NwU16T udpSrcPort; +} NwGtpv1uStackConfigT; + +/*--------------------------------------------------------------------------* + * S T A C K A P I D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Gtpv2 Stack ULP API type definitions + *--------------------------------------------------------------------------*/ + +/** + * APIs types between ULP and Stack + */ + +typedef enum +{ + /* APIs from ULP to stack */ + + NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT = 0x00000000, /**< Create a local teid context on stack */ + NW_GTPV1U_ULP_API_DESTROY_TUNNEL_ENDPOINT, /**< Delete a local teid context on stack */ + NW_GTPV1U_ULP_API_INITIAL_REQ, /**< Send a Initial Request over a session */ + NW_GTPV1U_ULP_API_TRIGGERED_REQ, /**< Send a Initial Request over a session */ + NW_GTPV1U_ULP_API_TRIGGERED_RSP, /**< Send a Trigger Response over a session */ + NW_GTPV1U_ULP_API_SEND_TPDU, /**< Send a T-PDU message over teid context */ + + /* APIs from stack to ULP */ + + NW_GTPV1U_ULP_API_RECV_TPDU, /**< Receive a gtpv1u T-PDU from stack */ + NW_GTPV1U_ULP_API_RECV_MSG, /**< Receive a gtpv1u message from stack */ + NW_GTPV1U_ULP_API_RSP_FAILURE, /**< Rsp failure for gtpv2 message from stack */ + + /* Do not add below this */ + + NW_GTPV1U_ULP_API_END = 0xFFFFFFFF, +} NwGtpv1uUlpApiTypeT; + +/*--------------------------------------------------------------------------- + * Gtpv2 Stack API information elements definitions + *--------------------------------------------------------------------------*/ + +typedef NwU32T NwGtpv1uStackSessionHandleT;/**< Gtpv2 Stack session Handle */ +typedef NwU8T NwGtpv1uMsgTypeT; /**< Gtpv2 Msg Type */ +typedef NwU32T NwGtpv1uTrxnHandleT; /**< Gtpv2 Transaction Handle */ +typedef NwU32T NwGtpv1uUlpTrxnHandleT; /**< Gtpv2 Ulp Transaction Handle */ +typedef NwU32T NwGtpv1uUlpSessionHandleT; /**< Gtpv2 Ulp session Handle */ + +/** + * API information elements between ULP and Stack for + * creating a session. + */ + +typedef struct +{ + NW_IN NwU32T teid; + NW_IN NwGtpv1uUlpSessionHandleT hUlpSession; + NW_OUT NwGtpv1uStackSessionHandleT hStackSession; +} NwGtpv1uCreateTunnelEndPointT; + +/** + * API information elements between ULP and Stack for + * destroying a session. + */ + +typedef struct +{ + NW_IN NwGtpv1uStackSessionHandleT hStackSessionHandle; +} NwGtpv1uDestroyTunnelEndPointT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv1u initial message. + */ + +typedef struct +{ + NW_IN NwGtpv1uUlpTrxnHandleT hUlpTrxn; + NW_IN NwU32T peerIp; + NW_IN NwU32T peerPort; + NW_IN NwU8T flags; + NW_IN NwU32T teid; +} NwGtpv1uInitialReqInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv1u triggered response message. + */ + +typedef struct +{ + NW_IN NwGtpv1uUlpTrxnHandleT hUlpTrxn; + NW_IN NwU32T peerIp; + NW_IN NwU32T peerPort; + NW_IN NwU8T flags; + NW_IN NwU32T teid; + NW_IN NwU32T seqNum; + NW_IN NwGtpv1uMsgHandleT hMsg; +} NwGtpv1uTriggeredRspInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv1u triggered request message. + */ + +typedef struct +{ + NW_IN NwGtpv1uUlpTrxnHandleT hUlpTrxn; + NW_IN NwU32T peerIp; + NW_IN NwU32T peerPort; + NW_IN NwU8T flags; + NW_IN NwU32T teid; + NW_IN NwU32T seqNum; + NW_IN NwGtpv1uMsgHandleT hMsg; +} NwGtpv1uTriggeredReqInfoT; + + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2 message over a session. + */ + +typedef struct +{ + NW_IN NwU32T teid; + NW_IN NwU32T ipAddr; + NW_IN NwU8T flags; + NW_IN NwGtpv1uMsgHandleT hMsg; +} NwGtpv1uSendtoInfoT; + + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2 message over a session. + */ + +typedef struct +{ + NW_OUT NwGtpv1uStackSessionHandleT hStackSessionHandle; + NW_INOUT NwGtpv1uTrxnHandleT hTrxn; + NW_IN NwGtpv1uUlpTrxnHandleT hUlpTrxn; + NW_IN NwGtpv1uMsgTypeT msgType; + NW_IN NwU8T flags; + NW_IN NwGtpv1uMsgHandleT hMsg; +} NwGtpv1uSendMsgInfoT; + +/** + * API information elements between ULP and Stack for + * receiving a Gtpv2 message over a session from stack. + */ + +typedef struct +{ + NW_IN NwGtpv1uUlpSessionHandleT hUlpSession; + NW_IN NwGtpv1uUlpTrxnHandleT hUlpTrxn; + NW_IN NwU32T teid; + NW_IN NwU32T peerIp; + NW_IN NwU32T peerPort; + NW_IN NwU32T msgType; /**< Message type */ + NW_IN NwGtpv1uMsgHandleT hMsg; /**< Gtp Message handle */ +} NwGtpv1uRecvMsgInfoT; + +/** + * API information elements between ULP and Stack for + * receiving a Gtpv2 message over a session from stack. + */ + +typedef struct +{ + NW_IN NwGtpv1uUlpSessionHandleT hUlpSession; + NW_IN NwGtpv1uTrxnHandleT hTrxn; +} NwGtpv1uNackInfoT; + +/*--------------------------------------------------------------------------- + * Gtpv2 Stack API structure definition + *--------------------------------------------------------------------------*/ + +/** + * API structure between ULP and Stack + */ + +typedef struct +{ + NwGtpv1uUlpApiTypeT apiType; + NwGtpv1uMsgHandleT hMsg; + union + { + NwGtpv1uCreateTunnelEndPointT createTunnelEndPointInfo; + NwGtpv1uDestroyTunnelEndPointT destroyTunnelEndPointInfo; + NwGtpv1uInitialReqInfoT initialReqInfo; + NwGtpv1uTriggeredRspInfoT triggeredRspInfo; + NwGtpv1uTriggeredReqInfoT triggeredReqInfo; + NwGtpv1uSendtoInfoT sendtoInfo; + NwGtpv1uSendMsgInfoT sendMsgInfo; + NwGtpv1uRecvMsgInfoT recvMsgInfo; + NwGtpv1uNackInfoT nackMsgInfo; + } apiInfo; +} NwGtpv1uUlpApiT; + + +/*--------------------------------------------------------------------------* + * S T A C K E N T I T I E S D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * ULP Entity Definitions + *--------------------------------------------------------------------------*/ + +/** + * Gtpv2 ULP entity definition + */ + +typedef struct +{ + NwGtpv1uUlpHandleT hUlp; + NwGtpv1uRcT (*ulpReqCallback) ( NW_IN NwGtpv1uUlpHandleT hUlp, + NW_IN NwGtpv1uUlpApiT *pUlpApi); +} NwGtpv1uUlpEntityT; + + +/*--------------------------------------------------------------------------- + * UDP Entity Definitions + *--------------------------------------------------------------------------*/ + +/** + * Gtpv2 UDP entity definition + */ + +typedef struct +{ + NwGtpv1uUdpHandleT hUdp; + NwGtpv1uRcT (*udpDataReqCallback) ( NW_IN NwGtpv1uUdpHandleT udpHandle, + NW_IN NwU8T* dataBuf, + NW_IN NwU32T dataSize, + NW_IN NwU32T peerIP, + NW_IN NwU16T peerPort); +} NwGtpv1uUdpEntityT; + +/** + * Gtpv1u Memory Manager entity definition + */ + +typedef struct +{ + NwGtpv1uMemMgrHandleT hMemMgr; + void* (*memAlloc)( NW_IN NwGtpv1uMemMgrHandleT hMemMgr, + NW_IN NwU32T memSize, + NW_IN NwCharT* fileName, + NW_IN NwU32T lineNumber); + + void (*memFree) ( NW_IN NwGtpv1uMemMgrHandleT hMemMgr, + NW_IN void* hMem, + NW_IN NwCharT* fileName, + NW_IN NwU32T lineNumber); +} NwGtpv1uMemMgrEntityT; + + +/*--------------------------------------------------------------------------- + * Timer Entity Definitions + *--------------------------------------------------------------------------*/ + +#define NW_GTPV1U_TMR_TYPE_ONE_SHOT (0) +#define NW_GTPV1U_TMR_TYPE_REPETITIVE (1) + +/** + * Gtpv2 Timer Manager entity definition + */ + +typedef struct +{ + NwGtpv1uTimerMgrHandleT tmrMgrHandle; + NwGtpv1uRcT (*tmrStartCallback)( NW_IN NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NW_IN NwU32T timeoutSecs, + NW_IN NwU32T timeoutUsec, + NW_IN NwU32T tmrType, + NW_IN void* tmrArg, + NW_OUT NwGtpv1uTimerHandleT* tmrHandle); + + NwGtpv1uRcT (*tmrStopCallback) ( NW_IN NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NW_IN NwGtpv1uTimerHandleT tmrHandle); +} NwGtpv1uTimerMgrEntityT; + + +/*--------------------------------------------------------------------------- + * Log Entity Definitions + *--------------------------------------------------------------------------*/ + +/** + * Gtpv2 Log manager entity definition + */ + +typedef struct +{ + NwGtpv1uLogMgrHandleT logMgrHandle; + NwGtpv1uRcT (*logReqCallback) (NW_IN NwGtpv1uLogMgrHandleT logMgrHandle, + NW_IN NwU32T logLevel, + NW_IN NwCharT* file, + NW_IN NwU32T line, + NW_IN NwCharT* logStr); +} NwGtpv1uLogMgrEntityT; + + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Constructor + *--------------------------------------------------------------------------*/ + +/** + Initialize the nw-gtpv1u stack. + + @param[in,out] phGtpv1uStackHandle : Pointer to stack handle + */ + +NwGtpv1uRcT +nwGtpv1uInitialize( NW_INOUT NwGtpv1uStackHandleT* phGtpv1uStackHandle); + +/*--------------------------------------------------------------------------- + * Destructor + *--------------------------------------------------------------------------*/ + +/** + Destroy the nw-gtpv1u stack. + + @param[in] hGtpv1uStackHandle : Stack handle + */ + +NwGtpv1uRcT +nwGtpv1uFinalize( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle); + +/*--------------------------------------------------------------------------- + * Configuration Get/Set Operations + *--------------------------------------------------------------------------*/ + +/** + Set Configuration for the nw-gtpv1u stack. + + @param[in,out] phGtpv1uStackHandle : Pointer to stack handle + */ + +NwGtpv1uRcT +NwGtpv1uConfigSet( NW_IN NwGtpv1uStackHandleT* phGtpv1uStackHandle, NW_IN NwGtpv1uStackConfigT* pConfig); + +/** + Get Configuration for the nw-gtpv1u stack. + + @param[in,out] phGtpv1uStackHandle : Pointer to stack handle + */ + +NwGtpv1uRcT +NwGtpv1uConfigGet( NW_IN NwGtpv1uStackHandleT* phGtpv1uStackHandle, NW_OUT NwGtpv1uStackConfigT* pConfig); + +/** + Set ULP entity for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pUlpEntity : Pointer to ULP entity. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetUlpEntity( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uUlpEntityT* pUlpEntity); + +/** + Set UDP entity for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pUdpEntity : Pointer to UDP entity. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetUdpEntity( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uUdpEntityT* pUdpEntity); + +/** + Set MemMgr entity for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pMemMgr : Pointer to Memory Manager. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetMemMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uMemMgrEntityT* pMemMgr); + + +/** + Set TmrMgr entity for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pTmrMgr : Pointer to Timer Manager. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetTimerMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uTimerMgrEntityT* pTmrMgr); + +/** + Set LogMgr entity for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pLogMgr : Pointer to Log Manager. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetLogMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uLogMgrEntityT* pLogMgr); + +/** + Set log level for the stack. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] logLevel : Log level. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uSetLogLevel( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU32T logLevel); +/*--------------------------------------------------------------------------- + * Process Request from Udp Layer + *--------------------------------------------------------------------------*/ + +/** + Process Data Request from UDP entity. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] udpData : Pointer to received UDP data. + @param[in] udpDataLen : Received data length. + @param[in] dstPort : Received on port. + @param[in] from : Received from peer information. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uProcessUdpReq( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwU8T* udpData, + NW_IN NwU32T udpDataLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIP); + +/*--------------------------------------------------------------------------- + * Process Request from Upper Layer + *--------------------------------------------------------------------------*/ + +/** + Process Request from ULP entity. + + @param[in] hGtpv1uStackHandle : Stack handle + @param[in] pLogMgr : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uProcessUlpReq( NW_IN NwGtpv1uStackHandleT hGtpv1uStackHandle, + NW_IN NwGtpv1uUlpApiT *ulpReq); + + +/*--------------------------------------------------------------------------- + * Process Timer timeout Request from Timer Manager + *--------------------------------------------------------------------------*/ + +/** + Process Timer timeout Request from Timer Manager + + @param[in] pLogMgr : Pointer timeout arguments. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpv1uProcessTimeout( NW_IN void* timeoutArg); + +NwGtpv1uRcT +nwGtpv1uPeerRspTimeout(void* arg); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV1U_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uError.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uError.h new file mode 100644 index 0000000000..d1b803e139 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uError.h @@ -0,0 +1,62 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#ifndef __NW_GTPV1U_ERROR_H__ +#define __NW_GTPV1U_ERROR_H__ + +/** + * @file NwGtpv1uError.h + * @brief This header file contains return error code type definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + + NW_GTPV1U_OK = 0x00000000, + NW_GTPV1U_MANDATORY_IE_DUPLICATE, + NW_GTPV1U_MANDATORY_IE_MISSING, + NW_GTPV1U_MSG_MALFORMED, + NW_GTPV1U_FAILURE = 0xFFFFFFFE +} NwGtpv1uRcT; + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV1U_ERROR_H__*/ + + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uIe.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uIe.h new file mode 100644 index 0000000000..ae4f7e64d2 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uIe.h @@ -0,0 +1,66 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +/** + * @file NwGtpv1uIe.h + * @brief This header file contains Information Element definitions for GTPv1u + * as per 3GPP TS 29281-930. +*/ + +#ifndef __NW_GTPV1U_IE_H__ +#define __NW_GTPV1U_IE_H__ + +/*--------------------------------------------------------------------------* + * G T P V 2 U I E T Y P E M A C R O D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#define NW_GTPV1U_IE_RECOVERY (14) +#define NW_GTPV1U_IE_TEID_DATA_I (15) +#define NW_GTPV1U_IE_GSN_ADDRESS (133) +#define NW_GTPV1U_IE_EXT_HDR_TYPE_LIST (141) +#define NW_GTPV1U_IE_PRIVATE_EXTENSION (255) + + +/*--------------------------------------------------------------------------* + * G T P V 2 U C A U S E V A L U E D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#define NW_GTPV1U_CAUSE_REQUEST_ACCEPTED (16) +#define NW_GTPV1U_CAUSE_MANDATORY_IE_MISSING (70) + +#endif /* __NW_GTPV1U_IE_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uMsg.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uMsg.h new file mode 100644 index 0000000000..2e636ccf3c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwGtpv1uMsg.h @@ -0,0 +1,320 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV1U_MSG_H__ +#define __NW_GTPV1U_MSG_H__ + +#include "NwTypes.h" +#include "NwGtpv1u.h" + +/** + * @file NwGtpv1uMsg.h + * @brief This file defines APIs for to build new outgoing gtpv1u messages and to parse incoming messages. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------* + * G T P V 2 C I E D A T A - T Y P E D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#pragma pack(1) + +typedef struct NwGtpv1uIeTv1 +{ + NwU8T t; + NwU8T v; +} NwGtpv1uIeTv1T; + +typedef struct NwGtpv1uIeTv2 +{ + NwU8T t; + NwU8T v; +} NwGtpv1uIeTv2T; + +typedef struct NwGtpv1uIeTv4 +{ + NwU8T t; + NwU32T v; +} NwGtpv1uIeTv4T; + +typedef struct NwGtpv1uIeTlv +{ + NwU8T t; + NwU16T l; +} NwGtpv1uIeTlvT; + +#pragma pack() + + + /** + * Allocate a GPDU gtpv1u message. + * + * @param[in] hGtpuStackHandle : gtpv1u stack handle. + * @param[in] teidPresent : TEID is present flag. + * @param[in] teid : TEID for this message. + * @param[in] seqNum : Sequence number for this message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwGtpv1uRcT +nwGtpv1uMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU8T seqNumFlag, + NW_IN NwU8T npduNumFlag, + NW_IN NwU8T extHdrFlag, + NW_IN NwU8T msgType, + NW_IN NwU8T teid, + NW_IN NwU16T seqNum, + NW_IN NwU8T npduNum, + NW_IN NwU8T nextExtHeader, + NW_OUT NwGtpv1uMsgHandleT *phMsg); + + + /** + * Allocate a gtpv1u message. + * + * @param[in] hGtpuStackHandle : gtpv1u stack handle. + * @param[in] teid : TEID for this message. + * @param[in] seqNumFlag : Sequence number flag for this message. + * @param[in] seqNum : Sequence number for this message. + * @param[in] pTpdu: T-PDU for this message. + * @param[in] tpduLength: T-PDU length for this message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwGtpv1uRcT +nwGtpv1uGpduMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU32T teid, + NW_IN NwU8T seqNumFlag, + NW_IN NwU16T seqNum, + NW_IN NwU8T* tpdu, + NW_IN NwU16T tpduLength, + NW_OUT NwGtpv1uMsgHandleT *phMsg); + + /** + * Allocate a gtpv1u message from another gtpv1u message. + * + * @param[in] hGtpuStackHandle : gtpv1u stack handle. + * @param[out] hMsg : Handle to input message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwGtpv1uRcT +nwGtpv1uMsgFromMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uMsgHandleT hMsg, + NW_OUT NwGtpv1uMsgHandleT *phMsg); + /** + * Allocate a gtpv1u message from data buffer. + * + * @param[in] hGtpuStackHandle : gtpv1u stack handle. + * @param[in] pBuf: Buffer to be copied in this message. + * @param[in] bufLen: Buffer length to be copied in this message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwGtpv1uRcT +nwGtpv1uMsgFromBufferNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU8T* pBuf, + NW_IN NwU32T bufLen, + NW_OUT NwGtpv1uMsgHandleT *phMsg); + + /** + * Free a gtpv1u message. + * + * @param[in] hGtpuStackHandle : gtpv1u stack handle. + * @param[in] hMsg : Message handle. + */ + +NwGtpv1uRcT +nwGtpv1uMsgDelete( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uMsgHandleT hMsg); + + /** + * Set TEID for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[in] teid: TEID value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgSetTeid(NW_IN NwGtpv1uMsgHandleT hMsg, NwU32T teid); + + /** + * Set TEID present flag for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[in] teidPesent: Flag boolean value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgSetTeidPresent(NW_IN NwGtpv1uMsgHandleT hMsg, NwBoolT teidPresent); + + /** + * Set sequence for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[in] seqNum: Flag boolean value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgSetSeqNumber(NW_IN NwGtpv1uMsgHandleT hMsg, NwU32T seqNum); + + /** + * Get TEID present for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv1uMsgGetTeid(NW_IN NwGtpv1uMsgHandleT hMsg); + + /** + * Get TEID present for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwBoolT +nwGtpv1uMsgGetTeidPresent(NW_IN NwGtpv1uMsgHandleT hMsg); + + /** + * Get sequence number for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv1uMsgGetSeqNumber(NW_IN NwGtpv1uMsgHandleT hMsg); + + /** + * Get tpdu for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[inout] pTpduBuf : Buffer to copy the T-PDU. + * @param[out] hMsg : T-PDU length. + */ + +NwU32T +nwGtpv1uMsgGetTpdu(NW_IN NwGtpv1uMsgHandleT hMsg, NwU8T* pTpduBuf, NwU32T* pTpduLength); + +NwU8T* +nwGtpv1uMsgGetTpduHandle(NW_IN NwGtpv1uMsgHandleT hMsg); + +NwU32T +nwGtpv1uMsgGetTpduLength(NW_IN NwGtpv1uMsgHandleT hMsg); + + /** + * Add a gtpv1u information element of length 1 to gtpv1u mesasge. + * + * @param[in] hMsg : Handle to gtpv1u message. + * @param[in] type : IE type. + * @param[in] value : IE value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV1(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T value); + + + /** + * Add a gtpv1u information element of length 2 to gtpv1u mesasge. + * + * @param[in] hMsg : Handle to gtpv1u message. + * @param[in] type : IE type. + * @param[in] value : IE value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV2(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU16T value); + + + /** + * Add a gtpv1u information element of length 4 to gtpv1u mesasge. + * + * @param[in] hMsg : Handle to gtpv1u message. + * @param[in] type : IE type. + * @param[in] value : IE value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV4(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU32T value); + + + /** + * Add a gtpv1u information element of variable length to gtpv1u mesasge. + * + * @param[in] hMsg : Handle to gtpv1u message. + * @param[in] type : IE type. + * @param[in] length : IE length. + * @param[in] value : IE value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgAddIe(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU8T* pVal); + +/** + * Dump the contents of gtpv1u mesasge. + * + * @param[in] hMsg : Handle to gtpv1u message. + * @param[in] fp: Pointer to output file. + */ + +NwGtpv1uRcT +nwGtpv1uMsgHexDump(NwGtpv1uMsgHandleT hMsg, FILE* fp); + +NwU32T +nwGtpv1uMsgGetMsgType(NW_IN NwGtpv1uMsgHandleT hMsg); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_TYPES_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwLog.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwLog.h new file mode 100644 index 0000000000..aaf83615a5 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwLog.h @@ -0,0 +1,88 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#ifndef __NW_LOG_H__ +#define __NW_LOG_H__ + +#include <libgen.h> + +#include "NwTypes.h" + +/** + * @file NwLog.h + * @brief This header file contains global shared logging definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Log Level Definitions + *--------------------------------------------------------------------------*/ + +#define NW_LOG_LEVEL_EMER (0) /**< system is unusable */ +#define NW_LOG_LEVEL_ALER (1) /**< action must be taken immediately*/ +#define NW_LOG_LEVEL_CRIT (2) /**< critical conditions */ +#define NW_LOG_LEVEL_ERRO (3) /**< error conditions */ +#define NW_LOG_LEVEL_WARN (4) /**< warning conditions */ +#define NW_LOG_LEVEL_NOTI (5) /**< normal but signification condition */ +#define NW_LOG_LEVEL_INFO (6) /**< informational */ +#define NW_LOG_LEVEL_DEBG (7) /**< debug-level messages */ + +// static +// NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * IPv4 logging macros + *--------------------------------------------------------------------------*/ +#define NW_IPV4_ADDR "%u.%u.%u.%u" +#define NW_IPV4_ADDR_FORMAT(__addr) (NwU8T)((__addr) & 0x000000ff), \ + (NwU8T)(((__addr) & 0x0000ff00) >> 8 ), \ + (NwU8T)(((__addr) & 0x00ff0000) >> 16), \ + (NwU8T)(((__addr) & 0xff000000) >> 24) + +#define NW_IPV4_ADDR_FORMATP(__paddr) (NwU8T)(*((NwU8T*)(__paddr)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 1)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 2)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 3)) & 0x000000ff) + + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_LOG_H__ */ + + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwTypes.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwTypes.h new file mode 100644 index 0000000000..bf45c2f614 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwTypes.h @@ -0,0 +1,83 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#include <stdlib.h> +#include <stdint.h> + +#ifndef __NW_TYPES_H__ +#define __NW_TYPES_H__ + +/** + * @file NwTypes.h + * @brief This header file contains basic type definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NW_IN /**< An input argument */ +#define NW_OUT /**< An output argumnet */ +#define NW_INOUT /**< An input and output argument */ + +#define NW_TRUE (1) /**< Truth value */ +#define NW_FALSE (0) /**< False value */ + +typedef unsigned char NwU8T; /**< Unsigned 1 byte */ +typedef unsigned short NwU16T; /**< Unsigned 2 byte */ +typedef unsigned int NwU32T; /**< Unsigned 4 byte */ +typedef unsigned long long NwU64T; /**< Unsigned 8 byte */ + +typedef signed char NwS8T; /**< Signed 1 byte */ +typedef signed short NwS16T; /**< Signed 2 byte */ +typedef signed int NwS32T; /**< Signed 4 byte */ +typedef signed long long NwS64T; /**< Signed 8 byte */ + +typedef uintptr_t NwPtrT; /**< Use this for generic pointers */ +typedef unsigned int NwHandleT; /**< Use this for generic handles */ + +typedef char NwBoolT; /**< Use this for booleans */ + +typedef char NwCharT; /**< Use this for strings */ + +typedef signed int NwFdT; /**< Use this for file descriptor */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_TYPES_H__ */ + + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwUtils.h b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwUtils.h new file mode 100644 index 0000000000..9e2adc86a2 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/shared/NwUtils.h @@ -0,0 +1,68 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <assert.h> + +#ifndef __NW_UTILS_H__ +#define __NW_UTILS_H__ + + +/** + * @file NwUtils.h + * @brief This header file contains utility macro and function definitions. +*/ + +#define NW_ASSERT assert /**< Assertion */ + +#define NW_CHK_NULL_PTR(_ptr) NW_ASSERT(_ptr != NULL) /**< Null pointer check */ + +#define NW_HTONS(x) ( ( ((x) & 0xff00) >> 8 ) | ( ((x) & 0x00ff) << 8 ) ) + +#define NW_HTONL(x) ( ( ((x) & 0xff000000) >> 24 ) | ( ( (x) & 0x00ff0000 ) >> 8 ) | \ + ( ( (x) & 0x0000ff00 ) << 8 ) | ( ( (x) & 0x000000ff) << 24 ) ) + +#define NW_HTONLL(x) ( \ + ( ( ((NwU64T)x) & 0xff00000000000000ULL ) >> 56 ) | ( ( ((NwU64T)x) & 0x00ff000000000000ULL ) >> 40 ) | \ + ( ( ((NwU64T)x) & 0x0000ff0000000000ULL ) >> 24 ) | ( ( ((NwU64T)x) & 0x000000ff00000000ULL ) >> 8 ) | \ + ( ( ((NwU64T)x) & 0x000000000000ff00ULL ) << 40 ) | ( ( ((NwU64T)x) & 0x00000000000000ffULL ) << 56 ) | \ + ( ( ((NwU64T)x) & 0x0000000000ff0000ULL ) << 24 ) | ( ( ((NwU64T)x) & 0x00000000ff000000ULL ) << 8 ) \ + ) + +#define NW_NTOHS NW_HTONS +#define NW_NTOHL NW_HTONL +#define NW_NTOHLL NW_HTONLL + + +#endif /* __NW_UTILS_H__ */ + + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c new file mode 100644 index 0000000000..cb1cb3c368 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1u.c @@ -0,0 +1,886 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwGtpv1uError.h" +#include "NwGtpv1uPrivate.h" +#include "NwGtpv1uTunnelEndPoint.h" +#include "NwGtpv1uTrxn.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uIe.h" +#include "NwGtpv1uLog.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +void +nwGtpv1uDisplayBanner(void) +{ + printf(" *----------------------------------------------------------------------------*\n"); + printf(" * *\n"); + printf(" * n w - g t p v 2 u *\n"); + printf(" * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k *\n"); + printf(" * *\n"); + printf(" * *\n"); + printf(" * Copyright (c) 2010-2011 Amit Chawre *\n"); + printf(" * All rights reserved. *\n"); + printf(" * *\n"); + printf(" * Redistribution and use in source and binary forms, with or without *\n"); + printf(" * modification, are permitted provided that the following conditions *\n"); + printf(" * are met: *\n"); + printf(" * *\n"); + printf(" * 1. Redistributions of source code must retain the above copyright *\n"); + printf(" * notice, this list of conditions and the following disclaimer. *\n"); + printf(" * 2. Redistributions in binary form must reproduce the above copyright *\n"); + printf(" * notice, this list of conditions and the following disclaimer in the *\n"); + printf(" * documentation and/or other materials provided with the distribution. *\n"); + printf(" * 3. The name of the author may not be used to endorse or promote products *\n"); + printf(" * derived from this software without specific prior written permission. *\n"); + printf(" * *\n"); + printf(" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *\n"); + printf(" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *\n"); + printf(" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *\n"); + printf(" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *\n"); + printf(" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *\n"); + printf(" * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *\n"); + printf(" * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *\n"); + printf(" * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *\n"); + printf(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *\n"); + printf(" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *\n"); + printf(" *----------------------------------------------------------------------------*\n\n"); + +} +/*--------------------------------------------------------------------------- + * RBTree Search Functions + *--------------------------------------------------------------------------*/ + +static inline NwS32T +nwGtpv1uCompareTeid(struct NwGtpv1uTunnelEndPoint *a, + struct NwGtpv1uTunnelEndPoint *b); + +static inline NwS32T +nwGtpv1uCompareSeqNum(struct NwGtpv1uTrxn *a, struct NwGtpv1uTrxn *b); + +RB_PROTOTYPE(NwGtpv1uOutstandingTxSeqNumTrxnMap, NwGtpv1uTrxn, + outstandingTxSeqNumMapRbtNode, nwGtpv1uCompareSeqNum) +RB_PROTOTYPE(NwGtpv1uOutstandingRxSeqNumTrxnMap, NwGtpv1uTrxn, + outstandingRxSeqNumMapRbtNode, nwGtpv1uCompareSeqNum) +RB_PROTOTYPE(NwGtpv1uTunnelEndPointTMap, NwGtpv1uTunnelEndPoint, + sessionMapRbtNode, nwGtpv1uCompareTeid) +RB_PROTOTYPE(NwGtpv1uTunnelEndPointIdentifierMap, NwGtpv1uTunnelEndPoint, + sessionMapRbtNode, nwGtpv1uCompareTeid) + +RB_GENERATE(NwGtpv1uOutstandingTxSeqNumTrxnMap, NwGtpv1uTrxn, + outstandingTxSeqNumMapRbtNode, nwGtpv1uCompareSeqNum) +RB_GENERATE(NwGtpv1uOutstandingRxSeqNumTrxnMap, NwGtpv1uTrxn, + outstandingRxSeqNumMapRbtNode, nwGtpv1uCompareSeqNum) +RB_GENERATE(NwGtpv1uTunnelEndPointTMap, NwGtpv1uTunnelEndPoint, + sessionMapRbtNode, nwGtpv1uCompareTeid) +RB_GENERATE(NwGtpv1uTunnelEndPointIdentifierMap, NwGtpv1uTunnelEndPoint, + sessionMapRbtNode, nwGtpv1uCompareTeid) + +/** + Comparator funtion for comparing two sessions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv1uCompareTeid(struct NwGtpv1uTunnelEndPoint *a, + struct NwGtpv1uTunnelEndPoint *b) +{ + if(a->teid > b->teid) { + return 1; + } + if(a->teid < b->teid) { + return -1; + } + return 0; +} + +/** + Comparator funtion for comparing two sequence number transactions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv1uCompareSeqNum(struct NwGtpv1uTrxn *a, struct NwGtpv1uTrxn *b) +{ + if(a->seqNum > b->seqNum) { + return 1; + } + if(a->seqNum < b->seqNum) { + return -1; + } + if(a->peerIp > b->peerIp) { + return 1; + } + if(a->peerIp < b->peerIp) { + return -1; + } + return 0; +} + +/** + Create and Send GTPU message. + + @param[in] thiz: Stack handle + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uCreateAndSendMsg( NwGtpv1uStackT *thiz, NwU32T peerIp, NwU16T peerPort, + NwGtpv1uMsgT *pMsg) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwU8T *msgHdr; + + NW_ASSERT(thiz); + NW_ASSERT(pMsg); + + NW_ENTER(thiz); + + msgHdr = pMsg->msgBuf; + NW_ASSERT(msgHdr != NULL); + + *(msgHdr++) = (pMsg->version << 5) | + (pMsg->protocolType << 4) | + (pMsg->extHdrFlag << 2) | + (pMsg->seqNumFlag << 1) | + (pMsg->npduNumFlag); + + *(msgHdr++) = (pMsg->msgType); + *((NwU16T *) msgHdr) = htons(pMsg->msgLen); + msgHdr += 2; + + *((NwU32T *) msgHdr) = htonl(pMsg->teid); + msgHdr += 4; + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, "nwGtpv1uCreateAndSendMsg to teid %u\n", pMsg->teid); + + if(pMsg->seqNumFlag || pMsg->extHdrFlag || pMsg->npduNumFlag) { + *((NwU16T *) msgHdr) = (pMsg->seqNumFlag ? htons(pMsg->seqNum) : 0x0000); + msgHdr += 2; + + *((NwU8T *) msgHdr) = (pMsg->npduNumFlag ? htons(pMsg->npduNum) : 0x00); + msgHdr++; + + *((NwU8T *) msgHdr) = (pMsg->extHdrFlag ? htons(pMsg->nextExtHdrType) : 0x00); + msgHdr++; + } + + rc = thiz->udp.udpDataReqCallback(thiz->udp.hUdp, + pMsg->msgBuf, + pMsg->msgLen, + peerIp, + peerPort); + + NW_LEAVE(thiz); + return rc; +} + +/** + * Send GTPv1u Message Indication to ULP entity. + * + * @param[in] hGtpuStackHandle : Stack handle + * @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uSendUlpMessageIndication( NW_IN NwGtpv1uStackT *thiz, + NW_IN NwU32T hUlpTrxn, + NW_IN NwU32T apiType, + NW_IN NwU32T msgType, + NW_IN NwU32T peerIp, + NW_IN NwU16T peerPort, + NW_IN NwU8T *pMsgBuf, + NW_IN NwU16T msgLength) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uUlpApiT ulpApi; + + NW_ENTER(thiz); + + ulpApi.apiType = apiType; + ulpApi.apiInfo.recvMsgInfo.msgType = msgType; + ulpApi.apiInfo.recvMsgInfo.hUlpTrxn = hUlpTrxn; + ulpApi.apiInfo.recvMsgInfo.peerIp = peerIp; + ulpApi.apiInfo.recvMsgInfo.peerPort = peerPort; + + if(pMsgBuf && msgLength) { + rc = nwGtpv1uMsgFromBufferNew((NwGtpv1uStackHandleT)thiz, pMsgBuf, msgLength, + &(ulpApi.apiInfo.recvMsgInfo.hMsg)); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + + rc = thiz->ulp.ulpReqCallback(thiz->ulp.hUlp, &ulpApi); + NW_ASSERT(rc == NW_GTPV1U_OK); + + NW_LEAVE(thiz); + + return rc; +} + +NwGtpv1uRcT +nwGtpv1uPeerRspTimeout(void *arg) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTrxnT *thiz; + NwGtpv1uTimeoutInfoT *timeoutInfo = arg; + + printf("Retransmission timer expired\n"); + + thiz = ((NwGtpv1uTrxnT *)timeoutInfo->timeoutArg); + rc = thiz->pStack->udp.udpDataReqCallback(thiz->pStack->udp.hUdp, + thiz->pMsg->msgBuf, + thiz->pMsg->msgLen, + thiz->peerIp, + thiz->peerPort); + + if(thiz->maxRetries) { + rc = thiz->pStack->tmrMgr.tmrStartCallback(thiz->pStack->tmrMgr.tmrMgrHandle, + 5, 0, NW_GTPV1U_TMR_TYPE_ONE_SHOT, (void *)timeoutInfo, &thiz->hRspTmr); + thiz->maxRetries--; + } else { + /* Inform session layer about path fialure */ + printf("Max retries over!\n"); + } + return rc; +} + +/*--------------------------------------------------------------------------- + * ULP API Processing Functions + *--------------------------------------------------------------------------*/ + +/** + Process NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT Request from ULP entity. + + @param[in] hGtpuStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +NwGtpv1uCreateTunnelEndPoint( NW_IN NwGtpv1uStackT *thiz, + NW_IN NwU32T teid, + NW_IN NwGtpv1uUlpSessionHandleT hUlpSession, + NW_OUT NwGtpv1uStackSessionHandleT *phStackSession ) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTunnelEndPointT *pTunnelEndPoint; + NwGtpv1uTunnelEndPointT *pCollision; + + NW_ENTER(thiz); + + pTunnelEndPoint = nwGtpTunnelEndPointNew(thiz); + + if(pTunnelEndPoint) { + + pTunnelEndPoint->teid = teid; + pTunnelEndPoint->pStack = thiz; + pTunnelEndPoint->hUlpSession = hUlpSession; + + pCollision = RB_INSERT(NwGtpv1uTunnelEndPointIdentifierMap, &(thiz->teidMap), + pTunnelEndPoint); + + if(pCollision) { + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, + "Tunnel end-point cannot be created for teid 0x%x. " + "Tunnel already exists", teid); + rc = nwGtpTunnelEndPointDestroy(thiz, pTunnelEndPoint); + NW_ASSERT(rc == NW_GTPV1U_OK); + *phStackSession = (NwGtpv1uStackSessionHandleT) 0; + NW_ASSERT(0); + rc = NW_GTPV1U_FAILURE; + } else { + *phStackSession = (NwGtpv1uStackSessionHandleT) pTunnelEndPoint; + pTunnelEndPoint = RB_FIND(NwGtpv1uTunnelEndPointIdentifierMap, + &(thiz->teidMap), pTunnelEndPoint); + NW_ASSERT(pTunnelEndPoint); + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, + "Tunnel end-point 0x%x creation successful for teid 0x%x", + (unsigned int)pTunnelEndPoint, teid); + } + + } else { + *phStackSession = (NwGtpv1uStackSessionHandleT) 0; + rc = NW_GTPV1U_FAILURE; + } + + NW_LEAVE(thiz); + return rc; +} + +/** + Process NW_GTPV1U_ULP_API_DESTROY_TUNNEL_ENDPOINT Request from ULP entity. + + @param[in] hGtpuStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uDestroyTunnelEndPoint( NwGtpv1uStackT *thiz, + NW_IN NwGtpv1uUlpApiT *pUlpReq) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTunnelEndPointT *pRemovedTeid; + + if(pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle) { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Destroying Tunnel end-point '%x'", + pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle); + pRemovedTeid = RB_REMOVE(NwGtpv1uTunnelEndPointIdentifierMap, &(thiz->teidMap), + (NwGtpv1uTunnelEndPointT *)( + pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle)); + + NW_ASSERT(pRemovedTeid == (NwGtpv1uTunnelEndPointT *)( + pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle)); + + rc = nwGtpTunnelEndPointDestroy(thiz, + (NwGtpv1uTunnelEndPointT *) + pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle); + } else { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Non-existent Tunnel end-point handle '%x'", + pUlpReq->apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle); + } + + return rc; +} + +/** + Process NW_GTPV1U_ULP_API_INITIAL_REQ Request from ULP entity. + + @param[in] hGtpuStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uInitialReq( NW_IN NwGtpv1uStackT *thiz, NW_IN NwGtpv1uUlpApiT *pUlpReq) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uTrxnT *pTrxn; + + NW_ENTER(thiz); + + /* Create New Transaction */ + rc = nwGtpv1uTrxnNew(thiz, &pTrxn); + + if(pTrxn) { + rc = nwGtpv1uTrxnCreateAndSendMsg(thiz, + pTrxn, + pUlpReq->apiInfo.initialReqInfo.peerIp, + pUlpReq->apiInfo.initialReqInfo.peerPort, + (NwGtpv1uMsgT *) pUlpReq->hMsg); + + if(rc == NW_GTPV1U_OK) { + /* Insert into search tree */ + RB_INSERT(NwGtpv1uOutstandingTxSeqNumTrxnMap, &(thiz->outstandingTxSeqNumMap), + pTrxn); + } else { + rc = nwGtpv1uTrxnDelete(&pTrxn); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + } + + NW_LEAVE(thiz); + + return rc; +} + +/** + Process NW_GTPV1U_ULP_API_SEND_TPDU Request from ULP entity. + + @param[in] thiz: Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uSendto( NwGtpv1uStackT *thiz, NW_IN NwGtpv1uUlpApiT *pUlpReq) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + + NW_ASSERT(thiz); + NW_ENTER(thiz); + + (void) nwGtpv1uMsgSetTeid(pUlpReq->apiInfo.sendtoInfo.hMsg, + pUlpReq->apiInfo.sendtoInfo.teid); + + rc = nwGtpv1uCreateAndSendMsg(thiz, + pUlpReq->apiInfo.sendtoInfo.ipAddr, + 2152, + (NwGtpv1uMsgT *) (NwGtpv1uMsgT *) pUlpReq->apiInfo.sendtoInfo.hMsg); + + NW_LEAVE(thiz); + return rc; +} + +/** + Process GPDU from UDP entity. + + @param[in] thiz: Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uProcessGpdu( NwGtpv1uStackT *thiz, + NW_IN NwU8T *gpdu, + NW_IN NwU32T gdpuLen, + NW_IN NwU32T peerIp) + +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uMsgHeaderT *msgHdr; + NwGtpv1uTunnelEndPointT *pTunnelEndPoint; + NwGtpv1uTunnelEndPointT tunnelEndPointKey; + + NW_ENTER(thiz); + + msgHdr = (NwGtpv1uMsgHeaderT *) gpdu; + + tunnelEndPointKey.teid = ntohl(msgHdr->teid); + pTunnelEndPoint = RB_FIND(NwGtpv1uTunnelEndPointIdentifierMap, + &(thiz->teidMap), &tunnelEndPointKey); + + if(pTunnelEndPoint) { + NwGtpv1uMsgHandleT hMsg; + + rc = nwGtpv1uMsgFromBufferNew( (NwGtpv1uStackHandleT)thiz, + (NwU8T *)gpdu, + gdpuLen, + &hMsg); + + if(NW_GTPV1U_OK == rc) { + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, + "Received T-PDU over tunnel end-point '%x' of size %u from "NW_IPV4_ADDR, + ntohl(msgHdr->teid), pMsg->msgLen, NW_IPV4_ADDR_FORMAT((peerIp))); + rc = nwGtpSessionSendMsgApiToUlpEntity(pTunnelEndPoint, pMsg); + } + } else { + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, + "Received T-PDU over non-existent tunnel end-point '%x' from "NW_IPV4_ADDR, + ntohl(msgHdr->teid), NW_IPV4_ADDR_FORMAT((peerIp))); + } + NW_LEAVE(thiz); + + return rc; +} + +/** + Handle Echo Request from Peer Entity. + + @param[in] thiz : Stack context + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uHandleEchoReq(NW_IN NwGtpv1uStackT *thiz, + NW_IN NwU8T *msgBuf, + NW_IN NwU32T msgBufLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwU16T seqNum = 0; + NwGtpv1uMsgHandleT hMsg = 0; + + seqNum = ntohs(*(NwU16T *) (msgBuf + (((*msgBuf) & 0x02) ? 8 : 4))); + + /* Send Echo Response */ + + rc = nwGtpv1uMsgNew( (NwGtpv1uStackHandleT)thiz, + NW_TRUE, /* SeqNum flag */ + NW_FALSE, + NW_FALSE, + NW_GTP_ECHO_RSP, /* Msg Type */ + 0x00000000U, /* TEID */ + seqNum, /* Seq Number */ + 0, + 0, + (&hMsg)); + + NW_ASSERT(NW_GTPV1U_OK == rc); + + /* + * The Restart Counter value in the Recovery information element shall + * not be used, i.e. it shall be set to zero by the sender and shall be + * ignored by the receiver. + */ + rc = nwGtpv1uMsgAddIeTV1(hMsg, NW_GTPV1U_IE_RECOVERY, 0x00); + + NW_LOG(thiz, NW_LOG_LEVEL_INFO, + "Sending NW_GTP_ECHO_RSP message to %x:%x with seq %u", peerIp, peerPort, + seqNum); + + rc = nwGtpv1uCreateAndSendMsg(thiz, + peerIp, + peerPort, + (NwGtpv1uMsgT *) hMsg); + + rc = nwGtpv1uMsgDelete((NwGtpv1uStackHandleT)thiz, hMsg); + NW_ASSERT(NW_GTPV1U_OK == rc); + + return rc; +} + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Constructor + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uInitialize( NW_INOUT NwGtpv1uStackHandleT *hGtpuStackHandle) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz; + + thiz = (NwGtpv1uStackT *) malloc( sizeof(NwGtpv1uStackT)); + memset(thiz, 0, sizeof(NwGtpv1uStackT)); + + if(thiz) { + thiz->id = (NwU32T) thiz; + thiz->seq = (NwU16T) ((NwU32T)thiz) ; + RB_INIT(&(thiz->outstandingTxSeqNumMap)); + RB_INIT(&(thiz->outstandingRxSeqNumMap)); + RB_INIT(&(thiz->sessionMap)); + RB_INIT(&(thiz->teidMap)); + if (0 == 1) { + nwGtpv1uDisplayBanner(); + } + + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + + + *hGtpuStackHandle = (NwGtpv1uStackHandleT) thiz; + return rc; +} + + +/*--------------------------------------------------------------------------- + * Destructor + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uFinalize( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + if(hGtpuStackHandle) { + free((void *)hGtpuStackHandle); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + return rc; +} + + +/*--------------------------------------------------------------------------- + * Configuration Get/Set + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uSetUlpEntity( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uUlpEntityT *pUlpEntity) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + if(pUlpEntity) { + thiz->ulp = *(pUlpEntity); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + + return rc; +} + + +NwGtpv1uRcT +nwGtpv1uSetUdpEntity( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uUdpEntityT *pUdpEntity) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + if(pUdpEntity) { + thiz->udp = *(pUdpEntity); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + + return rc; +} + +NwGtpv1uRcT +nwGtpv1uSetMemMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uMemMgrEntityT *pMemMgrEntity) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + if(pMemMgrEntity) { + thiz->memMgr = *(pMemMgrEntity); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + + return rc; +} + + +NwGtpv1uRcT +nwGtpv1uSetTimerMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uTimerMgrEntityT *pTmrMgrEntity) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + if(pTmrMgrEntity) { + thiz->tmrMgr = *(pTmrMgrEntity); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + + return rc; +} + + +NwGtpv1uRcT +nwGtpv1uSetLogMgrEntity( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uLogMgrEntityT *pLogMgrEntity) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + if(pLogMgrEntity) { + thiz->logMgr = *(pLogMgrEntity); + rc = NW_GTPV1U_OK; + } else { + rc = NW_GTPV1U_FAILURE; + } + return rc; +} + +NwGtpv1uRcT +nwGtpv1uSetLogLevel( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU32T logLevel) +{ + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + thiz->logLevel = logLevel; + return NW_GTPV1U_OK; +} + +/*--------------------------------------------------------------------------- + * Process Request from Udp Layer + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uProcessUdpReq( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU8T *udpData, + NW_IN NwU32T udpDataLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwGtpv1uRcT ret = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz; + NwU16T msgType; + + thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + NW_ASSERT(thiz); + + msgType = *((NwU8T *)(udpData + 1)); + + switch(msgType) { + case NW_GTP_ECHO_REQ: + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "NW_GTP_ECHO_REQ"); + ret = nwGtpv1uHandleEchoReq( thiz, udpData, udpDataLen, peerPort, peerIp); + break; + + case NW_GTP_ERROR_INDICATION: + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "NW_GTP_ERROR_INDICATION"); + ret = nwGtpv1uSendUlpMessageIndication( thiz, + 0, + NW_GTPV1U_ULP_API_RECV_MSG, + msgType, + peerIp, + peerPort, + udpData, + udpDataLen); + + NW_ASSERT(ret == NW_GTPV1U_OK); + + break; + + case NW_GTP_ECHO_RSP: + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "NW_GTP_ECHO_RSP"); + ret = NW_GTPV1U_OK; + break; + + case NW_GTP_GPDU: + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "NW_GTP_GPDU"); + ret = nwGtpv1uProcessGpdu(thiz, udpData, udpDataLen, peerIp); + break; + + default: + ret = NW_GTPV1U_FAILURE; + NW_ASSERT(0); + break; + } + + NW_LEAVE(thiz); + return ret; +} + + +/*--------------------------------------------------------------------------- + * Process Request from Upper Layer + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uProcessUlpReq( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uUlpApiT *pUlpReq) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz = (NwGtpv1uStackT *) hGtpuStackHandle; + + NW_ASSERT(thiz); + NW_ASSERT(pUlpReq != NULL); + + NW_ENTER(thiz); + + switch(pUlpReq->apiType) { + case NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT: { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received create session req from ulp"); + rc = NwGtpv1uCreateTunnelEndPoint(thiz, + pUlpReq->apiInfo.createTunnelEndPointInfo.teid, + pUlpReq->apiInfo.createTunnelEndPointInfo.hUlpSession, + &(pUlpReq->apiInfo.createTunnelEndPointInfo.hStackSession)); + } + break; + + case NW_GTPV1U_ULP_API_DESTROY_TUNNEL_ENDPOINT: { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received destroy session req from ulp"); + rc = nwGtpv1uDestroyTunnelEndPoint(thiz, pUlpReq); + } + break; + + case NW_GTPV1U_ULP_API_INITIAL_REQ: { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received initial req from ulp"); + rc = nwGtpv1uInitialReq(thiz, pUlpReq); + } + break; + + case NW_GTPV1U_ULP_API_SEND_TPDU: { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received send tpdu req from ulp"); + rc = nwGtpv1uSendto(thiz, pUlpReq); + } + break; + + default: + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, "Unsupported API received from ulp"); + rc = NW_GTPV1U_FAILURE; + break; + } + + NW_LEAVE(thiz); + + return rc; +} + +/*--------------------------------------------------------------------------- + * Process Timer timeout Request from Timer Manager + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwGtpv1uProcessTimeout(void *timeoutInfo) +{ + NwGtpv1uRcT rc = NW_GTPV1U_FAILURE; + NwGtpv1uStackT *thiz; + + NW_ASSERT(timeoutInfo != NULL); + + thiz = (NwGtpv1uStackT *) (((NwGtpv1uTimeoutInfoT *) timeoutInfo)->hStack); + + NW_ASSERT(thiz != NULL); + + NW_ENTER(thiz); + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, + "Received timeout event from ULP with timeoutInfo %x!", + (unsigned int)timeoutInfo); + + rc = (((NwGtpv1uTimeoutInfoT *) timeoutInfo)->timeoutCallbackFunc) (timeoutInfo); + + NW_LEAVE(thiz); + + return rc; +} + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uMsg.c b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uMsg.c new file mode 100644 index 0000000000..b2abe76361 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uMsg.c @@ -0,0 +1,479 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "NwTypes.h" +#include "NwLog.h" +#include "NwUtils.h" +#include "NwGtpv1uLog.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uPrivate.h" +#include "NwGtpv1uMsg.h" + +#define NW_GTPV1U_EPC_SPECIFIC_HEADER_SIZE (12) /**< Size of GTPv1u EPC specific header */ + +#ifdef __cplusplus +extern "C" { +#endif + +static NwGtpv1uMsgT *gpGtpv1uMsgPool = NULL; + +NwGtpv1uRcT +nwGtpv1uMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU8T seqNumFlag, + NW_IN NwU8T npduNumFlag, + NW_IN NwU8T extHdrFlag, + NW_IN NwU8T msgType, + NW_IN NwU8T teid, + NW_IN NwU16T seqNum, + NW_IN NwU8T npduNum, + NW_IN NwU8T nextExtHeader, + NW_OUT NwGtpv1uMsgHandleT *phMsg) +{ + NwGtpv1uStackT *pStack = (NwGtpv1uStackT *) hGtpuStackHandle; + NwGtpv1uMsgT *pMsg; + + if(gpGtpv1uMsgPool) { + pMsg = gpGtpv1uMsgPool; + gpGtpv1uMsgPool = gpGtpv1uMsgPool->next; + } else { + NW_GTPV1U_MALLOC(pStack, sizeof(NwGtpv1uMsgT), pMsg, NwGtpv1uMsgT *); + } + + + if(pMsg) { + pMsg->version = NW_GTPU_VERSION; + pMsg->protocolType = NW_GTP_PROTOCOL_TYPE_GTP; + pMsg->seqNumFlag = seqNumFlag; + pMsg->npduNumFlag = npduNumFlag; + pMsg->extHdrFlag = extHdrFlag; + pMsg->msgType = msgType; + + if(seqNumFlag) { + pMsg->seqNum = seqNum; + } + if(npduNumFlag) { + pMsg->npduNum = npduNum; + } + if(extHdrFlag) { + pMsg->nextExtHdrType = nextExtHeader; + } + + pMsg->msgLen = ((pMsg->seqNumFlag || pMsg->npduNumFlag + || pMsg->extHdrFlag) ? + NW_GTPV1U_EPC_SPECIFIC_HEADER_SIZE : (NW_GTPV1U_EPC_SPECIFIC_HEADER_SIZE - 4)); + + *phMsg = (NwGtpv1uMsgHandleT) pMsg; + return NW_GTPV1U_OK; + } + + return NW_GTPV1U_FAILURE; +} + +NwGtpv1uRcT +nwGtpv1uGpduMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU32T teid, + NW_IN NwU8T seqNumFlag, + NW_IN NwU16T seqNum, + NW_IN NwU8T *tpdu, + NW_IN NwU16T tpduLength, + NW_OUT NwGtpv1uMsgHandleT *phMsg) +{ + NwGtpv1uStackT *pStack = (NwGtpv1uStackT *) hGtpuStackHandle; + NwGtpv1uMsgT *pMsg; + + if(gpGtpv1uMsgPool) { + pMsg = gpGtpv1uMsgPool; + gpGtpv1uMsgPool = gpGtpv1uMsgPool->next; + } else { + NW_GTPV1U_MALLOC(pStack, sizeof(NwGtpv1uMsgT), pMsg, NwGtpv1uMsgT *); + } + + if(pMsg) { + pMsg->version = NW_GTPU_VERSION; + pMsg->protocolType = NW_GTP_PROTOCOL_TYPE_GTP; + pMsg->extHdrFlag = NW_FALSE; + pMsg->seqNumFlag = (seqNumFlag? NW_TRUE : NW_FALSE); + pMsg->npduNumFlag = NW_FALSE; + pMsg->msgType = NW_GTP_GPDU; + pMsg->teid = teid; + pMsg->seqNum = seqNum; + pMsg->npduNum = 0x00; + pMsg->nextExtHdrType= 0x00; + pMsg->msgLen = ((pMsg->seqNumFlag || pMsg->npduNumFlag + || pMsg->extHdrFlag ) ? + NW_GTPV1U_EPC_SPECIFIC_HEADER_SIZE : (NW_GTPV1U_EPC_SPECIFIC_HEADER_SIZE - 4)); + + memcpy(pMsg->msgBuf + pMsg->msgLen, tpdu, tpduLength); + pMsg->msgLen += tpduLength; + + *phMsg = (NwGtpv1uMsgHandleT) pMsg; + return NW_GTPV1U_OK; + } + + return NW_GTPV1U_FAILURE; +} + +NwGtpv1uRcT +nwGtpv1uMsgFromMsgNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uMsgHandleT hMsg, + NW_OUT NwGtpv1uMsgHandleT *phMsg) +{ + NwGtpv1uStackT *pStack = (NwGtpv1uStackT *) hGtpuStackHandle; + NwGtpv1uMsgT *pMsg; + + if(gpGtpv1uMsgPool) { + pMsg = gpGtpv1uMsgPool; + gpGtpv1uMsgPool = gpGtpv1uMsgPool->next; + } else { + NW_GTPV1U_MALLOC(pStack, sizeof(NwGtpv1uMsgT), pMsg, NwGtpv1uMsgT *); + } + + + if(pMsg) { + memcpy(pMsg, (NwGtpv1uMsgT *)hMsg, sizeof(NwGtpv1uMsgT)); + *phMsg = (NwGtpv1uMsgHandleT) pMsg; + return NW_GTPV1U_OK; + } + return NW_GTPV1U_FAILURE; +} + +NwGtpv1uRcT +nwGtpv1uMsgFromBufferNew( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwU8T *pBuf, + NW_IN NwU32T bufLen, + NW_OUT NwGtpv1uMsgHandleT *phMsg) +{ + NwGtpv1uStackT *pStack = (NwGtpv1uStackT *) hGtpuStackHandle; + NwGtpv1uMsgT *pMsg; + + if(gpGtpv1uMsgPool) { + pMsg = gpGtpv1uMsgPool; + gpGtpv1uMsgPool = gpGtpv1uMsgPool->next; + } else { + NW_GTPV1U_MALLOC(pStack, sizeof(NwGtpv1uMsgT), pMsg, NwGtpv1uMsgT *); + } + + + if(pMsg) { + memcpy(pMsg->msgBuf, pBuf, bufLen); + pMsg->msgLen = bufLen; + + pMsg->version = ((*pBuf) & 0xE0) >> 5; + pMsg->protocolType = ((*pBuf) & 0x10) >> 4; + pMsg->extHdrFlag = ((*pBuf) & 0x04) >> 2; + pMsg->seqNumFlag = ((*pBuf) & 0x02) >> 1; + pMsg->npduNumFlag = ((*pBuf) & 0x01); + pBuf++; + + pMsg->msgType = *(pBuf); + pBuf++; + + pBuf += 2; + + pMsg->teid = ntohl(*((NwU32T *)pBuf)); + pBuf += 4; + + if(pMsg->extHdrFlag || pMsg->seqNumFlag || pMsg->npduNumFlag) { + pMsg->seqNum = ntohs(*(((NwU16T *)pBuf))); + pBuf += 2; + pMsg->npduNum = *(pBuf++); + pMsg->nextExtHdrType = *(pBuf++); + } + *phMsg = (NwGtpv1uMsgHandleT) pMsg; + return NW_GTPV1U_OK; + } + return NW_GTPV1U_FAILURE; +} + +NwGtpv1uRcT +nwGtpv1uMsgDelete( NW_IN NwGtpv1uStackHandleT hGtpuStackHandle, + NW_IN NwGtpv1uMsgHandleT hMsg) +{ + ((NwGtpv1uMsgT *)hMsg)->next = gpGtpv1uMsgPool; + gpGtpv1uMsgPool = (NwGtpv1uMsgT *) hMsg; + return NW_GTPV1U_OK; +} + +/** + * Set TEID for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[in] teid: TEID value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgSetTeid(NW_IN NwGtpv1uMsgHandleT hMsg, NwU32T teid) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + thiz->teid = teid; + printf("nwGtpv1uMsgSetTeid() teid %u", teid); + return NW_GTPV1U_OK; +} + +/** + * Set sequence for gtpv1u message. + * + * @param[in] hMsg : Message handle. + * @param[in] seqNum: Flag boolean value. + */ + +NwGtpv1uRcT +nwGtpv1uMsgSetSeqNumber(NW_IN NwGtpv1uMsgHandleT hMsg, NwU32T seqNum) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + thiz->seqNum = seqNum; + return NW_GTPV1U_OK; +} + +/** + * Get TEID present for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv1uMsgGetTeid(NW_IN NwGtpv1uMsgHandleT hMsg) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + return (thiz->teid); +} + + +/** + * Get sequence number for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv1uMsgGetSeqNumber(NW_IN NwGtpv1uMsgHandleT hMsg) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + return (thiz->seqNum); +} + +/** + * Get msg type for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv1uMsgGetMsgType(NW_IN NwGtpv1uMsgHandleT hMsg) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + return (thiz->msgType); +} + +/** + * Get tpdu for gtpv1u message. + * + * @param[in] hMsg : Message handle. + */ + +NwGtpv1uRcT +nwGtpv1uMsgGetTpdu(NW_IN NwGtpv1uMsgHandleT hMsg, NwU8T *pTpduBuf, + NwU32T *pTpduLength) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + NwU8T headerLength = ((thiz->seqNumFlag || thiz->extHdrFlag + || thiz->npduNumFlag) ? 12 : 8); + + *pTpduLength = thiz->msgLen - headerLength; + memcpy(pTpduBuf, thiz->msgBuf + headerLength, *pTpduLength); + return NW_GTPV1U_OK; +} + +NwU8T * +nwGtpv1uMsgGetTpduHandle(NW_IN NwGtpv1uMsgHandleT hMsg) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + return (thiz->msgBuf + ((thiz->seqNumFlag || thiz->extHdrFlag + || thiz->npduNumFlag) ? 12 : 8)); +} + +NwU32T +nwGtpv1uMsgGetTpduLength(NW_IN NwGtpv1uMsgHandleT hMsg) +{ + NwGtpv1uMsgT *thiz = (NwGtpv1uMsgT *) hMsg; + return (thiz->msgLen - ((thiz->seqNumFlag || thiz->extHdrFlag + || thiz->npduNumFlag) ? 12 : 8)); +} + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV1(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T value) +{ + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NwGtpv1uIeTv1T *pIe; + + pIe = (NwGtpv1uIeTv1T *) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->v = value; + + pMsg->msgLen += sizeof(NwGtpv1uIeTv1T); + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV2(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU16T value) +{ + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NwGtpv1uIeTv2T *pIe; + + pIe = (NwGtpv1uIeTv2T *) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->v = htons(value); + + pMsg->msgLen += sizeof(NwGtpv1uIeTv2T); + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwGtpv1uMsgAddIeTV4(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU32T value) +{ + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NwGtpv1uIeTv4T *pIe; + + pIe = (NwGtpv1uIeTv4T *) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->v = htonl(value); + + pMsg->msgLen += sizeof(NwGtpv1uIeTv4T); + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwGtpv1uMsgAddIe(NW_IN NwGtpv1uMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU8T *pVal) +{ + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NwGtpv1uIeTlvT *pIe; + + pIe = (NwGtpv1uIeTlvT *) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->l = htons(length); + + memcpy(pIe + 4, pVal, length); + pMsg->msgLen += (4 + length); + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwGtpv1uMsgHexDump(NwGtpv1uMsgHandleT hMsg, FILE *fp) +{ + + NwGtpv1uMsgT *pMsg = (NwGtpv1uMsgT *) hMsg; + NwU8T *data = pMsg->msgBuf; + NwU32T size = pMsg->msgLen; + + unsigned char *p = (unsigned char *)data; + unsigned char c; + int n; + char bytestr[4] = {0}; + char addrstr[10] = {0}; + char hexstr[ 16*3 + 5] = {0}; + char charstr[16*1 + 5] = {0}; + fprintf((FILE *)fp, "\n"); + for(n=1; n<=size; n++) { + if (n%16 == 1) { + /* store address for this line */ + snprintf(addrstr, sizeof(addrstr), "%.4x", + ((unsigned int)p-(unsigned int)data) ); + } + + c = *p; + if (isalnum(c) == 0) { + c = '.'; + } + + /* store hex str (for left side) */ + snprintf(bytestr, sizeof(bytestr), "%02X ", *p); + strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); + + /* store char str (for right side) */ + snprintf(bytestr, sizeof(bytestr), "%c", c); + strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); + if(n%16 == 0) { + /* line completed */ + fprintf((FILE *)fp, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } else if(n%8 == 0) { + /* half line: add whitespaces */ + strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); + strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); + } + p++; /* next byte */ + } + + if (strlen(hexstr) > 0) { + /* print rest of buffer if not empty */ + fprintf((FILE *)fp, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + + } + fprintf((FILE *)fp, "\n"); + + return NW_GTPV1U_OK; +} + +#ifdef __cplusplus +} +#endif + + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTrxn.c b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTrxn.c new file mode 100644 index 0000000000..36f1d24c26 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTrxn.c @@ -0,0 +1,391 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "NwTypes.h" +#include "NwLog.h" +#include "NwUtils.h" +#include "NwGtpv1uLog.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uPrivate.h" +#include "NwGtpv1uTrxn.h" + +/*--------------------------------------------------------------------------* + * P R I V A T E D E C L A R A T I O N S * + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +static NwGtpv1uTrxnT *gpGtpv1uTrxnPool = NULL; + +/*--------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Send msg retransmission to peer via data request to UDP Entity + *--------------------------------------------------------------------------*/ + +static NwGtpv1uRcT +nwGtpv1uTrxnSendMsgRetransmission(NwGtpv1uTrxnT *thiz) +{ + NwGtpv1uRcT rc; + + NW_ASSERT(thiz); + NW_ASSERT(thiz->pMsg); + + rc = thiz->pStack->udp.udpDataReqCallback(thiz->pStack->udp.hUdp, + thiz->pMsg->msgBuf, + thiz->pMsg->msgLen, + thiz->peerIp, + thiz->peerPort); + + return rc; +} + +static NwGtpv1uRcT +nwGtpv1uTrxnPeerRspTimeout(void *arg) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTrxnT *thiz; + NwGtpv1uStackT *pStack; + NwGtpv1uTimeoutInfoT *timeoutInfo = arg; + + thiz = ((NwGtpv1uTrxnT *)timeoutInfo->timeoutArg); + pStack = thiz->pStack; + + NW_ASSERT(pStack); + + NW_LOG(pStack, NW_LOG_LEVEL_WARN, "T3 timer expired for transaction 0x%x", + (unsigned int)thiz); + + rc = nwGtpv1uTrxnSendMsgRetransmission(thiz); + + if(thiz->maxRetries) { + rc = pStack->tmrMgr.tmrStartCallback(pStack->tmrMgr.tmrMgrHandle, + thiz->t3Timer, 0, NW_GTPV1U_TMR_TYPE_ONE_SHOT, (void *)timeoutInfo, + &thiz->hRspTmr); + thiz->maxRetries--; + } else { + NwGtpv1uUlpApiT ulpApi; + ulpApi.apiType = NW_GTPV1U_ULP_API_RSP_FAILURE; + ulpApi.apiInfo.recvMsgInfo.msgType = nwGtpv1uMsgGetMsgType(( + NwGtpv1uMsgHandleT)thiz->pMsg); + ulpApi.apiInfo.recvMsgInfo.hUlpTrxn = thiz->hUlpTrxn; + ulpApi.apiInfo.recvMsgInfo.peerIp = thiz->peerIp; + ulpApi.apiInfo.recvMsgInfo.peerPort = thiz->peerPort; + thiz->hRspTmr = 0; + + rc = nwGtpv1uTrxnDelete(&thiz); + NW_ASSERT(rc == NW_GTPV1U_OK); + + rc = pStack->ulp.ulpReqCallback(pStack->ulp.hUlp, &ulpApi); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + return rc; +} + +/** + Send timer start request to TmrMgr Entity. + + @param[in] thiz : Pointer to transaction + @param[in] timeoutCallbackFunc : Timeout handler callback function. + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uTrxnStartPeerRspTimer(NwGtpv1uTrxnT *thiz, + NwGtpv1uRcT (*timeoutCallbackFunc)(void *)) +{ + NwGtpv1uRcT rc; + NwGtpv1uTimeoutInfoT *timeoutInfo; + + NW_ASSERT(thiz->pStack->tmrMgr.tmrStartCallback != NULL); + + timeoutInfo = &thiz->peerRspTimeoutInfo; + timeoutInfo->timeoutArg = thiz; + timeoutInfo->timeoutCallbackFunc = timeoutCallbackFunc; + timeoutInfo->hStack = (NwGtpv1uStackHandleT)thiz->pStack; + + rc = thiz->pStack->tmrMgr.tmrStartCallback(thiz->pStack->tmrMgr.tmrMgrHandle, + thiz->t3Timer, 0, NW_GTPV1U_TMR_TYPE_ONE_SHOT, (void *)timeoutInfo, + &thiz->hRspTmr); + + return rc; +} + +/** + Send timer stop request to TmrMgr Entity. + + @param[in] thiz : Pointer to transaction + @return NW_GTPV1U_OK on success. + */ + +static NwGtpv1uRcT +nwGtpv1uTrxnStopPeerRspTimer(NwGtpv1uTrxnT *thiz) +{ + NwGtpv1uRcT rc; + + NW_ASSERT(thiz->pStack->tmrMgr.tmrStopCallback != NULL); + + rc = thiz->pStack->tmrMgr.tmrStopCallback(thiz->pStack->tmrMgr.tmrMgrHandle, + thiz->hRspTmr); + + thiz->hRspTmr = 0; + + return rc; +} + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/** + * Constructor + * + * @param[in] thiz : Pointer to stack + * @param[out] ppTrxn : Pointer to pointer to Trxn object. + * @return NW_GTPV1U_OK on success. + */ +NwGtpv1uRcT +nwGtpv1uTrxnNew( NW_IN NwGtpv1uStackT *thiz, + NW_OUT NwGtpv1uTrxnT **ppTrxn) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTrxnT *pTrxn; + + if(gpGtpv1uTrxnPool) { + pTrxn = gpGtpv1uTrxnPool; + gpGtpv1uTrxnPool = gpGtpv1uTrxnPool->next; + } else { + NW_GTPV1U_MALLOC(thiz, sizeof(NwGtpv1uTrxnT), pTrxn, NwGtpv1uTrxnT *); + } + + if (pTrxn) { + pTrxn->maxRetries = 2; + pTrxn->pStack = thiz; + pTrxn->t3Timer = 2; + pTrxn->seqNum = thiz->seq; + + /* Increment sequence number */ + thiz->seq++; + if(thiz->seq == 0x800000) { + thiz->seq = 0; + } + + } else { + rc = NW_GTPV1U_FAILURE; + } + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Created transaction 0x%X", (unsigned int)pTrxn); + + *ppTrxn = pTrxn; + + return rc; +} + +/** + * Overloaded Constructor + * + * @param[in] thiz : Pointer to stack. + * @param[in] seqNum : Sequence number for this transaction. + * @param[out] ppTrxn : Pointer to pointer to Trxn object. + * @return NW_GTPV1U_OK on success. + */ +NwGtpv1uRcT +nwGtpv1uTrxnWithSeqNew( NW_IN NwGtpv1uStackT *thiz, + NW_IN NwU32T seqNum, + NW_OUT NwGtpv1uTrxnT **ppTrxn) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uTrxnT *pTrxn; + + if(gpGtpv1uTrxnPool) { + pTrxn = gpGtpv1uTrxnPool; + gpGtpv1uTrxnPool = gpGtpv1uTrxnPool->next; + } else { + NW_GTPV1U_MALLOC(thiz, sizeof(NwGtpv1uTrxnT), pTrxn, NwGtpv1uTrxnT *); + } + + + if (pTrxn) { + pTrxn->maxRetries = 2; + pTrxn->pStack = thiz; + pTrxn->t3Timer = 2; + pTrxn->seqNum = seqNum; + pTrxn->pMsg = NULL; + } else { + rc = NW_GTPV1U_FAILURE; + } + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Created transaction 0x%X", (unsigned int)pTrxn); + + *ppTrxn = pTrxn; + + return rc; +} + +/** + * Destructor + * + * @param[out] pthiz : Pointer to pointer to Trxn object. + * @return NW_GTPV1U_OK on success. + */ +NwGtpv1uRcT +nwGtpv1uTrxnDelete( NW_INOUT NwGtpv1uTrxnT **pthiz) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uStackT *pStack; + NwGtpv1uTrxnT *thiz = *pthiz; + + pStack = thiz->pStack; + + if(thiz->hRspTmr) { + rc = nwGtpv1uTrxnStopPeerRspTimer(thiz); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + + if(thiz->pMsg) { + rc = nwGtpv1uMsgDelete((NwGtpv1uStackHandleT)pStack, + (NwGtpv1uMsgHandleT)thiz->pMsg); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + + thiz->next = gpGtpv1uTrxnPool; + gpGtpv1uTrxnPool = thiz; + + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Purged transaction 0x%X", (unsigned int)thiz); + + *pthiz = NULL; + return rc; +} + + +#if 1 +/** + * Send msg to peer via data request to UDP Entity + * + * @param[in] thiz : Pointer to stack. + * @param[in] pTrxn : Pointer to Trxn object. + * @param[in] peerIp : Peer Ip address. + * @param[in] peerPort : Peer Ip port. + * @param[in] pMsg : Message to be sent. + * @return NW_GTPV1U_OK on success. + */ +NwGtpv1uRcT +nwGtpv1uTrxnCreateAndSendMsg( NW_IN NwGtpv1uStackT *thiz, + NW_IN NwGtpv1uTrxnT *pTrxn, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwGtpv1uMsgT *pMsg) +{ + NwGtpv1uRcT rc; + NwU8T *msgHdr; + + NW_ASSERT(thiz); + NW_ASSERT(pMsg); + + msgHdr = pMsg->msgBuf; + NW_ASSERT(msgHdr != NULL); + + *(msgHdr++) = (pMsg->version << 5) | + (pMsg->protocolType << 4) | + (pMsg->extHdrFlag << 2) | + (pMsg->seqNumFlag << 1) | + (pMsg->npduNumFlag); + + *(msgHdr++) = (pMsg->msgType); + *((NwU16T *) msgHdr) = htons(pMsg->msgLen); + msgHdr += 2; + + *((NwU32T *) msgHdr) = htonl(pMsg->teid); + msgHdr += 4; + + if(pMsg->seqNumFlag | pMsg->extHdrFlag | pMsg->npduNumFlag) { + if(pMsg->seqNumFlag) { + *((NwU16T *) msgHdr) = htons((pTrxn ? pTrxn->seqNum : pMsg->seqNum)); + } else { + *((NwU16T *) msgHdr) = 0x0000; + } + msgHdr += 2; + + if(pMsg->npduNumFlag) { + *((NwU8T *) msgHdr) = pMsg->npduNumFlag; + } else { + *((NwU8T *) msgHdr) = 0x00; + } + msgHdr++; + + if(pMsg->extHdrFlag) { + *((NwU8T *) msgHdr) = pMsg->extHdrFlag; + } else { + *((NwU8T *) msgHdr) = 0x00; + } + msgHdr++; + } + + NW_ASSERT(thiz->udp.udpDataReqCallback != NULL); + + rc = thiz->udp.udpDataReqCallback(thiz->udp.hUdp, + pMsg->msgBuf, + pMsg->msgLen, + peerIp, + peerPort); + + /* Save the message for retransmission */ + if(rc == NW_GTPV1U_OK && pTrxn) { + pTrxn->pMsg = pMsg; + pTrxn->peerIp = peerIp; + pTrxn->peerPort = peerPort; + + rc = nwGtpv1uTrxnStartPeerRspTimer(pTrxn, nwGtpv1uTrxnPeerRspTimeout); + NW_ASSERT(rc == NW_GTPV1U_OK); + } + + return rc; +} +#endif + + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c new file mode 100644 index 0000000000..b4dcef0145 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/src/NwGtpv1uTunnelEndPoint.c @@ -0,0 +1,134 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwGtpv1uError.h" +#include "NwGtpv1uPrivate.h" +#include "NwGtpv1uMsg.h" +#include "NwGtpv1uTunnelEndPoint.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uLog.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------* + * P R I V A T E D E C L A R A T I O N S * + *--------------------------------------------------------------------------*/ + +static NwGtpv1uTunnelEndPointT *gpTunnelEndPointPool = NULL; + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/** + Constructor + + @param[in] msid: MSID + @param[in] peerAddr: Address of the peer. + @return Pointer to Session on success, NULL on failure. + */ + + +NwGtpv1uTunnelEndPointT * +nwGtpTunnelEndPointNew(struct NwGtpv1uStack *pStack) +{ + NwGtpv1uTunnelEndPointT *thiz; + if(gpTunnelEndPointPool) { + thiz = gpTunnelEndPointPool; + gpTunnelEndPointPool = gpTunnelEndPointPool->next; + } else { + NW_GTPV1U_MALLOC(pStack, sizeof(NwGtpv1uTunnelEndPointT), thiz, + NwGtpv1uTunnelEndPointT *); + } + + return thiz; +} + +/** + Destructor + + @param[in] thiz: Pointer to session + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpTunnelEndPointDestroy(struct NwGtpv1uStack *pStack, + NwGtpv1uTunnelEndPointT *thiz) +{ + thiz->next = gpTunnelEndPointPool; + gpTunnelEndPointPool = thiz; + return NW_GTPV1U_OK; +} + +/** + Purge a Transaction for a Session. + + @param[in] thiz: Pointer to session + @param[in,out] pTrxn: Pointer to the trxn. + @return NW_GTPV1U_OK on success. + */ + +NwGtpv1uRcT +nwGtpSessionSendMsgApiToUlpEntity(NwGtpv1uTunnelEndPointT *thiz, + NwGtpv1uMsgT *pMsg) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwGtpv1uUlpApiT api; + + api.apiType = NW_GTPV1U_ULP_API_RECV_TPDU; + api.apiInfo.recvMsgInfo.hUlpSession = thiz->hUlpSession; + api.apiInfo.recvMsgInfo.teid = thiz->teid; + api.apiInfo.recvMsgInfo.hMsg = (NwGtpv1uMsgHandleT)pMsg; + + NW_ASSERT(thiz->pStack->ulp.ulpReqCallback != NULL); + + thiz->pStack->ulp.ulpReqCallback(thiz->pStack->ulp.hUlp, &api); + + return rc; +} + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.am b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.am new file mode 100644 index 0000000000..69b8e698e9 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.am @@ -0,0 +1,5 @@ +# this is example-file: Makefile.am + +# the subdirectories of the project to go into +SUBDIRS = \ + nw-helloworld diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.in b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.in new file mode 100644 index 0000000000..46928b9e3c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/Makefile.in @@ -0,0 +1,461 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# this is example-file: Makefile.am +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = nw-gtpv1u/test-app +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# the subdirectories of the project to go into +SUBDIRS = \ + nw-helloworld + +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu nw-gtpv1u/test-app/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu nw-gtpv1u/test-app/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic ctags \ + ctags-recursive distclean distclean-generic distclean-tags \ + distdir dvi dvi-am html html-am info info-am install \ + install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \ + tags-recursive uninstall uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.am b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.am new file mode 100644 index 0000000000..f60cd93f55 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.am @@ -0,0 +1,17 @@ +bin_PROGRAMS = helloworld + +AM_CFLAGS = -D__WITH_LIBEVENT__ -I../../shared -I../../include -I../../test-app/nw-udp -I../../test-app/nw-log @AM_CFLAGS@ + +helloworld_SOURCES = \ + NwEvt.h\ + NwMiniLogMgrEntity.h\ + NwMiniTmrMgrEntity.h\ + NwMiniUlpEntity.h\ + NwMiniUdpEntity.h\ + NwMiniLogMgrEntity.c\ + NwMiniTmrMgrEntity.c\ + NwMiniUlpEntity.c\ + NwMiniUdpEntity.c\ + helloworld.c + +helloworld_LDADD = ../../src/libNwGtpv1u.a -levent $(AM_LDFLAGS) diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.in b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.in new file mode 100644 index 0000000000..769d75c16b --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/Makefile.in @@ -0,0 +1,433 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = helloworld$(EXEEXT) +subdir = nw-gtpv1u/test-app/nw-helloworld +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_helloworld_OBJECTS = NwMiniLogMgrEntity.$(OBJEXT) \ + NwMiniTmrMgrEntity.$(OBJEXT) NwMiniUlpEntity.$(OBJEXT) \ + NwMiniUdpEntity.$(OBJEXT) helloworld.$(OBJEXT) +helloworld_OBJECTS = $(am_helloworld_OBJECTS) +am__DEPENDENCIES_1 = +helloworld_DEPENDENCIES = ../../src/libNwGtpv1u.a \ + $(am__DEPENDENCIES_1) +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(helloworld_SOURCES) +DIST_SOURCES = $(helloworld_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = -D__WITH_LIBEVENT__ -I../../shared -I../../include -I../../test-app/nw-udp -I../../test-app/nw-log @AM_CFLAGS@ +AM_LDFLAGS = @AM_LDFLAGS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +helloworld_SOURCES = \ + NwEvt.h\ + NwMiniLogMgrEntity.h\ + NwMiniTmrMgrEntity.h\ + NwMiniUlpEntity.h\ + NwMiniUdpEntity.h\ + NwMiniLogMgrEntity.c\ + NwMiniTmrMgrEntity.c\ + NwMiniUlpEntity.c\ + NwMiniUdpEntity.c\ + helloworld.c + +helloworld_LDADD = ../../src/libNwGtpv1u.a -levent $(AM_LDFLAGS) +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu nw-gtpv1u/test-app/nw-helloworld/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu nw-gtpv1u/test-app/nw-helloworld/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +helloworld$(EXEEXT): $(helloworld_OBJECTS) $(helloworld_DEPENDENCIES) + @rm -f helloworld$(EXEEXT) + $(LINK) $(helloworld_OBJECTS) $(helloworld_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NwMiniLogMgrEntity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NwMiniTmrMgrEntity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NwMiniUdpEntity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NwMiniUlpEntity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/helloworld.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-binPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwEvt.h b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwEvt.h new file mode 100644 index 0000000000..da02372e2a --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwEvt.h @@ -0,0 +1,81 @@ +/*----------------------------------------------------------------------------* + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_EVT_H__ +#define __NW_EVT_H__ +/** + * @file NwEvt.h + * @brief +*/ + +#ifdef __WITH_LIBEVENT__ + +#include <event.h> + +typedef struct event NwEventT; + +#define NW_EVT_READ (EV_READ) +#define NW_EVT_PERSIST (EV_PERSIST) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) + +#define NW_EVT_INIT event_init +#define NW_EVT_LOOP event_dispatch + +#define NW_EVENT_ADD(__ev, __evSelObj, __evCallback, __evCallbackArg, __evFlags) \ + do { \ + event_set(&(__ev), __evSelObj, __evFlags, __evCallback, __evCallbackArg); \ + event_add(&(__ev), NULL); \ + } while(0) + +#else + +#warning "Event library not defined!" + +/* HACK : Defining dummy values for compilation!*/ + +typedef struct +{ + int __tbd; +} NwEventT; + +#define NW_EVT_READ (0) +#define NW_EVT_PERSIST (1) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(void *arg) + + +#define NW_EVT_INIT() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVT_LOOP() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVENT_ADD(...) do { printf("error: Event library not defined!\n"); exit (0); } while(0) + + +#endif + +#endif /* __NW_EVT_H__ */ diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.c b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.c new file mode 100644 index 0000000000..f2484d545e --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.c @@ -0,0 +1,60 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwLog.h" +#include "NwEvt.h" +#include "NwGtpv1u.h" + +#include "NwMiniLogMgrEntity.h" + +#ifdef __cplusplus +extern "C" { +#endif + +NwU32T g_log_level = NW_LOG_LEVEL_INFO; + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT nwMiniLogMgrInit(NwMiniLogMgrT *thiz, NwU32T logLevel ) +{ + thiz->logLevel = logLevel; + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT nwMiniLogMgrSetLogLevel(NwMiniLogMgrT *thiz, NwU32T logLevel) +{ + thiz->logLevel = logLevel; +} + +NwGtpv1uRcT nwMiniLogMgrLogRequest (NwGtpv1uLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT *file, + NwU32T line, + NwCharT *logStr) +{ + NwMiniLogMgrT *thiz = (NwMiniLogMgrT *) hLogMgr; + if(thiz->logLevel >= logLevel) { + printf("NWGTPv2U-STK %s - %s <%s,%u>\n", gLogLevelStr[logLevel], logStr, + basename(file), line); + } + return NW_GTPV1U_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.h b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.h new file mode 100644 index 0000000000..a6015f7278 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniLogMgrEntity.h @@ -0,0 +1,58 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_LOG_MGR_H__ +#define __NW_MINI_LOG_MGR_H__ + +extern NwU32T g_log_level; + + +#define NW_LOG( _logLevel, ...) \ + do { \ + if(g_log_level >= _logLevel) \ + { \ + char _logStr[1024]; \ + snprintf(_logStr, 1024, __VA_ARGS__); \ + printf("NWGTPv2U-APP %s - %s <%s,%u>\n", gLogLevelStr[_logLevel], _logStr, basename(__FILE__), __LINE__);\ + } \ + } while(0) + +typedef struct +{ + NwU8T logLevel; +} NwMiniLogMgrT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv1uRcT nwMiniLogMgrLogRequest (NwGtpv1uLogMgrHandleT logMgrHandle, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.c b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.c new file mode 100644 index 0000000000..defc860c8f --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.c @@ -0,0 +1,101 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv1u.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static void +NW_TMR_CALLBACK(nwMiniTmrMgrHandleTimeout) +{ + NwGtpv1uRcT rc; + NwMiniTmrMgrEntityT *pTmr = (NwMiniTmrMgrEntityT *) arg; + + /*--------------------------------------------------------------------------- + * Send Timeout Request to GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + rc = nwGtpv1uProcessTimeout(pTmr->timeoutArg); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + free(pTmr); + + return; +} + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT nwTimerStart( NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void *timeoutArg, + NwGtpv1uTimerHandleT *hTmr) +{ + NwGtpv1uRcT rc = NW_GTPV1U_OK; + NwMiniTmrMgrEntityT *pTmr; + struct timeval tv; + + NW_LOG(NW_LOG_LEVEL_INFO, + "Received start timer request from stack with timer type %u, arg %x, for %u sec and %u usec", + tmrType, timeoutArg, timeoutSec, timeoutUsec); + + pTmr = (NwMiniTmrMgrEntityT *) malloc (sizeof(NwMiniTmrMgrEntityT)); + + /* set the timevalues*/ + timerclear(&tv); + tv.tv_sec = timeoutSec; + tv.tv_usec = timeoutUsec; + + pTmr->timeoutArg = timeoutArg; + evtimer_set(&pTmr->ev, nwMiniTmrMgrHandleTimeout, pTmr); + + /*add event*/ + + event_add(&(pTmr->ev), &tv); + + *hTmr = (NwGtpv1uTimerHandleT)pTmr; + + return rc; +} + +NwGtpv1uRcT nwTimerStop( NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwGtpv1uTimerHandleT hTmr) +{ + NW_LOG(NW_LOG_LEVEL_INFO, + "Received stop timer request from stack for timer handle %u", hTmr); + evtimer_del(&(((NwMiniTmrMgrEntityT *)hTmr)->ev)); + free((void *)hTmr); + return NW_GTPV1U_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.h b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.h new file mode 100644 index 0000000000..6e2c5a0dcd --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniTmrMgrEntity.h @@ -0,0 +1,54 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_TMR_MGR_H__ +#define __NW_MINI_TMR_MGR_H__ + +typedef struct +{ + NwEventT ev; + void* timeoutArg; +} NwMiniTmrMgrEntityT; + + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv1uRcT nwTimerStart( NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void* timeoutArg, + NwGtpv1uTimerHandleT* hTmr); + + +NwGtpv1uRcT nwTimerStop( NwGtpv1uTimerMgrHandleT tmrMgrHandle, + NwGtpv1uTimerHandleT hTmr); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.c b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.c new file mode 100644 index 0000000000..46b5b46bee --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.c @@ -0,0 +1,155 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> + +#include "NwEvt.h" +#include "NwGtpv1u.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUdpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#define MAX_UDP_PAYLOAD_LEN (4096) + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static +void NW_TMR_CALLBACK(nwUdpDataIndicationCallbackData) +{ + NwGtpv1uRcT rc; + NwU8T udpBuf[MAX_UDP_PAYLOAD_LEN]; + NwS32T bytesRead; + NwU32T peerLen; + struct sockaddr_in peer; + NwMiniUdpEntityT *thiz = (NwMiniUdpEntityT *) arg; + + peerLen = sizeof(peer); + + bytesRead = recvfrom(thiz->hSocket, udpBuf, MAX_UDP_PAYLOAD_LEN , 0, + (struct sockaddr *) &peer,(socklen_t *) &peerLen); + if(bytesRead) { + NW_LOG(NW_LOG_LEVEL_DEBG, "Received UDP message of length %u from %X:%u", + bytesRead, ntohl(peer.sin_addr.s_addr), ntohs(peer.sin_port)); + rc = nwGtpv1uProcessUdpReq(thiz->hGtpv1uStack, udpBuf, bytesRead, + peer.sin_port, peer.sin_addr.s_addr); + } else { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + } +} + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT nwMiniUdpInit(NwMiniUdpEntityT *thiz, + NwGtpv1uStackHandleT hGtpv1uStack, NwU8T *ipAddr) +{ + int sd; + struct sockaddr_in addr; + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(2152); + addr.sin_addr.s_addr = inet_addr(ipAddr); + memset(addr.sin_zero, '\0', sizeof (addr.sin_zero)); + + if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + event_set(&(thiz->ev), sd, EV_READ|EV_PERSIST, nwUdpDataIndicationCallbackData, + thiz); + event_add(&(thiz->ev), NULL); + + thiz->hSocket = sd; + thiz->hGtpv1uStack = hGtpv1uStack; + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT nwMiniUdpDestroy(NwMiniUdpEntityT *thiz) +{ + close(thiz->hSocket); +} + +NwGtpv1uRcT nwMiniUdpDataReq(NwGtpv1uUdpHandleT udpHandle, + NwU8T *dataBuf, + NwU32T dataSize, + NwU32T peerIpAddr, + NwU32T peerPort) +{ + struct sockaddr_in peerAddr; + NwS32T bytesSent; + NwMiniUdpEntityT *thiz = (NwMiniUdpEntityT *) udpHandle; + + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(peerPort); + peerAddr.sin_addr.s_addr = (peerIpAddr); + memset(peerAddr.sin_zero, '\0', sizeof (peerAddr.sin_zero)); + + NW_LOG(NW_LOG_LEVEL_DEBG, + "Sending %u bytes on handle 0x%x to peer %u.%u.%u.%u:%u", dataSize, udpHandle, + (peerIpAddr & 0x000000ff), + (peerIpAddr & 0x0000ff00) >> 8, + (peerIpAddr & 0x00ff0000) >> 16, + (peerIpAddr & 0xff000000) >> 24, + peerPort); + + bytesSent = sendto (thiz->hSocket, dataBuf, dataSize, 0, + (struct sockaddr *) &peerAddr, sizeof(peerAddr)); + + if(bytesSent < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + } else { + NW_LOG(NW_LOG_LEVEL_DEBG, "Sent %u bytes on handle 0x%x to peer %u.%u.%u.%u", + dataSize, udpHandle, + (peerIpAddr & 0x000000ff), + (peerIpAddr & 0x0000ff00) >> 8, + (peerIpAddr & 0x00ff0000) >> 16, + (peerIpAddr & 0xff000000) >> 24); + + } + return NW_GTPV1U_OK; +} + + + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.h b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.h new file mode 100644 index 0000000000..a0488d541c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUdpEntity.h @@ -0,0 +1,52 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.h + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_UDP_ENTITY_H__ +#define __NW_MINI_UDP_ENTITY_H__ + +typedef struct +{ + NwU32T hSocket; + NwEventT ev; + NwGtpv1uStackHandleT hGtpv1uStack; +} NwMiniUdpEntityT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv1uRcT nwMiniUdpInit(NwMiniUdpEntityT* thiz, NwGtpv1uStackHandleT hGtpv1uStack, NwU8T* ipAddr); + +NwGtpv1uRcT nwMiniUdpDestroy(NwMiniUdpEntityT* thiz); + +NwGtpv1uRcT nwMiniUdpDataReq(NwGtpv1uUdpHandleT udpHandle, + NwU8T* dataBuf, + NwU32T dataSize, + NwU32T peerAddr, + NwU32T peerPort); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.c b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.c new file mode 100644 index 0000000000..4227b62d3c --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.c @@ -0,0 +1,306 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv1u.h" +#include "NwGtpv1uIe.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Private Functions + *--------------------------------------------------------------------------*/ + +#define MAX_UDP_PAYLOAD_LEN (4096) + +NwGtpv1uRcT +nwMiniUlpSendEchoRequestToPeer(NwMiniUlpEntityT *thiz, NwU32T peerIp) +{ + NwGtpv1uRcT rc; + NwGtpv1uUlpApiT ulpReq; + + /* + * Send Message Request to Gtpv1u Stack Instance + */ + + ulpReq.apiType = NW_GTPV1U_ULP_API_INITIAL_REQ; + + ulpReq.apiInfo.initialReqInfo.hUlpTrxn = (NwGtpv1uUlpTrxnHandleT)thiz; + ulpReq.apiInfo.initialReqInfo.teid = 0x00; + ulpReq.apiInfo.initialReqInfo.peerIp = (peerIp); + ulpReq.apiInfo.initialReqInfo.peerPort = 2152; + + /* Send Echo Request*/ + + rc = nwGtpv1uMsgNew( thiz->hGtpv1uStack, + NW_TRUE, /* SeqNum flag */ + NW_FALSE, + NW_FALSE, + NW_GTP_ECHO_REQ, /* Msg Type */ + 0x00000000UL, /* TEID */ + 0x5678, /* Seq Number */ + 0, + 0, + (&ulpReq.hMsg)); + + NW_ASSERT( rc == NW_GTPV1U_OK ); + + rc = nwGtpv1uMsgAddIeTV1((ulpReq.hMsg), NW_GTPV1U_IE_RECOVERY, + thiz->restartCounter); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + rc = nwGtpv1uProcessUlpReq(thiz->hGtpv1uStack, &ulpReq); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + return NW_GTPV1U_OK; +} + +static +void NW_EVT_CALLBACK(nwMiniUlpDataIndicationCallbackData) +{ + NwMiniUlpEntityT *thiz = (NwMiniUlpEntityT *) arg; + NwGtpv1uRcT rc; + NwU8T udpBuf[MAX_UDP_PAYLOAD_LEN]; + NwS32T bytesRead; + NwU32T peerLen; + struct sockaddr_in peer; + + peerLen = sizeof(peer); + + bytesRead = recvfrom(thiz->hSocket, udpBuf, MAX_UDP_PAYLOAD_LEN , 0, + (struct sockaddr *) &peer,(socklen_t *) &peerLen); + if(bytesRead) { + NW_LOG(NW_LOG_LEVEL_DEBG, "Received UDP message of length %u from %X:%u", + bytesRead, ntohl(peer.sin_addr.s_addr), ntohs(peer.sin_port)); + rc = nwMiniUlpTpduSend(thiz, udpBuf, bytesRead, thiz->localPort[fd]); + } else { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + } +} + +/*--------------------------------------------------------------------------- + * Public Functions + *--------------------------------------------------------------------------*/ + +NwGtpv1uRcT +nwMiniUlpInit(NwMiniUlpEntityT *thiz, NwGtpv1uStackHandleT hGtpv1uStack) +{ + NwGtpv1uRcT rc; + thiz->hGtpv1uStack = hGtpv1uStack; + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwMiniUlpDestroy(NwMiniUlpEntityT *thiz) +{ + NW_ASSERT(thiz); + memset(thiz, 0, sizeof(NwMiniUlpEntityT)); + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwMiniUlpCreateConn(NwMiniUlpEntityT *thiz, char *localIpStr, NwU16T localport, + char *peerIpStr) +{ + NwGtpv1uRcT rc; + int sd; + struct sockaddr_in addr; + NwGtpv1uUlpApiT ulpReq; + + strcpy(thiz->peerIpStr, peerIpStr); + + /* + * Create local tunnel endpoint + */ + + NW_LOG(NW_LOG_LEVEL_NOTI, "Creating tunnel endpoint with teid %d", localport); + ulpReq.apiType = + NW_GTPV1U_ULP_API_CREATE_TUNNEL_ENDPOINT; + ulpReq.apiInfo.createTunnelEndPointInfo.teid = localport; + ulpReq.apiInfo.createTunnelEndPointInfo.hUlpSession = + (NwGtpv1uUlpSessionHandleT)thiz; + + rc = nwGtpv1uProcessUlpReq(thiz->hGtpv1uStack, &ulpReq); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + thiz->hGtpv1uConn = ulpReq.apiInfo.createTunnelEndPointInfo.hStackSession; + + /* + * Create local udp listening endpoint + */ + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(localport); + addr.sin_addr.s_addr = inet_addr(localIpStr); + memset(addr.sin_zero, '\0', sizeof (addr.sin_zero)); + + if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + event_set(&(thiz->ev[sd]), sd, EV_READ|EV_PERSIST, + nwMiniUlpDataIndicationCallbackData, thiz); + event_add(&(thiz->ev[sd]), NULL); + + thiz->localPort[sd] = localport; + + /* + * Create local udp for sendign data + */ + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + + thiz->hSocket = sd; + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwMiniUlpDestroyConn(NwMiniUlpEntityT *thiz) +{ + NwGtpv1uRcT rc; + NwGtpv1uUlpApiT ulpReq; + /*--------------------------------------------------------------------------- + * Send Destroy Session Request to GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + ulpReq.apiType = NW_GTPV1U_ULP_API_DESTROY_TUNNEL_ENDPOINT; + ulpReq.apiInfo.destroyTunnelEndPointInfo.hStackSessionHandle = thiz->hGtpv1uConn; + + rc = nwGtpv1uProcessUlpReq(thiz->hGtpv1uStack, &ulpReq); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + thiz->hGtpv1uConn = 0; + + return NW_GTPV1U_OK; +} + + +NwGtpv1uRcT +nwMiniUlpTpduSend(NwMiniUlpEntityT *thiz, NwU8T *tpduBuf, NwU32T tpduLen , + NwU16T fromPort) +{ + NwGtpv1uRcT rc; + NwGtpv1uUlpApiT ulpReq; + + /* + * Send Message Request to GTPv1u Stack Instance + */ + + ulpReq.apiType = NW_GTPV1U_ULP_API_SEND_TPDU; + ulpReq.apiInfo.sendtoInfo.teid = fromPort; + ulpReq.apiInfo.sendtoInfo.ipAddr = inet_addr(thiz->peerIpStr); + + rc = nwGtpv1uGpduMsgNew( thiz->hGtpv1uStack, + fromPort, + NW_FALSE, + thiz->seqNum++, + tpduBuf, + tpduLen, + &(ulpReq.apiInfo.sendtoInfo.hMsg)); + + NW_ASSERT( rc == NW_GTPV1U_OK ); + + rc = nwGtpv1uProcessUlpReq(thiz->hGtpv1uStack, &ulpReq); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + rc = nwGtpv1uMsgDelete(thiz->hGtpv1uStack, (ulpReq.apiInfo.sendtoInfo.hMsg)); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + return NW_GTPV1U_OK; +} + +NwGtpv1uRcT +nwMiniUlpProcessStackReqCallback (NwGtpv1uUlpHandleT hUlp, + NwGtpv1uUlpApiT *pUlpApi) +{ + NwMiniUlpEntityT *thiz; + NW_ASSERT(pUlpApi != NULL); + + thiz = (NwMiniUlpEntityT *) hUlp; + + switch(pUlpApi->apiType) { + case NW_GTPV1U_ULP_API_RECV_TPDU: { + struct sockaddr_in peerAddr; + NwS32T bytesSent; + NwU8T dataBuf[4096]; + NwU32T dataSize; + NwU32T peerIpAddr = (inet_addr(thiz->peerIpStr)); + + NW_ASSERT( NW_GTPV1U_OK == nwGtpv1uMsgGetTpdu(pUlpApi->apiInfo.recvMsgInfo.hMsg, + dataBuf, &dataSize) ); + + NW_LOG(NW_LOG_LEVEL_DEBG, "Received TPDU from gtpv1u stack %u!", + pUlpApi->apiInfo.recvMsgInfo.teid); + + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(pUlpApi->apiInfo.recvMsgInfo.teid); + peerAddr.sin_addr.s_addr = (peerIpAddr); + memset(peerAddr.sin_zero, '\0', sizeof (peerAddr.sin_zero)); + + bytesSent = sendto (thiz->hSocket, dataBuf, dataSize, 0, + (struct sockaddr *) &peerAddr, sizeof(peerAddr)); + + if(bytesSent < 0) { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } else { + NW_LOG(NW_LOG_LEVEL_DEBG, "Sent %u bytes to peer %u.%u.%u.%u", dataSize, + (peerIpAddr & 0x000000ff), + (peerIpAddr & 0x0000ff00) >> 8, + (peerIpAddr & 0x00ff0000) >> 16, + (peerIpAddr & 0xff000000) >> 24); + } + + NW_ASSERT(nwGtpv1uMsgDelete(thiz->hGtpv1uStack, + (pUlpApi->apiInfo.recvMsgInfo.hMsg)) == NW_GTPV1U_OK); + + } + break; + default: + NW_LOG(NW_LOG_LEVEL_WARN, "Received undefined UlpApi (%d) from gtpv1u stack!", + pUlpApi->apiType); + } + return NW_GTPV1U_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.h b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.h new file mode 100644 index 0000000000..b4f12e760e --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/NwMiniUlpEntity.h @@ -0,0 +1,65 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.h + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef __NW_MINI_ULP_H__ +#define __NW_MINI_ULP_H__ + +typedef struct +{ + int hSocket; + NwU16T seqNum; + NwU8T restartCounter; + NwU8T localIpStr[16]; + NwU8T peerIpStr[16]; + NwU32T localPort[1025]; + NwEventT ev[1025]; + NwGtpv1uStackHandleT hGtpv1uStack; + NwGtpv1uStackSessionHandleT hGtpv1uConn; +} NwMiniUlpEntityT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv1uRcT +nwMiniUlpInit(NwMiniUlpEntityT* thiz, NwGtpv1uStackHandleT hGtpv1uStack); + +NwGtpv1uRcT +nwMiniUlpDestroy(NwMiniUlpEntityT* thiz); + +NwGtpv1uRcT +nwMiniUlpCreateConn(NwMiniUlpEntityT* thiz, char* localIpStr, NwU16T localPort, char* peerIpStr); + +NwGtpv1uRcT +nwMiniUlpDestroyConn(NwMiniUlpEntityT* thiz); + +NwGtpv1uRcT +nwMiniUlpSendMsg(NwMiniUlpEntityT* thiz); + +NwGtpv1uRcT +nwMiniUlpTpduSend(NwMiniUlpEntityT* thiz, NwU8T* tpduBuf, NwU32T tpduLen , NwU16T fromPort); + +NwGtpv1uRcT +nwMiniUlpProcessStackReqCallback (NwGtpv1uUlpHandleT hUlp, + NwGtpv1uUlpApiT *pUlpApi); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/helloworld.c b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/helloworld.c new file mode 100644 index 0000000000..dd4a0f13e3 --- /dev/null +++ b/openair-cn/GTPV1-U/nw-gtpv1u/test-app/nw-helloworld/helloworld.c @@ -0,0 +1,207 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 u * + * G P R S T u n n e l i n g P r o t o c o l v 2 u S t a c k * + * * + * M I N I M A L I S T I C D E M O N S T R A T I O N * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file hello-world.c + * @brief This is a test program demostrating usage of nw-gtpv2 library. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv1u.h" + +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" +#include "NwMiniUdpEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +/*--------------------------------------------------------------------------- + * T H E M A I N F U N C T I O N + *--------------------------------------------------------------------------*/ + +int main(int argc, char *argv[]) +{ + NwGtpv1uRcT rc; + char *logLevelStr; + NwU32T logLevel; + NwU32T num_of_connections; + + NwGtpv1uStackHandleT hGtpv1uStack = 0; + NwMiniUlpEntityT ulpObj; + NwMiniUdpEntityT udpObj; + NwMiniLogMgrT logObj; + NwGtpv1uUlpEntityT ulp; + NwGtpv1uUdpEntityT udp; + NwGtpv1uTimerMgrEntityT tmrMgr; + NwGtpv1uLogMgrEntityT logMgr; + + if(argc != 4) { + printf("Usage: %s <num-of-connections> <local-ip> <peer-ip>\n", argv[0]); + exit(0); + } + + + logLevelStr = getenv ("NW_LOG_LEVEL"); + + if(logLevelStr == NULL) { + logLevel = NW_LOG_LEVEL_INFO; + } else { + if(strncmp(logLevelStr, "EMER",4) == 0) { + logLevel = NW_LOG_LEVEL_EMER; + } else if(strncmp(logLevelStr, "ALER",4) == 0) { + logLevel = NW_LOG_LEVEL_ALER; + } else if(strncmp(logLevelStr, "CRIT",4) == 0) { + logLevel = NW_LOG_LEVEL_CRIT; + } else if(strncmp(logLevelStr, "ERRO",4) == 0) { + logLevel = NW_LOG_LEVEL_ERRO ; + } else if(strncmp(logLevelStr, "WARN",4) == 0) { + logLevel = NW_LOG_LEVEL_WARN; + } else if(strncmp(logLevelStr, "NOTI",4) == 0) { + logLevel = NW_LOG_LEVEL_NOTI; + } else if(strncmp(logLevelStr, "INFO",4) == 0) { + logLevel = NW_LOG_LEVEL_INFO; + } else if(strncmp(logLevelStr, "DEBG",4) == 0) { + logLevel = NW_LOG_LEVEL_DEBG; + } + } + + /*--------------------------------------------------------------------------- + * Initialize event library + *--------------------------------------------------------------------------*/ + + NW_EVT_INIT(); + + /*--------------------------------------------------------------------------- + * Initialize Log Manager + *--------------------------------------------------------------------------*/ + + nwMiniLogMgrInit(&logObj, logLevel); + + /*--------------------------------------------------------------------------- + * Create GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + rc = nwGtpv1uInitialize(&hGtpv1uStack); + + if(rc != NW_GTPV1U_OK) { + NW_LOG(NW_LOG_LEVEL_ERRO, + "Failed to create gtpv1u stack instance. Error '%u' occured", rc); + exit(1); + } + + NW_LOG(NW_LOG_LEVEL_INFO, "Gtpv1u Stack Handle '%X' Creation Successful!", + hGtpv1uStack); + + /*--------------------------------------------------------------------------- + * Set up Ulp Entity + *--------------------------------------------------------------------------*/ + + rc = nwMiniUlpInit(&ulpObj, hGtpv1uStack); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + ulp.hUlp = (NwGtpv1uUlpHandleT) &ulpObj; + ulp.ulpReqCallback = nwMiniUlpProcessStackReqCallback; + + rc = nwGtpv1uSetUlpEntity(hGtpv1uStack, &ulp); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + + /*--------------------------------------------------------------------------- + * Set up Udp Entity + *--------------------------------------------------------------------------*/ + + rc = nwMiniUdpInit(&udpObj, hGtpv1uStack, (argv[2])); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + udp.hUdp = (NwGtpv1uUdpHandleT) &udpObj; + udp.udpDataReqCallback = nwMiniUdpDataReq; + + rc = nwGtpv1uSetUdpEntity(hGtpv1uStack, &udp); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + + tmrMgr.tmrMgrHandle = 0; + tmrMgr.tmrStartCallback = nwTimerStart; + tmrMgr.tmrStopCallback = nwTimerStop; + + rc = nwGtpv1uSetTimerMgrEntity(hGtpv1uStack, &tmrMgr); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + + logMgr.logMgrHandle = (NwGtpv1uLogMgrHandleT) &logObj; + logMgr.logReqCallback = nwMiniLogMgrLogRequest; + + rc = nwGtpv1uSetLogMgrEntity(hGtpv1uStack, &logMgr); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + /*--------------------------------------------------------------------------- + * Set GTPv1u log level + *--------------------------------------------------------------------------*/ + + rc = nwGtpv1uSetLogLevel(hGtpv1uStack, logLevel); + + /*--------------------------------------------------------------------------- + * Send Create Session Request to GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + num_of_connections = atoi(argv[1]); + + while ( num_of_connections-- ) { + //rc = nwMiniUlpCreateConn(&ulpObj, argv[2], 1234 + num_of_connections, argv[3]); + rc = nwMiniUlpSendEchoRequestToPeer(&ulpObj, inet_addr(argv[3])); + NW_ASSERT( rc == NW_GTPV1U_OK ); + } + + /*--------------------------------------------------------------------------- + * Event loop + *--------------------------------------------------------------------------*/ + + NW_EVT_LOOP(); + + NW_LOG(NW_LOG_LEVEL_ERRO, "Exit from eventloop, no events to process!"); + + /*--------------------------------------------------------------------------- + * Send Destroy Session Request to GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + rc = nwMiniUlpDestroyConn(&ulpObj); + NW_ASSERT( rc == NW_GTPV1U_OK ); + + + /*--------------------------------------------------------------------------- + * Destroy GTPv1u Stack Instance + *--------------------------------------------------------------------------*/ + + rc = nwGtpv1uFinalize(hGtpv1uStack); + + if(rc != NW_GTPV1U_OK) { + NW_LOG(NW_LOG_LEVEL_ERRO, + "Failed to finalize gtpv1u stack instance. Error '%u' occured", rc); + } else { + NW_LOG(NW_LOG_LEVEL_INFO, "Gtpv1u Stack Handle '%X' Finalize Successful!", + hGtpv1uStack); + } + + + return rc; +} diff --git a/openair-cn/GTPV2-C/Makefile.am b/openair-cn/GTPV2-C/Makefile.am new file mode 100644 index 0000000000..8bd729571e --- /dev/null +++ b/openair-cn/GTPV2-C/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = nwgtpv2c-0.11/ \ No newline at end of file diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/AUTHORS b/openair-cn/GTPV2-C/nwgtpv2c-0.11/AUTHORS new file mode 100644 index 0000000000..b068a40fdd --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/AUTHORS @@ -0,0 +1 @@ +Amit Chawre diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/COPYING b/openair-cn/GTPV2-C/nwgtpv2c-0.11/COPYING new file mode 100644 index 0000000000..d27832d6c1 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/COPYING @@ -0,0 +1,26 @@ +Copyright (c) 2010-2011 Amit Chawre <http://www.amitchawre.net/contact.html> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products +derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/ChangeLog b/openair-cn/GTPV2-C/nwgtpv2c-0.11/ChangeLog new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/INSTALL b/openair-cn/GTPV2-C/nwgtpv2c-0.11/INSTALL new file mode 100644 index 0000000000..a1e89e18ad --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2011 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/Makefile.am b/openair-cn/GTPV2-C/nwgtpv2c-0.11/Makefile.am new file mode 100644 index 0000000000..2b8e86b1a2 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/Makefile.am @@ -0,0 +1,6 @@ +# this is example-file: Makefile.am + +# the subdirectories of the project to go into +SUBDIRS = \ + src\ + test-app diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/NEWS b/openair-cn/GTPV2-C/nwgtpv2c-0.11/NEWS new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/README b/openair-cn/GTPV2-C/nwgtpv2c-0.11/README new file mode 100644 index 0000000000..8aa79638e9 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/README @@ -0,0 +1,168 @@ + +INTRODUCTION +------------ + +nwGtpv2c library is a free and open source implementation of GPRS Tunneling +Protocol v2, also known as eGTP-C, as per 3GPP TS-29274. + +The stack library supports transaction management, message creation and parsing, +message validation, echo response and retransmission management. Other than +this, timer and memory management functions are also built into the stack. + +The library is published under BSD three clause license. + + +DESIGN PHILOSPHY +---------------- + +The stack is designed for high portability not only for the hardware and OS +it will run on but also for the application software that uses it. The stack +doesn't mandate conditions on the user application architecture or design. +The stack relies on the user application for infrastructure utilities such +as I/O, timers, logs and multithreading. This realized by using callback +mechanisms and enables the stack library to seamlessly integrate without or +very little changes to the existing application framework. + +The stack is fully-asynchronous in design for compatibility with event loop +mechanisms such as select, poll, etc. and can also be used for multi-threaded +applications. It should compile on Linux, BSD, Mac OS X, Solaris and Windows +(cygwin). + +The stack architecture builds upon following mentioned entities that are +external to it: + + +-------------+ +---------+ +---------+ + | ULP ENTITY | | TMR MGR | | LOG MGR | + +------+------+ +----+----+ +----+----+ + | | | + +------+------------------+------------------+----+ + | | + | NWGTPv2 STACK | + | | + +-------------------------+-----------------------+ + | + +------+------+ + | UDP ENTITY | + +-------------+ + + +- User Layer Protocol (ULP) Entity: +This entity is the one which decides behaviour of the GTP user application. +This layer implements the intelligent logic for the GTP application and sits +on top of the GTP stack. This layer may also execute functions other than GTP +procedures for example authetication. + +- UDP Entity: +This is the layer below the GTP stack and is responsible for UDP I/O between +the stack and network. This layer shall manage the socket interface. This entity +abstracts the stack library's view of the network. This may be useful in a +multiprocess load balancing application wherein the GTP messages are received +by a GTP load distribution entity and relayed to multiple GTP stacks over +internal messaging. It may or may not be housed with/in ULP. + +- Timer Manager Entity: +Timer Manager Entity provides the GTP stack library with infrastructure for +timer CRUD operations. It may or may not be housed with/in ULP. + +- Log Manager Entity: +Log Manager Entity provides the GTP stack library with callbacks for logging +operations. It may or may not be housed with/in ULP. + + +Optionally, there may be a user level "Stack Management Entity" which shall be +resposible for creating and configuring the stack library, though the stack +library is not aware of any such entity. + +The application may implement all above entities as a single or multiple object. +The external entities need to register callbacks with GTP stack library for +receiving APIs from the stack library and stack library exposes API for the same. + +The GTP stack library doesn't implement any execution threads of its own. It is +up-to user application if it want to call the library APIs via multiple threads. +The stack library, though, currently DOES NOT protect its critical section and +hence, is NOT threadsafe. + + +FEATURES +-------- + +- TS 29.274 (Release 9) compliance target for gtp-c +- Message Encoding +- Reliable Message Delivery +- Message Parser +- Message Integrity and Error Checking +- Support for S11, S5 and S8 SAE/EPC interfaces +- Easy Application Integration + + +APPLICATIONS +------------ + +In general, the GTP stack library may be used to write any GTP version 2 based +application. +The GTP stack library can also be used by applications implementing LTE MME, SGW +or PDN Gateways and simulators/emulators for either of them. Please see the test +applications involving basic GTP procedures. + +The test applications use libevent-1.4 library for I/O and timer infrastructure, +(http://www.monkey.org/~provos/libevent-1.4.14b-stable.tar.gz). +Following is a brief description of the test applications: + +- nw-helloworld +This is minimalistic program demostrating usage of nw-gtpv2 library. It +demostrates ulp, udp, tmrmgr and logmgr entities as well as stack construction +and destruction. The gtpv2c test application creates a transaction and sends +a initial request messages over it. + +- nw-egpting +egtping is a utility for pinging a GPRS Tunneling Protocol (GTP) version 2, +or Evolved GTP (eGTP) using Echo Request/Response. + +- nw-epc +The nw-epc software package is a free and open source framework implementation +of SGW and PGW built upon nw-gtpv2. + + +LICENSE +------- + +Copyright (c) 2010-2011 Amit Chawre <http://www.amitchawre.net/contact.html> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +DISCLAIMER +---------- + +THIS INFORMATION IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS INFORMATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/aclocal.m4 b/openair-cn/GTPV2-C/nwgtpv2c-0.11/aclocal.m4 new file mode 100644 index 0000000000..63b681e77a --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/aclocal.m4 @@ -0,0 +1,986 @@ +# generated automatically by aclocal 1.12 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically 'autoreconf'.])]) + +# Copyright (C) 2002-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.12' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.12], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.12])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to +# '$srcdir', '$srcdir/..', or '$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is '.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ([2.52])dnl + m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], + [$1], [CXX], [depcc="$CXX" am_compiler_list=], + [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], [UPC], [depcc="$UPC" am_compiler_list=], + [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named 'D' -- because '-MD' means "put the output + # in D". + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with + # Solaris 10 /bin/sh. + echo '/* dummy */' > sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with '-c' and '-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle '-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs. + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # After this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested. + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok '-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES. +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE([dependency-tracking], [dnl +AS_HELP_STRING( + [--enable-dependency-tracking], + [do not reject slow dependency extractors]) +AS_HELP_STRING( + [--disable-dependency-tracking], + [speeds up one-time build])]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named 'Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running 'make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each '.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 18 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if( + m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), + [ok:ok],, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) + AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) +AM_MISSING_PROG([AUTOCONF], [autoconf]) +AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) +AM_MISSING_PROG([AUTOHEADER], [autoheader]) +AM_MISSING_PROG([MAKEINFO], [makeinfo]) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES([CC])], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES([CXX])], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES([OBJC])], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The 'parallel-tests' driver may need to know about EXEEXT, so add the +dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST([install_sh])]) + +# Copyright (C) 2003-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from 'make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN(['missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# AM_PROG_MKDIR_P +# --------------- +# Check for 'mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), [1])]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; +esac + +# Do 'set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + am_has_slept=no + for am_try in 1 2; do + echo "timestamp, slept: $am_has_slept" > conftest.file + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken + alias in your environment]) + fi + if test "$[2]" = conftest.file || test $am_try -eq 2; then + break + fi + # Just in case. + sleep 1 + am_has_slept=yes + done + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT([yes]) +# If we didn't sleep, we still need to ensure time stamps of config.status and +# generated files are strictly newer. +am_sleep_pid= +if grep 'slept: no' conftest.file >/dev/null 2>&1; then + ( sleep 1 ) & + am_sleep_pid=$! +fi +AC_CONFIG_COMMANDS_PRE( + [AC_MSG_CHECKING([that generated files are newer than configure]) + if test -n "$am_sleep_pid"; then + # Hide warnings about reused PIDs. + wait $am_sleep_pid 2>/dev/null + fi + AC_MSG_RESULT([done])]) +rm -f conftest.file +]) + +# Copyright (C) 2001-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor 'install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in "make install-strip", and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using 'strip' when the user +# run "make install-strip". However 'strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the 'STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004-2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of 'v7', 'ustar', or 'pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of '-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/configure.ac b/openair-cn/GTPV2-C/nwgtpv2c-0.11/configure.ac new file mode 100644 index 0000000000..c9284f575e --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/configure.ac @@ -0,0 +1,58 @@ +# this is example-file: configure.ac + +# initial information about the project +AC_INIT([NwGtpv2c],[0.11],[]) + +# check if the source folder is correct +AC_CONFIG_SRCDIR([src/NwGtpv2c.c]) + +# Checks for programs + +# check for C++ preprocessor and compiler and the library compiler +AC_PROG_CXXCPP +AC_PROG_CXX +AC_PROG_RANLIB + +# automake initialisation and check for minimal automake API version 1.9 +AM_INIT_AUTOMAKE([1.9]) + +# use the C compiler for the following checks +AC_LANG([C]) +AC_C_INLINE + +# Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h]) +AC_CHECK_HEADERS([string]) +AC_CHECK_HEADERS([iostream]) +AC_CHECK_HEADERS([arpa/inet.h]) +AC_CHECK_HEADERS([sys/time.h]) +AC_CHECK_HEADERS([sys/socket.h]) + +AC_CHECK_FUNCS([strerror]) +AC_CHECK_FUNCS([socket]) +AC_CHECK_FUNCS([memset]) +AC_CHECK_FUNCS([gettimeofday]) +AC_FUNC_MALLOC +AC_PROG_LN_S + +AC_CHECK_LIB([event], [event_init]) +AM_CONDITIONAL([ENABLE_TESTS_APP], [test x$HAVE_LIBEVENT == xyes]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIZE_T + +# distribute additional compiler and linker flags +# --> set these variables instead of CXXFLAGS or LDFLAGS +AC_SUBST([AM_CFLAGS]) +AC_SUBST([AM_LDFLAGS]) + +# files to generate via autotools (.am or .in source files) +AC_CONFIG_FILES([Makefile]) +AC_CONFIG_FILES([src/Makefile]) +AC_CONFIG_FILES([test-app/Makefile]) +AC_CONFIG_FILES([test-app/nw-helloworld/Makefile]) +AC_CONFIG_FILES([test-app/nw-egtping/Makefile]) + +# generate the final Makefile etc. +AC_OUTPUT diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cLog.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cLog.h new file mode 100644 index 0000000000..724c830e9b --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cLog.h @@ -0,0 +1,83 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_LOG_H__ +#define __NW_GTPV2C_LOG_H__ + +#include <stdio.h> +#include "NwLog.h" + +/** + * @file NwGtpv2cLog.h + * @brief This header contains logging related definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Log Macro Definition + *--------------------------------------------------------------------------*/ + +#define NW_LOG(_gtpv2cHandle, _logLevel, ...) \ + do { \ + if(((NwGtpv2cStackT*)(_gtpv2cHandle))->logLevel >= _logLevel) \ + { \ + char _logBuf[1024]; \ + snprintf(_logBuf, 1024, __VA_ARGS__); \ + ((NwGtpv2cStackT*)(_gtpv2cHandle))->logMgr.logReqCallback(((NwGtpv2cStackT*)_gtpv2cHandle)->logMgr.logMgrHandle, _logLevel, __FILE__, __LINE__, _logBuf);\ + } \ + } while(0) + +#define NW_ENTER(_gtpv2cHandle) \ + do { \ + NW_LOG(_gtpv2cHandle, NW_LOG_LEVEL_DEBG, "Entering '%s'", __func__);\ + } while(0) + +#define NW_LEAVE(_gtpv2cHandle) \ + do { \ + NW_LOG(_gtpv2cHandle, NW_LOG_LEVEL_DEBG, "Leaving '%s'", __func__);\ + } while(0) + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_TYPES_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cMsgIeParseInfo.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cMsgIeParseInfo.h new file mode 100644 index 0000000000..a382cee451 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cMsgIeParseInfo.h @@ -0,0 +1,97 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_MSG_PARSE_INFO_H__ +#define __NW_GTPV2C_MSG_PARSE_INFO_H__ + +#include "NwTypes.h" +#include "NwGtpv2c.h" + +/** + * @file NwGtpv2cMsgParseInfo.h + * @brief This file defines APIs for to parse incoming messages. +*/ + +typedef struct +{ + NwU8T groupedIeType; + NwU16T mandatoryIeCount; + NwGtpv2cStackHandleT hStack; + + struct { + NwU8T ieMinLength; + NwU8T iePresence; + } ieParseInfo[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; + +} NwGtpv2cGroupedIeParseInfoT; + +typedef struct +{ + NwU16T msgType; + NwU16T mandatoryIeCount; + NwGtpv2cStackHandleT hStack; + + struct { + NwU8T ieMinLength; + NwU8T iePresence; + NwGtpv2cGroupedIeParseInfoT* pGroupedIeInfo; + } ieParseInfo[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; + +} NwGtpv2cMsgIeParseInfoT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwGtpv2cMsgIeParseInfoT* +nwGtpv2cMsgIeParseInfoNew(NwGtpv2cStackHandleT hStack, NwU8T msgType); + +NwRcT +nwGtpv2cMsgIeParseInfoDelete(NwGtpv2cMsgIeParseInfoT* thiz); + +NwRcT +nwGtpv2cMsgIeParse(NW_IN NwGtpv2cMsgIeParseInfoT* thiz, + NW_IN NwGtpv2cMsgHandleT hMsg, + NW_INOUT NwGtpv2cErrorT *pError); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_MSG_PARSE_INFO_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cPrivate.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cPrivate.h new file mode 100644 index 0000000000..c12af21c38 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cPrivate.h @@ -0,0 +1,242 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_PRIVATE_H__ +#define __NW_GTPV2C_PRIVATE_H__ + +#include <sys/time.h> + +#include "tree.h" +#include "queue.h" + +#include "NwTypes.h" +#include "NwError.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgIeParseInfo.h" +#include "NwGtpv2cTunnel.h" + +/** + * @file NwGtpv2cPrivate.h + * @brief This header file contains nw-gtpv2c private definitions not to be + * exposed to user application. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NW_GTPV2C_MALLOC(_stack, _size, _mem, _type) \ + do { \ + if(((NwGtpv2cStackT*)(_stack))->memMgr.memAlloc && ((NwGtpv2cStackT*)(_stack))->memMgr.memFree )\ + { \ + _mem = (_type) ((NwGtpv2cStackT*) (_stack))->memMgr.memAlloc(((NwGtpv2cStackT*) (_stack))->memMgr.hMemMgr, _size, __FILE__, __LINE__);\ + } \ + else \ + { \ + _mem = (_type) malloc (_size); \ + } \ + } while (0) + +#define NW_GTPV2C_FREE(_stack, _mem) \ + do { \ + if(((NwGtpv2cStackT*)(_stack))->memMgr.memAlloc && ((NwGtpv2cStackT*)(_stack))->memMgr.memFree )\ + { \ + ((NwGtpv2cStackT*)(_stack))->memMgr.memFree(((NwGtpv2cStackT*) (_stack))->memMgr.hMemMgr, _mem, __FILE__, __LINE__);\ + } \ + else \ + { \ + free ((void*)_mem); \ + } \ + } while (0) + +/*--------------------------------------------------------------------------* + * G T P V 2 C S T A C K O B J E C T T Y P E D E F I N I T I O N * + *--------------------------------------------------------------------------*/ + +/** + * gtpv2c stack class definition + */ + +typedef struct NwGtpv2cStack +{ + NwU32T id; + NwGtpv2cUlpEntityT ulp; + NwGtpv2cUdpEntityT udp; + NwGtpv2cMemMgrEntityT memMgr; + NwGtpv2cTimerMgrEntityT tmrMgr; + NwGtpv2cLogMgrEntityT logMgr; + + NwU32T seqNum; + NwU32T logLevel; + NwU32T restartCounter; + + NwGtpv2cMsgIeParseInfoT *pGtpv2cMsgIeParseInfo[NW_GTP_MSG_END]; + struct NwGtpv2cTimeoutInfo *activeTimerInfo; + + RB_HEAD( NwGtpv2cTunnelMap, NwGtpv2cTunnel ) tunnelMap; + RB_HEAD( NwGtpv2cOutstandingTxSeqNumTrxnMap, NwGtpv2cTrxn ) outstandingTxSeqNumMap; + RB_HEAD( NwGtpv2cOutstandingRxSeqNumTrxnMap, NwGtpv2cTrxn ) outstandingRxSeqNumMap; + RB_HEAD( NwGtpv2cActiveTimerList, NwGtpv2cTimeoutInfo ) activeTimerList; + NwHandleT hTmrMinHeap; +} NwGtpv2cStackT; + + +/*--------------------------------------------------------------------------* + * Timeout Info Type Definition + *--------------------------------------------------------------------------*/ + +/** + * gtpv2c timeout info + */ + +typedef struct NwGtpv2cTimeoutInfo +{ + NwGtpv2cStackHandleT hStack; + struct timeval tvTimeout; + NwU32T tmrType; + void* timeoutArg; + NwRcT (*timeoutCallbackFunc)(void*); + NwGtpv2cTimerHandleT hTimer; + RB_ENTRY (NwGtpv2cTimeoutInfo) activeTimerListRbtNode; /**< RB Tree Data Structure Node */ + NwU32T timerMinHeapIndex; + struct NwGtpv2cTimeoutInfo *next; +} NwGtpv2cTimeoutInfoT; + + +/*--------------------------------------------------------------------------- + * GTPv2c Message Container Definition + *--------------------------------------------------------------------------*/ + +#define NW_GTPV2C_MAX_MSG_LEN (1024) /**< Maximum supported gtpv2c packet length including header */ + +/** + * NwGtpv2cMsgT holds gtpv2c messages to/from the peer. + */ +typedef struct NwGtpv2cMsgS +{ + NwU8T version; + NwU8T teidPresent; + NwU8T msgType; + NwU16T msgLen; + NwU32T teid; + NwU32T seqNum; + NwU8T* pMsgStart; + +#define NW_GTPV2C_MAX_GROUPED_IE_DEPTH (2) + struct { + NwGtpv2cIeTlvT *pIe[NW_GTPV2C_MAX_GROUPED_IE_DEPTH]; + NwU8T top; + } groupedIeEncodeStack; + + NwBoolT isIeValid[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; + NwU8T *pIe[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; + NwU8T msgBuf[NW_GTPV2C_MAX_MSG_LEN]; + NwGtpv2cStackHandleT hStack; + struct NwGtpv2cMsgS* next; +} NwGtpv2cMsgT; + +/** + * Transaction structure + */ + +typedef struct NwGtpv2cTrxn +{ + NwU32T seqNum; + NwU32T peerIp; + NwU32T peerPort; + NwU8T t3Timer; + NwU8T maxRetries; + NwGtpv2cMsgT* pMsg; + NwGtpv2cStackT* pStack; + NwGtpv2cTimerHandleT hRspTmr; /**< Handle to reponse timer */ + NwGtpv2cTunnelHandleT hTunnel; /**< Handle to local tunnel context */ + NwGtpv2cUlpTrxnHandleT hUlpTrxn; /**< Handle to ULP tunnel context */ + RB_ENTRY (NwGtpv2cTrxn) outstandingTxSeqNumMapRbtNode; /**< RB Tree Data Structure Node */ + RB_ENTRY (NwGtpv2cTrxn) outstandingRxSeqNumMapRbtNode; /**< RB Tree Data Structure Node */ + struct NwGtpv2cTrxn* next; +} NwGtpv2cTrxnT; + +/** + * GTPv2c Path Context + */ + +typedef struct NwGtpv2cPathS +{ + NwU32T hUlpPath; /**< Handle to ULP path contect */ + NwU32T ipv4Address; + NwU32T restartCounter; + NwU16T t3ResponseTimout; + NwU16T n3RequestCount; + NwGtpv2cTimerHandleT hKeepAliveTmr; /**< Handle to path keep alive echo timer */ + RB_ENTRY (NwGtpv2cPathS) pathMapRbtNode; +} NwGtpv2cPathT; + + +RB_PROTOTYPE(NwGtpv2cTunnelMap, NwGtpv2cTunnel, tunnelMapRbtNode, nwGtpv2cCompareTunnel) +RB_PROTOTYPE(NwGtpv2cOutstandingTxSeqNumTrxnMap, NwGtpv2cTrxn, outstandingTxSeqNumMapRbtNode, nwGtpv2cCompareSeqNum) +RB_PROTOTYPE(NwGtpv2cOutstandingRxSeqNumTrxnMap, NwGtpv2cTrxn, outstandingRxSeqNumMapRbtNode, nwGtpv2cCompareSeqNum) +RB_PROTOTYPE(NwGtpv2cActiveTimerList, NwGtpv2cTimeoutInfo, activeTimerListRbtNode, nwGtpv2cCompareOutstandingTxRexmitTime) + +/** + * Start Timer with ULP Timer Manager + */ + +NwRcT +nwGtpv2cStartTimer(NwGtpv2cStackT* thiz, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + NwRcT (*timeoutCallbackFunc)(void*), + void* timeoutCallbackArg, + NwGtpv2cTimerHandleT *phTimer); + + +/** + * Stop Timer with ULP Timer Manager + */ + +NwRcT +nwGtpv2cStopTimer(NwGtpv2cStackT* thiz, + NwGtpv2cTimerHandleT hTimer); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_PRIVATE_H__ */ +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTrxn.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTrxn.h new file mode 100644 index 0000000000..3e95373434 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTrxn.h @@ -0,0 +1,117 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +/** + * @file NwGtpv2cTrxn.h + * @author Amit Chawre + * @brief + * + * This header file contains required definitions and functions + * prototypes used by gtpv2c transactions. + * + **/ + + +#ifndef __NW_GTPV2C_TRXN_H__ +#define __NW_GTPV2C_TRXN_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Constructotr + */ +NwGtpv2cTrxnT* +nwGtpv2cTrxnNew( NW_IN NwGtpv2cStackT* pStack); + +/** + * Overloaded Constructotr + */ +NwGtpv2cTrxnT* +nwGtpv2cTrxnWithSeqNumNew( NW_IN NwGtpv2cStackT* pStack, + NW_IN NwU32T seqNum); + +/** + * Another overloaded constructor. Create transaction as outstanding + * RX transaction for detecting duplicated requests. + * + * @param[in] thiz : Pointer to stack. + * @param[in] teidLocal : Trxn teid. + * @param[in] peerIp : Peer Ip address. + * @param[in] peerPort : Peer Ip port. + * @param[in] seqNum : Seq Number. + * @return NW_OK on success. + */ + +NwGtpv2cTrxnT* +nwGtpv2cTrxnOutstandingRxNew( NW_IN NwGtpv2cStackT* pStack, + NW_IN NwU32T teidLocal, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwU32T seqNum); + +NwRcT +nwGtpv2cTrxnDelete( NW_INOUT NwGtpv2cTrxnT **ppTrxn); + +/** + * Start timer to wait before pruginf a req tran for which response has been sent + * + * @param[in] thiz : Pointer to transaction + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cTrxnStartDulpicateRequestWaitTimer(NwGtpv2cTrxnT* thiz); + +/** + * Start timer to wait for rsp of a req message + * + * @param[in] thiz : Pointer to transaction + * @param[in] timeoutCallbackFunc : Timeout handler callback function. + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cTrxnStartPeerRspWaitTimer(NwGtpv2cTrxnT* thiz); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_TRXN_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTunnel.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTunnel.h new file mode 100644 index 0000000000..0ea339f270 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/NwGtpv2cTunnel.h @@ -0,0 +1,80 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_TUNNEL_H__ +#define __NW_GTPV2C_TUNNEL_H__ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "tree.h" +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwError.h" +#include "NwGtpv2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct NwGtpv2cStack; + +typedef struct NwGtpv2cTunnel +{ + NwU32T teid; + NwU32T ipv4AddrRemote; + NwGtpv2cUlpTunnelHandleT hUlpTunnel; + RB_ENTRY (NwGtpv2cTunnel) tunnelMapRbtNode; /**< RB Tree Data Structure Node */ + struct NwGtpv2cTunnel* next; +} NwGtpv2cTunnelT; + +NwGtpv2cTunnelT* +nwGtpv2cTunnelNew(struct NwGtpv2cStack *hStack, NwU32T teid, NwU32T peerIpv4Addr, NwGtpv2cUlpTunnelHandleT hUlpTunnel); + +NwRcT +nwGtpv2cTunnelDelete(struct NwGtpv2cStack *pStack, NwGtpv2cTunnelT* thiz); + +NwRcT +nwGtpv2cTunnelGetUlpTunnelHandle( NwGtpv2cTunnelT* thiz, NwGtpv2cUlpTunnelHandleT* phUlpTunnel); + +#ifdef __cplusplus +} +#endif + +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/queue.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/queue.h new file mode 100644 index 0000000000..ad97ce5016 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/queue.h @@ -0,0 +1,566 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + * $FreeBSD: src/sys/sys/queue.h,v 1.32.2.6 2001/12/18 10:09:02 ru Exp $ + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + + +/* + * This file defines five types of data structures: singly-linked lists, + * singly-linked tail queues, lists, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The elements + * are singly linked for minimum space and pointer manipulation overhead at + * the expense of O(n) removal for arbitrary elements. New elements can be + * added to the list after an existing element or at the head of the list. + * Elements being removed from the head of the list should use the explicit + * macro for this purpose for tmpimum efficiency. A singly-linked list may + * only be traversed in the forward direction. Singly-linked lists are ideal + * for applications with large datasets and few or no removals or for + * implementing a LIFO queue. + * + * A singly-linked tail queue is headed by a pair of pointers, one to the + * head of the list and the other to the tail of the list. The elements are + * singly linked for minimum space and pointer manipulation overhead at the + * expense of O(n) removal for arbitrary elements. New elements can be added + * to the list after an existing element, at the head of the list, or at the + * end of the list. Elements being removed from the head of the tail queue + * should use the explicit macro for this purpose for tmpimum efficiency. + * A singly-linked tail queue may only be traversed in the forward direction. + * Singly-linked tail queues are ideal for applications with large datasets + * and few or no removals or for implementing a FIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + * + * + * SLIST LIST STAILQ TAILQ CIRCLEQ + * _HEAD + + + + + + * _HEAD_INITIALIZER + + + + + + * _ENTRY + + + + + + * _INIT + + + + + + * _EMPTY + + + + + + * _FIRST + + + + + + * _NEXT + + + + + + * _PREV - - - + + + * _LAST - - + + + + * _FOREACH + + + + + + * _FOREACH_REVERSE - - - + + + * _INSERT_HEAD + + + + + + * _INSERT_BEFORE - + - + + + * _INSERT_AFTER + + + + + + * _INSERT_TAIL - - + + + + * _REMOVE_HEAD + - + - - + * _REMOVE + + + + + + * + */ + +/* + * Singly-linked List declarations. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) + +#define SLIST_FIRST(head) ((head)->slh_first) + +#define SLIST_FOREACH(var, head, field) \ + for ((var) = SLIST_FIRST((head)); \ + (var); \ + (var) = SLIST_NEXT((var), field)) + +#define SLIST_INIT(head) do { \ + SLIST_FIRST((head)) = NULL; \ +} while (0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ + SLIST_NEXT((slistelm), field) = (elm); \ +} while (0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ + SLIST_FIRST((head)) = (elm); \ +} while (0) + +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if (SLIST_FIRST((head)) == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = SLIST_FIRST((head)); \ + while (SLIST_NEXT(curelm, field) != (elm)) \ + curelm = SLIST_NEXT(curelm, field); \ + SLIST_NEXT(curelm, field) = \ + SLIST_NEXT(SLIST_NEXT(curelm, field), field); \ + } \ +} while (0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ +} while (0) + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first;/* first element */ \ + struct type **stqh_last;/* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_HEAD_INIT(head) do{ \ + (head).stqh_first = NULL; \ + (head).stqh_last = &(head).stqh_first; \ +}while(0) + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) + +#define STAILQ_FIRST(head) ((head)->stqh_first) + +#define STAILQ_FOREACH(var, head, field) \ + for((var) = STAILQ_FIRST((head)); \ + (var); \ + (var) = STAILQ_NEXT((var), field)) + +#define STAILQ_INIT(head) do { \ + STAILQ_FIRST((head)) = NULL; \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_NEXT((tqelm), field) = (elm); \ +} while (0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ + STAILQ_FIRST((head)) = (elm); \ +} while (0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + STAILQ_NEXT((elm), field) = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &STAILQ_NEXT((elm), field); \ +} while (0) + +#define STAILQ_LAST(head, type, field) \ + (STAILQ_EMPTY(head) ? \ + NULL : \ + ((struct type *) \ + ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) + +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if (STAILQ_FIRST((head)) == (elm)) { \ + STAILQ_REMOVE_HEAD(head, field); \ + } \ + else { \ + struct type *curelm = STAILQ_FIRST((head)); \ + while (STAILQ_NEXT(curelm, field) != (elm)) \ + curelm = STAILQ_NEXT(curelm, field); \ + if ((STAILQ_NEXT(curelm, field) = \ + STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\ + (head)->stqh_last = &STAILQ_NEXT((curelm), field);\ + } \ +} while (0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if ((STAILQ_FIRST((head)) = \ + STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \ + if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \ + (head)->stqh_last = &STAILQ_FIRST((head)); \ +} while (0) + +/* + * List declarations. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ + +#define LIST_EMPTY(head) ((head)->lh_first == NULL) + +#define LIST_FIRST(head) ((head)->lh_first) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = LIST_FIRST((head)); \ + (var); \ + (var) = LIST_NEXT((var), field)) + +#define LIST_INIT(head) do { \ + LIST_FIRST((head)) = NULL; \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ + LIST_NEXT((listelm), field)->field.le_prev = \ + &LIST_NEXT((elm), field); \ + LIST_NEXT((listelm), field) = (elm); \ + (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + LIST_NEXT((elm), field) = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ + LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ + LIST_FIRST((head)) = (elm); \ + (elm)->field.le_prev = &LIST_FIRST((head)); \ +} while (0) + +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_REMOVE(elm, field) do { \ + if (LIST_NEXT((elm), field) != NULL) \ + LIST_NEXT((elm), field)->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = LIST_NEXT((elm), field); \ +} while (0) + +/* + * Tail queue declarations. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue functions. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = TAILQ_LAST((head), headname); \ + (var); \ + (var) = TAILQ_PREV((var), headname, field)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_NEXT((listelm), field) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + TAILQ_NEXT((elm), field) = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) + +/* + * Circular queue declarations. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&(head), (void *)&(head) } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) + +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = CIRCLEQ_FIRST((head)); \ + (var) != (void *)(head); \ + (var) = CIRCLEQ_NEXT((var), field)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = CIRCLEQ_LAST((head)); \ + (var) != (void *)(head); \ + (var) = CIRCLEQ_PREV((var), field)) + +#define CIRCLEQ_INIT(head) do { \ + CIRCLEQ_FIRST((head)) = (void *)(head); \ + CIRCLEQ_LAST((head)) = (void *)(head); \ +} while (0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \ + CIRCLEQ_PREV((elm), field) = (listelm); \ + if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\ + CIRCLEQ_NEXT((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (listelm); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \ + if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\ + CIRCLEQ_PREV((listelm), field) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \ + CIRCLEQ_PREV((elm), field) = (void *)(head); \ + if (CIRCLEQ_LAST((head)) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = (elm); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \ + CIRCLEQ_FIRST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + CIRCLEQ_NEXT((elm), field) = (void *)(head); \ + CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \ + if (CIRCLEQ_FIRST((head)) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = (elm); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \ + CIRCLEQ_LAST((head)) = (elm); \ +} while (0) + +#define CIRCLEQ_LAST(head) ((head)->cqh_last) + +#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next) + +#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \ + CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \ + else \ + CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \ + CIRCLEQ_PREV((elm), field); \ + if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \ + CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \ + else \ + CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \ + CIRCLEQ_NEXT((elm), field); \ +} while (0) + +#ifdef _KERNEL + +/* + * XXX insque() and remque() are an old way of handling certain queues. + * They bogusly assumes that all queue heads look alike. + */ + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +#ifdef __GNUC__ + +static __inline void +insque(void *a, void *b) +{ + struct quehead *element = (struct quehead *)a, + *head = (struct quehead *)b; + + element->qh_link = head->qh_link; + element->qh_rlink = head; + head->qh_link = element; + element->qh_link->qh_rlink = element; +} + +static __inline void +remque(void *a) +{ + struct quehead *element = (struct quehead *)a; + + element->qh_link->qh_rlink = element->qh_rlink; + element->qh_rlink->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +#else /* !__GNUC__ */ + +void insque __P((void *a, void *b)); +void remque __P((void *a)); + +#endif /* __GNUC__ */ + +#endif /* _KERNEL */ + +#endif /* !_SYS_QUEUE_H_ */ + + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/tree.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/tree.h new file mode 100644 index 0000000000..8e4e35c408 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/include/tree.h @@ -0,0 +1,678 @@ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-back tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + { \ + RB_ROOT(head) = elm; \ + } \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwError.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwError.h new file mode 100644 index 0000000000..e5495b2d70 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwError.h @@ -0,0 +1,65 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#ifndef __NW_ERROR_H__ +#define __NW_ERROR_H__ + +/** + * @file NwError.h + * @brief This header file contains return error code type definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + + NW_OK = 0x00000000, + NW_GTPV2C_IE_MISSING, + NW_GTPV2C_IE_INCORRECT, + NW_GTPV2C_MANDATORY_IE_DUPLICATE, + NW_GTPV2C_CONDITIONAL_IE_MISSING, + NW_GTPV2C_MANDATORY_IE_MISSING, + NW_GTPV2C_MSG_MALFORMED, + NW_FAILURE = 0xFFFFFFFE +} NwRcT; + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_ERROR_CODE_H__ */ + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2c.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2c.h new file mode 100644 index 0000000000..dfc61ee324 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2c.h @@ -0,0 +1,595 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_H__ +#define __NW_GTPV2C_H__ + +#include <sys/types.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include "NwTypes.h" +#include "NwError.h" + +/** @mainpage + + @section intro Introduction + + nw-gtpv2c library is a free and open source control plane implementation of GPRS + Tunneling protocol v2 also known as eGTPc as per 3GPP TS29274-930. + The library is published under BSD three clause license. + + @section scope Scope + + The stack library also does basic tasks like packet/header validation, + retransmission and message parsing. + + @section design Design Philosophy + + The stack is fully-asynchronous in design for compatibility with event loop + mechanisms such as select, poll, etc. and can also be used for multi-threaded + applications. It should compile on Linux, *BSD, Mac OS X, Solaris and Windows + (cygwin). + + The stack is designed for high portability not only for the hardware and OS it will + run on but also for the application software that uses it. The stack doesn't mandate + conditions on the user application architecture or design. The stack relies on + the user application for infrastructure utilities such as I/O, timers, + logs and multithreading. This realized by using callback mechanisms and enables the + stack library to seamlessly integrate without or very little changes to the existing + application framework. + + The stack architecture builds upon following mentioned entities that are external to it. + + User Layer Protocol (ULP) Entity: + This layer implements the intelligent logic for the application and sits on top of the + stack. + + UDP Entity: + This is the layer below the stack and is responsible for UDP I/O with the stack and network. + It may or may not be housed in ULP. + + Timer Manager Entity: + Timer Manager Entity provides the stack with infrastructure for timer CRUD operations. + + Log Manager Entity: + Log Manager Entity provides the stack with callbacks for logging operations. It may + or may not be housed in ULP. + + The application may implement all above entities as a single or multiple object. + + @section applications Applications and Usage + + Please refer sample applications under 'test-app' directory for usage examples. + + */ + +/** + * @file NwGtpv2c.h + * @author Amit Chawre + * @brief + * + * This header file contains all required definitions and functions + * prototypes for using nw-gtpv2c library. + * + **/ + +/*--------------------------------------------------------------------------* + * S T A C K H A N D L E D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +typedef NwPtrT NwGtpv2cStackHandleT; /**< Gtpv2c Stack Handle */ +typedef NwPtrT NwGtpv2cUlpHandleT; /**< Gtpv2c Stack Ulp Entity Handle */ +typedef NwPtrT NwGtpv2cUdpHandleT; /**< Gtpv2c Stack Udp Entity Handle */ +typedef NwPtrT NwGtpv2cTimerMgrHandleT; /**< Gtpv2c Stack Timer Manager Handle */ +typedef NwPtrT NwGtpv2cMemMgrHandleT; /**< Gtpv2c Stack Memory Manager Handle */ +typedef NwPtrT NwGtpv2cLogMgrHandleT; /**< Gtpv2c Stack Log Manager Handle */ +typedef NwPtrT NwGtpv2cTimerHandleT; /**< Gtpv2c Stack Timer Handle */ +typedef NwPtrT NwGtpv2cMsgHandleT; /**< Gtpv2c Msg Handle */ +typedef NwPtrT NwGtpv2cTrxnHandleT; /**< Gtpv2c Transaction Handle */ +typedef NwPtrT NwGtpv2cTunnelHandleT; /**< Gtpv2c Ulp Tunnel Handle */ +typedef NwPtrT NwGtpv2cUlpTrxnHandleT; /**< Gtpv2c Ulp Transaction Handle */ +typedef NwPtrT NwGtpv2cUlpTunnelHandleT; /**< Gtpv2c Ulp Tunnel Handle */ + +typedef NwU8T NwGtpv2cMsgTypeT; /**< Gtpv2c Msg Type */ + +typedef struct NwGtpv2cStackConfigS +{ + NwU16T __tbd; +} NwGtpv2cStackConfigT; + +/*--------------------------------------------------------------------------* + * S T A C K A P I D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#define NW_GTPV2C_ULP_API_FLAG_NONE (0x00 << 24) +#define NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL (0x01 << 24) +#define NW_GTPV2C_ULP_API_FLAG_DELETE_LOCAL_TUNNEL (0x02 << 24) +#define NW_GTPV2C_ULP_API_FLAG_IS_COMMAND_MESSAGE (0x03 << 24) + +/*--------------------------------------------------------------------------- + * Gtpv2c Stack ULP API type definitions + *--------------------------------------------------------------------------*/ + +/** + * APIs types between ULP and Stack + */ + +typedef enum +{ + /* APIs from ULP to stack */ + + NW_GTPV2C_ULP_API_INITIAL_REQ = 0x00000000, /**< Send a initial message */ + NW_GTPV2C_ULP_API_TRIGGERED_REQ, /**< Send a triggered req message */ + NW_GTPV2C_ULP_API_TRIGGERED_RSP, /**< Send a triggered rsp message */ + + /* APIs from stack to ULP */ + + NW_GTPV2C_ULP_API_INITIAL_REQ_IND, /**< Receive a initial message from stack */ + NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND, /**< Recieve a triggered rsp message from stack */ + NW_GTPV2C_ULP_API_TRIGGERED_REQ_IND, /**< Recieve a triggered req message from stack */ + NW_GTPV2C_ULP_API_RSP_FAILURE_IND, /**< Rsp failure for gtpv2 message from stack */ + + /* Local tunnel management APIs from ULP to stack */ + + NW_GTPV2C_ULP_CREATE_LOCAL_TUNNEL, /**< Create a local tunnel */ + NW_GTPV2C_ULP_DELETE_LOCAL_TUNNEL, /**< Delete a local tunnel */ + + /* Do not add below this */ + NW_GTPV2C_ULP_API_END = 0xFFFFFFFF, + +} NwGtpv2cUlpApiTypeT; + +/** + * Error information of incoming GTP messages + */ + +typedef struct NwGtpv2cErrorS +{ + NW_IN NwU8T cause; + NW_IN NwU8T flags; + struct { + NW_IN NwU8T type; + NW_IN NwU8T instance; + } offendingIe; +} NwGtpv2cErrorT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c initial message. + */ + +typedef struct +{ + NW_INOUT NwGtpv2cTunnelHandleT hTunnel; /**< Tunnel handle over which the mesasge is to be sent.*/ + NW_IN NwU16T t3Timer; + NW_IN NwU16T maxRetries; + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; /**< Optional handle to be returned in rsp of this msg. */ + + NW_IN NwU32T peerIp; /**< Required only in case when hTunnel == 0 */ + NW_IN NwU32T teidLocal; /**< Required only in case when hTunnel == 0 */ + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; /**< Required only in case when hTunnel == 0 */ +} NwGtpv2cInitialReqInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c triggered request message. + */ + +typedef struct +{ + NW_IN NwGtpv2cTunnelHandleT hTunnel; /**< Tunnel handle over which the mesasge is to be sent */ + NW_IN NwGtpv2cTrxnHandleT hTrxn; /**< Request Trxn handle which to which triggered req is being sent */ + NW_IN NwU16T t3Timer; + NW_IN NwU16T maxRetries; + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; /**< Optional handle to be returned in rsp of this msg. */ + NW_IN NwU32T peerIp; /**< Required only in case when hTunnel == 0 */ + NW_IN NwU32T teidLocal; /**< Required only in case when hTunnel == 0 */ + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; /**< Required only in case when hTunnel == 0 */ + +} NwGtpv2cTriggeredReqInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c triggered response message. + */ + +typedef struct +{ + NW_IN NwGtpv2cTrxnHandleT hTrxn; /**< Request Trxn handle which to which triggered rsp is being sent */ + NW_IN NwU32T teidLocal; /**< Required only if NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL is set to flags. */ + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; /**< Required only if NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL is set to flags. */ + + NW_OUT NwGtpv2cTunnelHandleT hTunnel; /**< Returned only in case flags is set to + NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL */ +} NwGtpv2cTriggeredRspInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c initial message. + */ + +typedef struct +{ + NW_IN NwGtpv2cErrorT error; + NW_IN NwGtpv2cTrxnHandleT hTrxn; + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; + NW_IN NwGtpv2cMsgTypeT msgType; + NW_IN NwU32T peerIp; + NW_IN NwU32T peerPort; + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; + NW_INOUT NwGtpv2cTunnelHandleT hTunnel; +} NwGtpv2cInitialReqIndInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c triggered request message. + */ + +typedef struct +{ + NW_IN NwGtpv2cErrorT error; + NW_IN NwGtpv2cTrxnHandleT hTrxn; + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; + NW_IN NwGtpv2cMsgTypeT msgType; + NW_IN NwU32T seqNum; + NW_IN NwU32T teidLocal; + NW_IN NwU32T teidRemote; + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; +} NwGtpv2cTriggeredReqIndInfoT; + +/** + * API information elements between ULP and Stack for + * sending a Gtpv2c triggered response message. + */ + +typedef struct +{ + NW_IN NwGtpv2cErrorT error; + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; + NW_IN NwGtpv2cMsgTypeT msgType; +} NwGtpv2cTriggeredRspIndInfoT; + +/** + * API information elements between ULP and Stack for + * receving a path failure indication from stack. + */ + +typedef struct +{ + NW_IN NwGtpv2cUlpTrxnHandleT hUlpTrxn; + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; +} NwGtpv2cRspFailureIndInfoT; + +/** + * API information elements between ULP and Stack for + * creating local tunnel. + */ + +typedef struct +{ + NW_OUT NwGtpv2cTunnelHandleT hTunnel; + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel; + NW_IN NwU32T teidLocal; + NW_IN NwU32T peerIp; +} NwGtpv2cCreateLocalTunnelInfoT; + + +/** + * API information elements between ULP and Stack for + * deleting a local tunnel. + */ + +typedef struct +{ + NW_IN NwGtpv2cTunnelHandleT hTunnel; +} NwGtpv2cDeleteLocalTunnelInfoT; + + +/** + * API container structure between ULP and Stack. + */ + +typedef struct +{ + NwGtpv2cUlpApiTypeT apiType; /**< First bytes of this field is used as flag holder */ + NwGtpv2cMsgHandleT hMsg; /**< Handle associated with this API */ + union + { + NwGtpv2cInitialReqInfoT initialReqInfo; + NwGtpv2cTriggeredRspInfoT triggeredRspInfo; + NwGtpv2cTriggeredReqInfoT triggeredReqInfo; + NwGtpv2cInitialReqIndInfoT initialReqIndInfo; + NwGtpv2cTriggeredRspIndInfoT triggeredRspIndInfo; + NwGtpv2cTriggeredReqIndInfoT triggeredReqIndInfo; + NwGtpv2cRspFailureIndInfoT rspFailureInfo; + NwGtpv2cCreateLocalTunnelInfoT createLocalTunnelInfo; + NwGtpv2cDeleteLocalTunnelInfoT deleteLocalTunnelInfo; + } apiInfo; +} NwGtpv2cUlpApiT; + + +/*--------------------------------------------------------------------------* + * S T A C K E N T I T I E S D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +/** + * Gtpv2c ULP entity definition + */ + +typedef struct +{ + NwGtpv2cUlpHandleT hUlp; + NwRcT (*ulpReqCallback) ( NW_IN NwGtpv2cUlpHandleT hUlp, + NW_IN NwGtpv2cUlpApiT *pUlpApi); +} NwGtpv2cUlpEntityT; + + +/** + * Gtpv2c UDP entity definition + */ + +typedef struct +{ + NwGtpv2cUdpHandleT hUdp; + NwRcT (*udpDataReqCallback) ( NW_IN NwGtpv2cUdpHandleT udpHandle, + NW_IN NwU8T* dataBuf, + NW_IN NwU32T dataSize, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort); +} NwGtpv2cUdpEntityT; + +/** + * Gtpv2c Memory Manager entity definition + */ + +typedef struct +{ + NwGtpv2cMemMgrHandleT hMemMgr; + void* (*memAlloc)( NW_IN NwGtpv2cMemMgrHandleT hMemMgr, + NW_IN NwU32T memSize, + NW_IN NwCharT* fileName, + NW_IN NwU32T lineNumber); + + void (*memFree) ( NW_IN NwGtpv2cMemMgrHandleT hMemMgr, + NW_IN void* hMem, + NW_IN NwCharT* fileName, + NW_IN NwU32T lineNumber); +} NwGtpv2cMemMgrEntityT; + + +#define NW_GTPV2C_TMR_TYPE_ONE_SHOT (0) +#define NW_GTPV2C_TMR_TYPE_REPETITIVE (1) +/** + * Gtpv2c Timer Manager entity definition + */ + +typedef struct +{ + NwGtpv2cTimerMgrHandleT tmrMgrHandle; + NwRcT (*tmrStartCallback)( NW_IN NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NW_IN NwU32T timeoutSec, + NW_IN NwU32T timeoutUsec, + NW_IN NwU32T tmrType, + NW_IN void* tmrArg, + NW_OUT NwGtpv2cTimerHandleT* tmrHandle); + + NwRcT (*tmrStopCallback) ( NW_IN NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NW_IN NwGtpv2cTimerHandleT tmrHandle); +} NwGtpv2cTimerMgrEntityT; + +/** + * Gtpv2c Log manager entity definition + */ + +typedef struct +{ + NwGtpv2cLogMgrHandleT logMgrHandle; + NwRcT (*logReqCallback) (NW_IN NwGtpv2cLogMgrHandleT logMgrHandle, + NW_IN NwU32T logLevel, + NW_IN NwCharT* filename, + NW_IN NwU32T line, + NW_IN NwCharT* logStr); +} NwGtpv2cLogMgrEntityT; + + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + Constructor. Initialize nw-gtpv2c stack instance. + + @param[in,out] phGtpcStackHandle : Pointer to stack instance handle + */ + +NwRcT +nwGtpv2cInitialize( NW_INOUT NwGtpv2cStackHandleT* phGtpcStackHandle); + +/** + Destructor. Destroy nw-gtpv2c stack instance . + + @param[in] hGtpcStackHandle : Stack instance handle + */ + +NwRcT +nwGtpv2cFinalize( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle); + +/** + Set Configuration for the nw-gtpv2c stack. + + @param[in,out] phGtpcStackHandle : Pointer to stack handle + */ + +NwRcT +nwGtpv2cConfigSet( NW_IN NwGtpv2cStackHandleT* phGtpcStackHandle, NW_IN NwGtpv2cStackConfigT* pConfig); + +/** + Get Configuration for the nw-gtpv2c stack. + + @param[in,out] phGtpcStackHandle : Pointer to stack handle + */ + +NwRcT +nwGtpv2cConfigGet( NW_IN NwGtpv2cStackHandleT* phGtpcStackHandle, NW_OUT NwGtpv2cStackConfigT* pConfig); + +/** + Set ULP entity for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpEntity : Pointer to ULP entity. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetUlpEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUlpEntityT* pUlpEntity); + +/** + Set UDP entity for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUdpEntity : Pointer to UDP entity. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetUdpEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUdpEntityT* pUdpEntity); + +/** + Set MemMgr entity for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pMemMgr : Pointer to Memory Manager. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetMemMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMemMgrEntityT* pMemMgr); + + +/** + Set TmrMgr entity for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pTmrMgr : Pointer to Timer Manager. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetTimerMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cTimerMgrEntityT* pTmrMgr); + +/** + Set LogMgr entity for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pLogMgr : Pointer to Log Manager. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetLogMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cLogMgrEntityT* pLogMgr); + +/** + Set log level for the stack. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] logLevel : Log Level. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cSetLogLevel( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU32T logLevel); + + +/** + Process Data Request from UDP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] udpData : Pointer to received UDP data. + @param[in] udpDataLen : Received data length. + @param[in] dstPort : Received on port. + @param[in] from : Received from peer information. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cProcessUdpReq( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T* udpData, + NW_IN NwU32T udpDataLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIP); + +/** + Process Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pLogMgr : Pointer to Ulp Req. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cProcessUlpReq( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUlpApiT *ulpReq); + + +/** + Process Timer timeout Request from Timer Manager + + @param[in] pLogMgr : Pointer timeout arguments. + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cProcessTimeout( NW_IN void* timeoutArg); + + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cIe.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cIe.h new file mode 100644 index 0000000000..62b9c06459 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cIe.h @@ -0,0 +1,159 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +/** + * @file NwGtpv2cIe.h + * @brief This header file contains Information Element definitions for GTPv2c + * as per 3GPP TS 29274-930. +*/ + +#ifndef __NW_GTPV2C_IE_H__ +#define __NW_GTPV2C_IE_H__ + +/*--------------------------------------------------------------------------* + * G T P V 2 C I E T Y P E M A C R O D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#define NW_GTPV2C_IE_RESERVED (0) +#define NW_GTPV2C_IE_IMSI (1) +#define NW_GTPV2C_IE_CAUSE (2) +#define NW_GTPV2C_IE_RECOVERY (3) +#define NW_GTPV2C_IE_APN (71) +#define NW_GTPV2C_IE_AMBR (72) +#define NW_GTPV2C_IE_EBI (73) +#define NW_GTPV2C_IE_IP_ADDRESS (74) +#define NW_GTPV2C_IE_MEI (75) +#define NW_GTPV2C_IE_MSISDN (76) +#define NW_GTPV2C_IE_INDICATION (77) +#define NW_GTPV2C_IE_PCO (78) +#define NW_GTPV2C_IE_PAA (79) +#define NW_GTPV2C_IE_BEARER_LEVEL_QOS (80) +#define NW_GTPV2C_IE_FLOW_QOS (81) +#define NW_GTPV2C_IE_RAT_TYPE (82) +#define NW_GTPV2C_IE_SERVING_NETWORK (83) +#define NW_GTPV2C_IE_BEARER_TFT (84) +#define NW_GTPV2C_IE_TAD (85) +#define NW_GTPV2C_IE_ULI (86) +#define NW_GTPV2C_IE_FTEID (87) +#define NW_GTPV2C_IE_TMSI (88) +#define NW_GTPV2C_IE_GLOBAL_CN_ID (89) +#define NW_GTPV2C_IE_S103PDF (90) +#define NW_GTPV2C_IE_S1UDF (91) +#define NW_GTPV2C_IE_DELAY_VALUE (92) +#define NW_GTPV2C_IE_BEARER_CONTEXT (93) +#define NW_GTPV2C_IE_CHARGING_ID (94) +#define NW_GTPV2C_IE_CHARGING_CHARACTERISTICS (95) +#define NW_GTPV2C_IE_TRACE_INFORMATION (96) +#define NW_GTPV2C_IE_BEARER_FLAGS (97) +#define NW_GTPV2C_IE_PDN_TYPE (99) +#define NW_GTPV2C_IE_PROCEDURE_TRANSACTION_ID (100) +#define NW_GTPV2C_IE_DRX_PARAMETER (101) +#define NW_GTPV2C_IE_UE_NETWORK_CAPABILITY (102) +#define NW_GTPV2C_IE_MM_CONTEXT (103) +#define NW_GTPV2C_IE_PDN_CONNECTION (109) +#define NW_GTPV2C_IE_PDU_NUMBERS (110) +#define NW_GTPV2C_IE_PTMSI (111) +#define NW_GTPV2C_IE_PTMSI_SIGNATURE (112) +#define NW_GTPV2C_IE_HOP_COUNTER (113) +#define NW_GTPV2C_IE_UE_TIME_ZONE (114) +#define NW_GTPV2C_IE_TRACE_REFERENCE (115) +#define NW_GTPV2C_IE_COMPLETE_REQUEST_MESSAGE (116) +#define NW_GTPV2C_IE_GUTI (117) +#define NW_GTPV2C_IE_F_CONTAINER (118) +#define NW_GTPV2C_IE_F_CAUSE (119) +#define NW_GTPV2C_IE_SELECTED_PLMN_ID (120) +#define NW_GTPV2C_IE_TARGET_IDENTIFICATION (121) +#define NW_GTPV2C_IE_PACKET_FLOW_ID (123) +#define NW_GTPV2C_IE_RAB_CONTEXT (124) +#define NW_GTPV2C_IE_SOURCE_RNC_PDCP_CONTEXT_INFO (125) +#define NW_GTPV2C_IE_UDP_SOURCE_PORT_NUMBER (126) +#define NW_GTPV2C_IE_APN_RESTRICTION (127) +#define NW_GTPV2C_IE_SELECTION_MODE (128) +#define NW_GTPV2C_IE_SOURCE_IDENTIFICATION (129) +#define NW_GTPV2C_IE_CHANGE_REPORTING_ACTION (131) +#define NW_GTPV2C_IE_FQ_CSID (132) +#define NW_GTPV2C_IE_CHANNEL_NEEDED (133) +#define NW_GTPV2C_IE_EMLPP_PRIORITY (134) +#define NW_GTPV2C_IE_NODE_TYPE (135) +#define NW_GTPV2C_IE_FQDN (136) +#define NW_GTPV2C_IE_TI (137) +#define NW_GTPV2C_IE_MBMS_SESSION_DURATION (138) +#define NW_GTPV2C_IE_MBMS_SERIVCE_AREA (139) +#define NW_GTPV2C_IE_MBMS_SESSION_IDENTIFIER (140) +#define NW_GTPV2C_IE_MBMS_FLOW_IDENTIFIER (141) +#define NW_GTPV2C_IE_MBMS_IP_MULTICAST_DISTRIBUTION (142) +#define NW_GTPV2C_IE_MBMS_IP_DISTRIBUTION_ACK (143) +#define NW_GTPV2C_IE_RFSP_INDEX (144) +#define NW_GTPV2C_IE_UCI (145) +#define NW_GTPV2C_IE_CSG_INFORMATION_REPORTING_ACTION (146) +#define NW_GTPV2C_IE_CSG_ID (147) +#define NW_GTPV2C_IE_CSG_MEMBERSHIP_INDICATION (148) +#define NW_GTPV2C_IE_SERVICE_INDICATOR (149) +#define NW_GTPV2C_IE_LDN (151) +#define NW_GTPV2C_IE_ADDITIONAL_MM_CTXT_FOR_SRVCC (159) +#define NW_GTPV2C_IE_ADDITIONAL_FLAGS_FOR_SRVCC (160) +#define NW_GTPV2C_IE_PRIVATE_EXTENSION (255) +#define NW_GTPV2C_IE_TYPE_MAXIMUM (256) + + +/*--------------------------------------------------------------------------* + * G T P V 2 C C A U S E V A L U E D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#define NW_GTPV2C_CAUSE_REQUEST_ACCEPTED (16) +#define NW_GTPV2C_CAUSE_INVALID_LENGTH (67) +#define NW_GTPV2C_CAUSE_MANDATORY_IE_INCORRECT (69) +#define NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING (70) +#define NW_GTPV2C_CAUSE_SYSTEM_FAILURE (72) +#define NW_GTPV2C_CAUSE_REQUEST_REJECTED (94) +#define NW_GTPV2C_CAUSE_REMOTE_PEER_NOT_RESPONDING (100) +#define NW_GTPV2C_CAUSE_CONDITIONAL_IE_MISSING (103) + +#define NW_GTPV2C_IE_INSTANCE_ZERO (0) +#define NW_GTPV2C_IE_INSTANCE_ONE (1) +#define NW_GTPV2C_IE_INSTANCE_TWO (2) +#define NW_GTPV2C_IE_INSTANCE_THREE (3) +#define NW_GTPV2C_IE_INSTANCE_FOUR (4) +#define NW_GTPV2C_IE_INSTANCE_MAXIMUM (NW_GTPV2C_IE_INSTANCE_FOUR) + +#define NW_GTPV2C_IE_PRESENCE_MANDATORY (1) +#define NW_GTPV2C_IE_PRESENCE_CONDITIONAL (2) +#define NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL (3) +#define NW_GTPV2C_IE_PRESENCE_OPTIONAL (4) + +#endif /* __NW_GTPV2C_IE_H__ */ + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsg.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsg.h new file mode 100644 index 0000000000..9e7ab6df38 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsg.h @@ -0,0 +1,631 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_GTPV2C_MSG_H__ +#define __NW_GTPV2C_MSG_H__ + +#include "NwTypes.h" +#include "NwGtpv2c.h" + +/** + * @file NwGtpv2cMsg.h + * @brief This file defines APIs for to build new outgoing gtpv2c messages and to parse incoming messages. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------* + * S H A R E D A P I M A C R O S * + *--------------------------------------------------------------------------*/ + + +#define NW_GTP_VERSION (0x02) /**< GTP Version */ +#define NW_GTPV2C_MINIMUM_HEADER_SIZE (8) /**< Size of GTPv2c minimun header */ +#define NW_GTPV2C_EPC_SPECIFIC_HEADER_SIZE (12) /**< Size of GTPv2c EPC specific header */ + +/* GTP Message Type Values */ +#define NW_GTP_ECHO_REQ (1) +#define NW_GTP_ECHO_RSP (2) +#define NW_GTP_VERSION_NOT_SUPPORTED_IND (3) +#define NW_GTP_CREATE_SESSION_REQ (32) +#define NW_GTP_CREATE_SESSION_RSP (33) +#define NW_GTP_MODIFY_BEARER_REQ (34) +#define NW_GTP_MODIFY_BEARER_RSP (35) +#define NW_GTP_DELETE_SESSION_REQ (36) +#define NW_GTP_DELETE_SESSION_RSP (37) +#define NW_GTP_MODIFY_BEARER_CMD (64) +#define NW_GTP_MODIFY_BEARER_FAILURE_IND (65) +#define NW_GTP_DELETE_BEARER_CMD (66) +#define NW_GTP_DELETE_BEARER_FAILURE_IND (67) +#define NW_GTP_BEARER_RESOURCE_CMD (68) +#define NW_GTP_BEARER_RESOURCE_FAILURE_IND (69) +#define NW_GTP_DOWNLINK_DATA_NOTIFICATION_FAILURE_IND (70) +#define NW_GTP_TRACE_SESSION_ACTIVATION (71) +#define NW_GTP_TRACE_SESSION_DEACTIVATION (72) +#define NW_GTP_STOP_PAGING_IND (73) +#define NW_GTP_CREATE_BEARER_REQ (95) +#define NW_GTP_CREATE_BEARER_RSP (96) +#define NW_GTP_UPDATE_BEARER_REQ (97) +#define NW_GTP_UPDATE_BEARER_RSP (98) +#define NW_GTP_DELETE_BEARER_REQ (99) +#define NW_GTP_DELETE_BEARER_RSP (100) +#define NW_GTP_DELETE_PDN_CONNECTION_SET_REQ (101) +#define NW_GTP_DELETE_PDN_CONNECTION_SET_RSP (102) +#define NW_GTP_IDENTIFICATION_REQ (128) +#define NW_GTP_IDENTIFICATION_RSP (129) +#define NW_GTP_CONTEXT_REQ (130) +#define NW_GTP_CONTEXT_RSP (131) +#define NW_GTP_CONTEXT_ACK (132) +#define NW_GTP_FORWARD_RELOCATION_REQ (133) +#define NW_GTP_FORWARD_RELOCATION_RSP (134) +#define NW_GTP_FORWARD_RELOCATION_COMPLETE_NTF (135) +#define NW_GTP_FORWARD_RELOCATION_COMPLETE_ACK (136) +#define NW_GTP_FORWARD_ACCESS_CONTEXT_NTF (137) +#define NW_GTP_FORWARD_ACCESS_CONTEXT_ACK (138) +#define NW_GTP_RELOCATION_CANCEL_REQ (139) +#define NW_GTP_RELOCATION_CANCEL_RSP (140) +#define NW_GTP_CONFIGURE_TRANSFER_TUNNEL (141) +#define NW_GTP_DETACH_NTF (149) +#define NW_GTP_DETACH_ACK (150) +#define NW_GTP_CS_PAGING_INDICATION (151) +#define NW_GTP_RAN_INFORMATION_RELAY (152) +#define NW_GTP_ALERT_MME_NTF (153) +#define NW_GTP_ALERT_MME_ACK (154) +#define NW_GTP_UE_ACTIVITY_NTF (155) +#define NW_GTP_UE_ACTIVITY_ACK (156) +#define NW_GTP_CREATE_FORWARDING_TUNNEL_REQ (160) +#define NW_GTP_CREATE_FORWARDING_TUNNEL_RSP (161) +#define NW_GTP_SUSPEND_NTF (162) +#define NW_GTP_SUSPEND_ACK (163) +#define NW_GTP_RESUME_NTF (164) +#define NW_GTP_RESUME_ACK (165) +#define NW_GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQ (166) +#define NW_GTP_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RSP (167) +#define NW_GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQ (168) +#define NW_GTP_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RSP (169) +#define NW_GTP_RELEASE_ACCESS_BEARERS_REQ (170) +#define NW_GTP_RELEASE_ACCESS_BEARERS_RSP (171) +#define NW_GTP_DOWNLINK_DATA_NOTIFICATION (176) +#define NW_GTP_DOWNLINK_DATA_NOTIFICATION_ACK (177) +#define NW_GTP_RESERVED (178) +#define NW_GTP_UPDATE_PDN_CONNECTION_SET_REQ (200) +#define NW_GTP_UPDATE_PDN_CONNECTION_SET_RSP (201) +#define NW_GTP_MBMS_SESSION_START_REQ (231) +#define NW_GTP_MBMS_SESSION_START_RSP (232) +#define NW_GTP_MBMS_SESSION_UPDATE_REQ (233) +#define NW_GTP_MBMS_SESSION_UPDATE_RSP (234) +#define NW_GTP_MBMS_SESSION_STOP_REQ (235) +#define NW_GTP_MBMS_SESSION_STOP_RSP (236) +#define NW_GTP_MSG_END (255) + + +/* Cause Values */ +#define NW_GTPV2C_CAUSE_BIT_NONE (0x00) +#define NW_GTPV2C_CAUSE_BIT_CS (0x01) +#define NW_GTPV2C_CAUSE_BIT_BCE (0x02) +#define NW_GTPV2C_CAUSE_BIT_PCE (0x04) + +/* RAT Type Values */ +#define NW_RAT_TYPE_EUTRAN (0x06) + +/* PDN Type Values */ +#define NW_PDN_TYPE_IPv4 (0x01) +#define NW_PDN_TYPE_IPv6 (0x02) +#define NW_PDN_TYPE_IPv4IPv6 (0x03) + +/* Interface Type Values */ +#define NW_GTPV2C_IFTYPE_S1U_ENODEB_GTPU (0) +#define NW_GTPV2C_IFTYPE_S1U_SGW_GTPU (1) +#define NW_GTPV2C_IFTYPE_S12_RNC_GTPU (2) +#define NW_GTPV2C_IFTYPE_S12_SGW_GTPU (3) +#define NW_GTPV2C_IFTYPE_S5S8_SGW_GTPU (4) +#define NW_GTPV2C_IFTYPE_S5S8_PGW_GTPU (5) +#define NW_GTPV2C_IFTYPE_S5S8_SGW_GTPC (6) +#define NW_GTPV2C_IFTYPE_S5S8_PGW_GTPC (7) +#define NW_GTPV2C_IFTYPE_S5S8_SGW_PIMPv6 (8) +#define NW_GTPV2C_IFTYPE_S5S8_PGW_PIMPv6 (9) +#define NW_GTPV2C_IFTYPE_S11_MME_GTPC (10) +#define NW_GTPV2C_IFTYPE_S11S4_SGW_GTPC (11) + +/* Indication Flag Values */ +#define NW_GTPV2C_INDICATION_FLAG_NONE (0x0000) +#define NW_GTPV2C_INDICATION_FLAG_DAF (0x8000) +#define NW_GTPV2C_INDICATION_FLAG_DTF (0x4000) +#define NW_GTPV2C_INDICATION_FLAG_HI (0x2000) +#define NW_GTPV2C_INDICATION_FLAG_DFI (0x1000) +#define NW_GTPV2C_INDICATION_FLAG_OI (0x0800) +#define NW_GTPV2C_INDICATION_FLAG_ISRSI (0x0400) +#define NW_GTPV2C_INDICATION_FLAG_ISRAI (0x0200) +#define NW_GTPV2C_INDICATION_FLAG_SGWCI (0x0100) + +#define NW_GTPV2C_INDICATION_FLAG_SPARE (0x0080) +#define NW_GTPV2C_INDICATION_FLAG_UMSI (0x0040) +#define NW_GTPV2C_INDICATION_FLAG_CSFI (0x0020) +#define NW_GTPV2C_INDICATION_FLAG_CRSI (0x0010) +#define NW_GTPV2C_INDICATION_FLAG_PS (0x0008) +#define NW_GTPV2C_INDICATION_FLAG_PT (0x0004) +#define NW_GTPV2C_INDICATION_FLAG_SI (0x0002) +#define NW_GTPV2C_INDICATION_FLAG_MSV (0x0001) + +/*--------------------------------------------------------------------------* + * G T P V 2 C I E D A T A - T Y P E D E F I N I T I O N S * + *--------------------------------------------------------------------------*/ + +#pragma pack(1) + +typedef struct NwGtpv2cIeTv1 +{ + NwU8T t; + NwU16T l; + NwU8T i; + NwU8T v; +} NwGtpv2cIeTv1T; + +typedef struct NwGtpv2cIeTv2 +{ + NwU8T t; + NwU16T l; + NwU8T i; + NwU16T v; +} NwGtpv2cIeTv2T; + +typedef struct NwGtpv2cIeTv4 +{ + NwU8T t; + NwU16T l; + NwU8T i; + NwU32T v; +} NwGtpv2cIeTv4T; + +typedef struct NwGtpv2cIeTv8 +{ + NwU8T t; + NwU16T l; + NwU8T i; + NwU64T v; +} NwGtpv2cIeTv8T; + +typedef struct NwGtpv2cIeTlv +{ + NwU8T t; + NwU16T l; + NwU8T i; +} NwGtpv2cIeTlvT; + +#pragma pack() + + + /** + * Allocate a gtpv2c message. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] teidPresent : TEID is present flag. + * @param[in] msgType : Message type for this message. + * @param[in] teid : TEID for this message. + * @param[in] seqNum : Sequence number for this message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwRcT +nwGtpv2cMsgNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T teidPresent, + NW_IN NwU8T msgType, + NW_IN NwU32T teid, + NW_IN NwU32T seqNum, + NW_OUT NwGtpv2cMsgHandleT *phMsg); + + + /** + * Allocate a gtpv2c message from data buffer. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] pBuf: Buffer to be copied in this message. + * @param[in] bufLen: Buffer length to be copied in this message. + * @param[out] phMsg : Pointer to message handle. + */ + +NwRcT +nwGtpv2cMsgFromBufferNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T* pBuf, + NW_IN NwU32T bufLen, + NW_OUT NwGtpv2cMsgHandleT *phMsg); + + /** + * Free a gtpv2c message. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] hMsg : Message handle. + */ + +NwRcT +nwGtpv2cMsgDelete( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMsgHandleT hMsg); + + /** + * Set TEID for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] teid: TEID value. + */ + +NwRcT +nwGtpv2cMsgSetTeid(NW_IN NwGtpv2cMsgHandleT hMsg, NwU32T teid); + + /** + * Set TEID present flag for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] teidPesent: Flag boolean value. + */ + +NwRcT +nwGtpv2cMsgSetTeidPresent(NW_IN NwGtpv2cMsgHandleT hMsg, NwBoolT teidPresent); + + /** + * Set sequence for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] seqNum: Flag boolean value. + */ + +NwRcT +nwGtpv2cMsgSetSeqNumber(NW_IN NwGtpv2cMsgHandleT hMsg, NwU32T seqNum); + + /** + * Get TEID present for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetTeid(NW_IN NwGtpv2cMsgHandleT hMsg); + + /** + * Get TEID present for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwBoolT +nwGtpv2cMsgGetTeidPresent(NW_IN NwGtpv2cMsgHandleT hMsg); + + /** + * Get sequence number for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetSeqNumber(NW_IN NwGtpv2cMsgHandleT hMsg); + + /** + * Get msg lenght for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetLength(NW_IN NwGtpv2cMsgHandleT hMsg); + + /** + * Add a gtpv2c information element of length 1 to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE type. + * @param[in] instance : IE instance. + * @param[in] value : IE value. + */ + +NwRcT +nwGtpv2cMsgAddIeTV1(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU8T value); + + + /** + * Add a gtpv2c information element of length 2 to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE type. + * @param[in] instance : IE instance. + * @param[in] value : IE value. + */ + +NwRcT +nwGtpv2cMsgAddIeTV2(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU16T value); + + + /** + * Add a gtpv2c information element of length 4 to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE type. + * @param[in] instance : IE instance. + * @param[in] value : IE value. + */ + +NwRcT +nwGtpv2cMsgAddIeTV4(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU32T value); + + + /** + * Add a gtpv2c information element of variable length to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE type. + * @param[in] length : IE length. + * @param[in] instance : IE instance. + * @param[in] value : IE value. + */ + +NwRcT +nwGtpv2cMsgAddIe(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU8T instance, + NW_IN NwU8T* pVal); + + /** + * Add CAUSE information element to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] instance : IE instance. + * @param[in] causeValue: Cause value. + * @param[in] bitFlags: PDN Connetiion IE Error Flag, Bearer Context IE Error Flag, Cause Source Flag. + * @param[in] offendingIeType: Offending IE type. + * @param[in] offendingIeInstance: Offending IE instance. + */ + +NwRcT +nwGtpv2cMsgAddIeCause(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_IN NwU8T causeValue, + NW_IN NwU8T bitFlags, + NW_IN NwU8T offendingIeType, + NW_IN NwU8T offendingIeInstance); + + /** + * Add F-TEID information element to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] instance : IE instance. + * @param[in] ifType : Interface Type. + * @param[in] teidOrGreKey: TEID/ GRE Key + * @param[in] ipv4Addr : Ipv4 Address in Network Byte Order. + * @param[in] pIpv6Addr: Pointer to IPv6 Address in Network Byte Order. + */ + +NwRcT +nwGtpv2cMsgAddIeFteid(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_IN NwU8T ifType, + NW_IN NwU32T teidOrGreKey, + NW_IN NwU32T ipv4Addr, + NW_IN NwU8T* pIpv6Addr); + +NwRcT +nwGtpv2cMsgGroupedIeStart(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance); + +NwRcT +nwGtpv2cMsgGroupedIeEnd(NW_IN NwGtpv2cMsgHandleT hMsg); + + + /** + * Check if information element of type and instance is present + * in gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE Type. + * @param[in] instance : IE instance. + * @return NW_TRUE on success, NW_FALSE on failure. + */ + +NwBoolT +nwGtpv2cMsgIsIePresent(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance); + + /** + * Get an information element of type 'NwU8T' from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] type : IE Type. + * @param[in] instance : IE instance. + * @param[out] pVal : Pointer to value buffer. + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cMsgGetIeTV1(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU8T* pVal); + + /** + * Get an information element of type 'NwU16T' from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] tyep : IE Type. + * @param[in] instance : IE instance. + * @param[out] pVal : Pointer to value buffer. + * @return NW_OK on success. + */ + + +NwRcT +nwGtpv2cMsgGetIeTV2(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU16T* pVal); + + /** + * Get an information element of type 'NwU32T' from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] tyep : IE Type. + * @param[in] instance : IE instance. + * @param[out] pVal : Pointer to value buffer. + * @return NW_OK on success. + */ + + +NwRcT +nwGtpv2cMsgGetIeTV4(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU32T* pVal); + + /** + * Get an information element of type 'NwU64T' from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] tyep : IE Type. + * @param[in] instance : IE instance. + * @param[out] pVal : Pointer to IE value buffer. + * @return NW_OK on success. + */ + + +NwRcT +nwGtpv2cMsgGetIeTV8(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU64T* pVal); + + /** + * Get an information element of variable length from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] tyep : IE Type. + * @param[in] instance : IE instance. + * @param[in] maxLen : Maximum length of IE. + * @param[out] pVal : Pointer to IE value buffer. + * @param[out] pLen : Pointer to IE length buffer. + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cMsgGetIeTlv(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU16T maxLen, + NW_OUT NwU8T* pVal, + NW_OUT NwU16T* pLen); + + /** + * Get an information element of variable length from gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] tyep : IE Type. + * @param[in] instance : IE instance. + * @param[out] ppVal : Pointer to IE value buffer pointer. + * @param[out] pLen : Pointer to IE length buffer. + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cMsgGetIeTlvP(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU8T** ppVal, + NW_OUT NwU16T* pLen); + + + /** + * Get F-TEID information element to gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] instance : IE instance. + * @param[out] ifType : Interface Type. + * @param[out] teidOrGreKey: TEID/ GRE Key + * @param[out] ipv4Addr : Ipv4 Address in Network Byte Order. + * @param[out] pIpv6Addr: Pointer to IPv6 Address in Network Byte Order. + */ + +NwRcT +nwGtpv2cMsgGetIeFteid(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_OUT NwU8T* ifType, + NW_OUT NwU32T* teidOrGreKey, + NW_OUT NwU32T* ipv4Addr, + NW_OUT NwU8T* pIpv6Addr); + +NwRcT +nwGtpv2cMsgGetIeCause(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_OUT NwU8T* causeValue, + NW_OUT NwU8T* flags, + NW_OUT NwU8T* offendingIeType, + NW_OUT NwU8T* offendingIeInstance); + + /** + * Get msg type for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetMsgType(NW_IN NwGtpv2cMsgHandleT hMsg); + +/** + * Dump the contents of gtpv2c message. + * + * @param[in] hMsg : Handle to gtpv2c message. + * @param[in] fp: Pointer to output file. + */ + +NwRcT +nwGtpv2cMsgHexDump(NwGtpv2cMsgHandleT hMsg, FILE* fp); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_MSG_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsgParser.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsgParser.h new file mode 100644 index 0000000000..e0a2db871b --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwGtpv2cMsgParser.h @@ -0,0 +1,154 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <string.h> +#include "NwTypes.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" + +#ifndef __NW_GTPV2C_MSG_PARSER_H__ +#define __NW_GTPV2C_MSG_PARSER_H__ + +/** + * @file NwGtpv2cMsgParser.h + * @brief This file defines APIs to parser gtpv2c messages. +*/ + +typedef struct +{ + NwU16T msgType; + NwU16T mandatoryIeCount; + NwGtpv2cStackHandleT hStack; + NwRcT (*ieReadCallback) (NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T* ieValue, void* ieReadCallbackArg); + void* ieReadCallbackArg; + + struct { + NwU8T iePresence; + NwRcT (*ieReadCallback) (NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T* ieValue, void* ieReadCallbackArg); + void* ieReadCallbackArg; + } ieParseInfo[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; + + NwU8T *pIe[NW_GTPV2C_IE_TYPE_MAXIMUM][NW_GTPV2C_IE_INSTANCE_MAXIMUM]; +} NwGtpv2cMsgParserT; + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Allocate a gtpv2c message Parser. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] msgType : Message type for this message parser. + * @param[out] pthiz : Pointer to message parser handle. + */ + +NwRcT +nwGtpv2cMsgParserNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T msgType, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg, + NW_IN NwGtpv2cMsgParserT **pthiz); + + + /** + * Free a gtpv2c message parser. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] thiz : Message parser handle. + */ + +NwRcT +nwGtpv2cMsgParserDelete( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMsgParserT* thiz); + +NwRcT +nwGtpv2cMsgParserUpdateIe( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwU8T ieType, + NW_IN NwU8T ieInstance, + NW_IN NwU8T iePresence, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg); + + +NwRcT +nwGtpv2cMsgParserUpdateIeReadCallback( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg)); + + +NwRcT +nwGtpv2cMsgParserUpdateIeReadCallbackArg( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN void* ieReadCallbackArg); + +NwRcT +nwGtpv2cMsgParserAddIe( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwU8T ieType, + NW_IN NwU8T ieInstance, + NW_IN NwU8T iePresence, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg); + +NwRcT +nwGtpv2cMsgParserRun( NW_IN NwGtpv2cMsgParserT *thiz, + NW_IN NwGtpv2cMsgHandleT hMsg, + NW_OUT NwU8T *pOffendingIeType, + NW_OUT NwU8T *pOffendingIeInstance, + NW_OUT NwU16T *pOffendingIeLength); + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_GTPV2C_MSG_PARSER_H__ */ + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwLog.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwLog.h new file mode 100644 index 0000000000..c760cd9996 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwLog.h @@ -0,0 +1,85 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#ifndef __NW_LOG_H__ +#define __NW_LOG_H__ + +#include <libgen.h> + +#include "NwTypes.h" + +/** + * @file NwLog.h + * @brief This header file contains global shared logging definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/*--------------------------------------------------------------------------- + * Log Level Definitions + *--------------------------------------------------------------------------*/ + +#define NW_LOG_LEVEL_EMER (0) /**< system is unusable */ +#define NW_LOG_LEVEL_ALER (1) /**< action must be taken immediately*/ +#define NW_LOG_LEVEL_CRIT (2) /**< critical conditions */ +#define NW_LOG_LEVEL_ERRO (3) /**< error conditions */ +#define NW_LOG_LEVEL_WARN (4) /**< warning conditions */ +#define NW_LOG_LEVEL_NOTI (5) /**< normal but signification condition */ +#define NW_LOG_LEVEL_INFO (6) /**< informational */ +#define NW_LOG_LEVEL_DEBG (7) /**< debug-level messages */ + +/*--------------------------------------------------------------------------- + * IPv4 logging macros + *--------------------------------------------------------------------------*/ + +#define NW_IPV4_ADDR "%u.%u.%u.%u" +#define NW_IPV4_ADDR_FORMAT(__addr) (NwU8T)((__addr) & 0x000000ff), \ + (NwU8T)(((__addr) & 0x0000ff00) >> 8 ), \ + (NwU8T)(((__addr) & 0x00ff0000) >> 16), \ + (NwU8T)(((__addr) & 0xff000000) >> 24) + +#define NW_IPV4_ADDR_FORMATP(__paddr) (NwU8T)(*((NwU8T*)(__paddr)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 1)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 2)) & 0x000000ff), \ + (NwU8T)(*((NwU8T*)(__paddr + 3)) & 0x000000ff) + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_LOG_H__ */ + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwTypes.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwTypes.h new file mode 100644 index 0000000000..05b938c366 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwTypes.h @@ -0,0 +1,83 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + + +#include <stdlib.h> +#include <stdint.h> + +#ifndef __NW_TYPES_H__ +#define __NW_TYPES_H__ + +/** + * @file NwTypes.h + * @brief This header file contains basic type definitions. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +#define NW_IN /**< An input argument */ +#define NW_OUT /**< An output argument */ +#define NW_INOUT /**< An input and output argument */ + +#define NW_TRUE (1) /**< Truth value */ +#define NW_FALSE (0) /**< False value */ + +typedef unsigned char NwU8T; /**< Unsigned 1 byte */ +typedef unsigned short NwU16T; /**< Unsigned 2 byte */ +typedef unsigned int NwU32T; /**< Unsigned 4 byte */ +typedef unsigned long long NwU64T; /**< Unsigned 8 byte */ + +typedef signed char NwS8T; /**< Signed 1 byte */ +typedef signed short NwS16T; /**< Signed 2 byte */ +typedef signed int NwS32T; /**< Signed 4 byte */ +typedef signed long long NwS64T; /**< Signed 8 byte */ + +typedef char NwBoolT; /**< Use this for booleans */ + +typedef char NwCharT; /**< Use this for strings */ + +typedef signed int NwFdT; /**< Use this for file descriptor */ + +typedef uintptr_t NwPtrT; /**< Use this for generic pointers */ +typedef unsigned int NwHandleT; /**< Use this for generic handles */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __NW_TYPES_H__ */ + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwUtils.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwUtils.h new file mode 100644 index 0000000000..5be0736b75 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/shared/NwUtils.h @@ -0,0 +1,69 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <assert.h> + +#ifndef __NW_UTILS_H__ +#define __NW_UTILS_H__ + + +/** + * @file NwUtils.h + * @brief This header file contains utility macro and function definitions. +*/ + +#define NW_ASSERT assert /**< Assertion */ + +#define NW_CHK_NULL_PTR(_ptr) NW_ASSERT(_ptr != NULL) /**< Null pointer check */ + +#define NW_HTONS(x) ( ( ((x) & 0xff00) >> 8 ) | ( ((x) & 0x00ff) << 8 ) ) + +#define NW_HTONL(x) ( ( ((x) & 0xff000000) >> 24 ) | ( ( (x) & 0x00ff0000 ) >> 8 ) | \ + ( ( (x) & 0x0000ff00 ) << 8 ) | ( ( (x) & 0x000000ff) << 24 ) ) + +#define NW_HTONLL(x) ( \ + ( ( ((NwU64T)x) & 0xff00000000000000ULL ) >> 56 ) | ( ( ((NwU64T)x) & 0x00ff000000000000ULL ) >> 40 ) | \ + ( ( ((NwU64T)x) & 0x0000ff0000000000ULL ) >> 24 ) | ( ( ((NwU64T)x) & 0x000000ff00000000ULL ) >> 8 ) | \ + ( ( ((NwU64T)x) & 0x000000000000ff00ULL ) << 40 ) | ( ( ((NwU64T)x) & 0x00000000000000ffULL ) << 56 ) | \ + ( ( ((NwU64T)x) & 0x0000000000ff0000ULL ) << 24 ) | ( ( ((NwU64T)x) & 0x00000000ff000000ULL ) << 8 ) \ + ) + + +#define NW_NTOHS NW_HTONS +#define NW_NTOHL NW_HTONL +#define NW_NTOHLL NW_HTONLL + + +#endif /* __NW_UTILS_H__ */ + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/Makefile.am b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/Makefile.am new file mode 100644 index 0000000000..0c12bd5984 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/Makefile.am @@ -0,0 +1,46 @@ +# this is example-file: src/mylib/Makefile.am + +# additional include paths necessary to compile the C++ library +AM_CFLAGS = -Wall -I$(top_srcdir)/src -I$(top_srcdir)/shared -I$(top_srcdir)/include @AM_CFLAGS@ + +############################################################################### +# THE LIBRARIES TO BUILD +############################################################################### + +# the library names to build (note we are building static libs only) +lib_LIBRARIES = libNwGtpv2c.a + +# where to install the headers on the system +libNwGtpv2c_adir = $(includedir)/mylib + +# the list of header files that belong to the library (to be installed later) +libNwGtpv2c_a_HEADERS = \ + $(top_srcdir)/shared/NwTypes.h\ + $(top_srcdir)/shared/NwUtils.h\ + $(top_srcdir)/shared/NwError.h\ + $(top_srcdir)/shared/NwLog.h\ + $(top_srcdir)/shared/NwGtpv2c.h\ + $(top_srcdir)/shared/NwGtpv2cMsg.h\ + $(top_srcdir)/shared/NwGtpv2cMsgParser.h\ + $(top_srcdir)/shared/NwGtpv2cIe.h\ + $(top_srcdir)/include/NwGtpv2cPrivate.h\ + $(top_srcdir)/include/NwGtpv2cTrxn.h\ + $(top_srcdir)/include/NwGtpv2cTunnel.h\ + $(top_srcdir)/include/NwGtpv2cMsgIeParseInfo.h\ + $(top_srcdir)/include/NwGtpv2cLog.h\ + $(top_srcdir)/include/queue.h\ + $(top_srcdir)/include/tree.h + +# the sources to add to the library and to add to the source distribution +libNwGtpv2c_a_SOURCES = \ + $(libNwGtpv2_a_HEADERS) \ + NwGtpv2cTrxn.c\ + NwGtpv2cTunnel.c\ + NwGtpv2cMsg.c\ + NwGtpv2cMsgIeParseInfo.c\ + NwGtpv2cMsgParser.c\ + NwGtpv2c.c + +############################################################################### + + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2c.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2c.c new file mode 100644 index 0000000000..e6e4ad2917 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2c.c @@ -0,0 +1,1862 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwError.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cTrxn.h" +#include "NwGtpv2cLog.h" + +#ifdef _NWGTPV2C_HAVE_TIMERADD +#define NW_GTPV2C_TIMER_ADD(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp)) +#define NW_GTPV2C_TIMER_SUB(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp)) +#define NW_GTPV2C_TIMER_CMP_P(a, b, CMP) timercmp(a, b, CMP) +#else + +#define NW_GTPV2C_TIMER_ADD(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \ + if ((vvp)->tv_usec >= 1000000) { \ + (vvp)->tv_sec++; \ + (vvp)->tv_usec -= 1000000; \ + } \ + } while (0) + +#define NW_GTPV2C_TIMER_SUB(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + +#define NW_GTPV2C_TIMER_CMP_P(a, b, CMP) \ + (((a)->tv_sec == (b)->tv_sec) ? \ + ((a)->tv_usec CMP (b)->tv_usec) : \ + ((a)->tv_sec CMP (b)->tv_sec)) + +#endif + + +#define NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(__thiz, __msgType) \ + do { \ + __thiz->pGtpv2cMsgIeParseInfo[__msgType] = \ + nwGtpv2cMsgIeParseInfoNew((NwGtpv2cStackHandleT)__thiz, __msgType);\ + } while(0) + +#define NW_GTPV2C_UDP_PORT (2123) + +#ifdef __cplusplus +extern "C" { +#endif + +static NwGtpv2cTimeoutInfoT* gpGtpv2cTimeoutInfoPool = NULL; + +typedef struct +{ + int currSize; + int maxSize; + NwGtpv2cTimeoutInfoT** pHeap; +} NwGtpv2cTmrMinHeapT; + +#define NW_HEAP_PARENT_INDEX(__child) ( ( (__child) - 1 ) / 2 ) + + +NwGtpv2cTmrMinHeapT* +nwGtpv2cTmrMinHeapNew(int maxSize) +{ + NwGtpv2cTmrMinHeapT* thiz = (NwGtpv2cTmrMinHeapT*) malloc (sizeof(NwGtpv2cTmrMinHeapT)); + if(thiz) + { + thiz->currSize = 0; + thiz->maxSize = maxSize; + thiz->pHeap = (NwGtpv2cTimeoutInfoT**) malloc (maxSize * sizeof(NwGtpv2cTimeoutInfoT*)); + } + return thiz; +} + +void +nwGtpv2cTmrMinHeapDelete(NwGtpv2cTmrMinHeapT* thiz) +{ + free(thiz->pHeap); + free(thiz); +} + +static NwRcT +nwGtpv2cTmrMinHeapInsert(NwGtpv2cTmrMinHeapT* thiz, NwGtpv2cTimeoutInfoT* pTimerEvent) +{ + int holeIndex = thiz->currSize++; + + NW_ASSERT(thiz->currSize < thiz->maxSize); + + while((holeIndex > 0) && + NW_GTPV2C_TIMER_CMP_P(&(thiz->pHeap[NW_HEAP_PARENT_INDEX(holeIndex)])->tvTimeout, &(pTimerEvent->tvTimeout), >)) + { + thiz->pHeap[holeIndex] = thiz->pHeap[NW_HEAP_PARENT_INDEX(holeIndex)]; + thiz->pHeap[holeIndex]->timerMinHeapIndex = holeIndex; + holeIndex = NW_HEAP_PARENT_INDEX(holeIndex); + } + + thiz->pHeap[holeIndex] = pTimerEvent; + pTimerEvent->timerMinHeapIndex = holeIndex; + + return holeIndex; +} + +#define NW_MIN_HEAP_INDEX_INVALID (0xFFFFFFFF) +static NwRcT +nwGtpv2cTmrMinHeapRemove(NwGtpv2cTmrMinHeapT* thiz, int minHeapIndex) +{ + NwGtpv2cTimeoutInfoT* pTimerEvent; + int holeIndex = minHeapIndex; + int minChild, maxChild; + + //printf("- Trying Removing %p from index %u, currSize %u, minChild %u, maxChild %u\n", thiz->pHeap[minHeapIndex], minHeapIndex, thiz->currSize, minChild, maxChild); + if(minHeapIndex == NW_MIN_HEAP_INDEX_INVALID) return NW_FAILURE; + if(minHeapIndex < thiz->currSize) + { + thiz->pHeap[minHeapIndex]->timerMinHeapIndex = NW_MIN_HEAP_INDEX_INVALID; + thiz->currSize--; + + pTimerEvent = thiz->pHeap[thiz->currSize]; + holeIndex = minHeapIndex; + minChild = ( 2 * holeIndex ) + 1; + maxChild = minChild + 1; + + //printf("- Removing %p from index %u, currSize %u, minChild %u, maxChild %u\n", thiz->pHeap[minHeapIndex], minHeapIndex, thiz->currSize, minChild, maxChild); + + while( (maxChild) <= thiz->currSize ) + { + if(NW_GTPV2C_TIMER_CMP_P(&(thiz->pHeap[minChild]->tvTimeout), &(thiz->pHeap[maxChild]->tvTimeout), >)) + minChild = maxChild; + + if(NW_GTPV2C_TIMER_CMP_P(&(pTimerEvent->tvTimeout), &(thiz->pHeap[minChild]->tvTimeout), <)) + { + break; + } + thiz->pHeap[holeIndex] = thiz->pHeap[minChild]; + thiz->pHeap[holeIndex]->timerMinHeapIndex = holeIndex; + holeIndex = minChild; + minChild = ( 2 * holeIndex ) + 1; + maxChild = minChild + 1; + } + while((holeIndex > 0) && + NW_GTPV2C_TIMER_CMP_P(&((thiz->pHeap[NW_HEAP_PARENT_INDEX(holeIndex)])->tvTimeout), &(pTimerEvent->tvTimeout), >)) + { + thiz->pHeap[holeIndex] = thiz->pHeap[NW_HEAP_PARENT_INDEX(holeIndex)]; + thiz->pHeap[holeIndex]->timerMinHeapIndex = holeIndex; + holeIndex = NW_HEAP_PARENT_INDEX(holeIndex); + } + + if(holeIndex < thiz->currSize) + { + thiz->pHeap[holeIndex] = pTimerEvent; + pTimerEvent->timerMinHeapIndex = holeIndex; + } + + thiz->pHeap[thiz->currSize] = NULL; + return NW_OK; + } + return NW_FAILURE; +} + +static NwGtpv2cTimeoutInfoT* +nwGtpv2cTmrMinHeapPeek(NwGtpv2cTmrMinHeapT* thiz) +{ + if(thiz->currSize) + { + //printf("- Peek Returning %p at index %u(%u)\n", thiz->pHeap[0], thiz->pHeap[0]->timerMinHeapIndex, thiz->currSize); + return thiz->pHeap[0]; + } + return NULL; +} +/*--------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +static void +nwGtpv2cDisplayBanner( NwGtpv2cStackT* thiz) +{ +#ifdef NW_GTPV2C_DISPLAY_LICENCE_INFO + printf(" *----------------------------------------------------------------------------*\n"); + printf(" * *\n"); + printf(" * n w - g t p v 2 c *\n"); + printf(" * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k *\n"); + printf(" * *\n"); + printf(" * *\n"); + printf(" * Copyright (c) 2010-2011 Amit Chawre *\n"); + printf(" * All rights reserved. *\n"); + printf(" * *\n"); + printf(" * Redistribution and use in source and binary forms, with or without *\n"); + printf(" * modification, are permitted provided that the following conditions *\n"); + printf(" * are met: *\n"); + printf(" * *\n"); + printf(" * 1. Redistributions of source code must retain the above copyright *\n"); + printf(" * notice, this list of conditions and the following disclaimer. *\n"); + printf(" * 2. Redistributions in binary form must reproduce the above copyright *\n"); + printf(" * notice, this list of conditions and the following disclaimer in the *\n"); + printf(" * documentation and/or other materials provided with the distribution. *\n"); + printf(" * 3. The name of the author may not be used to endorse or promote products *\n"); + printf(" * derived from this software without specific prior written permission. *\n"); + printf(" * *\n"); + printf(" * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *\n"); + printf(" * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *\n"); + printf(" * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *\n"); + printf(" * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *\n"); + printf(" * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *\n"); + printf(" * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *\n"); + printf(" * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *\n"); + printf(" * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *\n"); + printf(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *\n"); + printf(" * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *\n"); + printf(" *----------------------------------------------------------------------------*\n\n"); +#endif +} + +/*--------------------------------------------------------------------------- + * Tunnel RBTree Search Data Structure + *--------------------------------------------------------------------------*/ + +/** + Comparator funtion for comparing two sequence number transactions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv2cCompareTunnel(struct NwGtpv2cTunnel * a, struct NwGtpv2cTunnel* b) +{ + if(a->teid > b->teid) + return 1; + if(a->teid < b->teid) + return -1; + if(a->ipv4AddrRemote > b->ipv4AddrRemote) + return 1; + if(a->ipv4AddrRemote < b->ipv4AddrRemote) + return -1; + return 0; +} + +RB_GENERATE(NwGtpv2cTunnelMap, NwGtpv2cTunnel, tunnelMapRbtNode, nwGtpv2cCompareTunnel) + +/*--------------------------------------------------------------------------- + * Transaction RBTree Search Data Structure + *--------------------------------------------------------------------------*/ + +/** + Comparator funtion for comparing two outstancing TX transactions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv2cCompareOutstandingTxSeqNumTrxn(struct NwGtpv2cTrxn* a, struct NwGtpv2cTrxn* b) +{ + if(a->seqNum > b->seqNum) + return 1; + if(a->seqNum < b->seqNum) + return -1; + if(a->peerIp > b->peerIp) + return 1; + if(a->peerIp < b->peerIp) + return -1; + return 0; +} + +RB_GENERATE(NwGtpv2cOutstandingTxSeqNumTrxnMap, NwGtpv2cTrxn, outstandingTxSeqNumMapRbtNode, nwGtpv2cCompareOutstandingTxSeqNumTrxn) + +/** + Comparator funtion for comparing outstanding RX transactions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv2cCompareOutstandingRxSeqNumTrxn(struct NwGtpv2cTrxn* a, struct NwGtpv2cTrxn* b) +{ + if(a->seqNum > b->seqNum) + return 1; + if(a->seqNum < b->seqNum) + return -1; + if(a->peerIp > b->peerIp) + return 1; + if(a->peerIp < b->peerIp) + return -1; + if(a->peerPort > b->peerPort) + return 1; + if(a->peerPort < b->peerPort) + return -1; + return 0; +} + +RB_GENERATE(NwGtpv2cOutstandingRxSeqNumTrxnMap, NwGtpv2cTrxn, outstandingRxSeqNumMapRbtNode, nwGtpv2cCompareOutstandingRxSeqNumTrxn) + +/*--------------------------------------------------------------------------- + * Timer RB-tree data structure. + *--------------------------------------------------------------------------*/ + +/** + Comparator funtion for comparing two outstancing TX transactions. + + @param[in] a: Pointer to session a. + @param[in] b: Pointer to session b. + @return An integer greater than, equal to or less than zero according to whether the + object pointed to by a is greater than, equal to or less than the object pointed to by b. + */ + +static inline NwS32T +nwGtpv2cCompareOutstandingTxRexmitTime(struct NwGtpv2cTimeoutInfo* a, struct NwGtpv2cTimeoutInfo* b) +{ + if(NW_GTPV2C_TIMER_CMP_P(&a->tvTimeout, &b->tvTimeout, >)) + return 1; + if(NW_GTPV2C_TIMER_CMP_P(&a->tvTimeout, &b->tvTimeout, <)) + return -1; + return 0; +} + +RB_GENERATE(NwGtpv2cActiveTimerList, NwGtpv2cTimeoutInfo, activeTimerListRbtNode, nwGtpv2cCompareOutstandingTxRexmitTime) + + + +/** + * Send msg to peer via data request to UDP Entity + * + * @param[in] thiz : Pointer to stack. + * @param[in] peerIp : Peer Ip address. + * @param[in] peerPort : Peer Ip port. + * @param[in] pMsg : Message to be sent. + * @return NW_OK on success. + */ +static NwRcT +nwGtpv2cCreateAndSendMsg(NW_IN NwGtpv2cStackT* thiz, + NW_IN NwU32T seqNum, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwGtpv2cMsgT *pMsg) +{ + NwRcT rc; + NwU8T* msgHdr; + + NW_ASSERT(thiz); + NW_ASSERT(pMsg); + + msgHdr = pMsg->msgBuf; + + /* Set flags in header */ + *(msgHdr++) = (pMsg->version << 5) | (pMsg->teidPresent << 3); + + /* Set msg type in header */ + *(msgHdr++) = (pMsg->msgType); + + /* Set msg length in header*/ + *((NwU16T*) msgHdr) = htons(pMsg->msgLen - 4 ); + msgHdr += 2; + + /* Set TEID, if present in header */ + if(pMsg->teidPresent) + { + *((NwU32T*) msgHdr) = htonl(pMsg->teid); + msgHdr += 4; + } + + /* Set seq num in header */ + *((NwU32T*) msgHdr) = htonl(seqNum << 8); + + /* Call UDP data request callback */ + NW_ASSERT(thiz->udp.udpDataReqCallback != NULL); + rc = thiz->udp.udpDataReqCallback(thiz->udp.hUdp, + pMsg->msgBuf, + pMsg->msgLen, + peerIp, + peerPort); + NW_ASSERT(NW_OK == rc); + + return rc; +} + +/** + Send an Version Not Supported message + + @param[in] thiz : Stack pointer + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cSendVersionNotSupportedInd( NW_IN NwGtpv2cStackT* thiz, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwU32T seqNum) +{ + NwRcT rc; + NwGtpv2cMsgHandleT hMsg = 0; + + rc = nwGtpv2cMsgNew( (NwGtpv2cStackHandleT)thiz, + NW_FALSE, + NW_GTP_VERSION_NOT_SUPPORTED_IND, + 0x00, + seqNum, + (&hMsg)); + + NW_ASSERT(NW_OK == rc); + + NW_LOG(thiz, NW_LOG_LEVEL_NOTI, "Sending Version Not Supported Indication message to %x:%x with seq %u", peerIp, peerPort, seqNum); + + rc = nwGtpv2cCreateAndSendMsg(thiz, + seqNum, + peerIp, + peerPort, + (NwGtpv2cMsgT*) hMsg); + + rc = nwGtpv2cMsgDelete((NwGtpv2cStackHandleT)thiz, hMsg); + NW_ASSERT(NW_OK == rc); + + return rc; +} + +/** + Create a local tunnel. + + @param[in] thiz : Stack pointer + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cCreateLocalTunnel( NW_IN NwGtpv2cStackT* thiz, + NW_IN NwU32T teid, + NW_IN NwU32T ipv4Remote, + NW_IN NwGtpv2cUlpTunnelHandleT hUlpTunnel, + NW_OUT NwGtpv2cTunnelHandleT *phTunnel) +{ + NwRcT rc; + NwGtpv2cTunnelT *pTunnel, *pCollision; + + NW_ENTER(thiz); + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Creating local tunnel with teid '0x%x' and peer IP 0x%x", teid, ipv4Remote); + + pTunnel = nwGtpv2cTunnelNew(thiz, teid, ipv4Remote, hUlpTunnel); + + if(pTunnel) + { + pCollision = RB_INSERT(NwGtpv2cTunnelMap, &(thiz->tunnelMap), pTunnel); + + if(pCollision) + { + rc = nwGtpv2cTunnelDelete(thiz, pTunnel); + NW_ASSERT(NW_OK == rc); + + *phTunnel = (NwGtpv2cTunnelHandleT) 0; + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Local tunnel creation failed for teid '0x%x' and peer IP "NW_IPV4_ADDR". Tunnel already exists!", teid, NW_IPV4_ADDR_FORMAT(ipv4Remote)); + + NW_ASSERT(0); + NW_LEAVE(thiz); + return NW_OK; + } + } + else + { + rc = NW_FAILURE; + } + + *phTunnel = (NwGtpv2cTunnelHandleT) pTunnel; + NW_LEAVE(thiz); + return NW_OK; +} + +/** + Delete a local tunnel. + + @param[in] thiz : Stack pointer + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cDeleteLocalTunnel( NW_IN NwGtpv2cStackT* thiz, + NW_OUT NwGtpv2cTunnelHandleT hTunnel) +{ + NwRcT rc; + NwGtpv2cTunnelT *pTunnel = (NwGtpv2cTunnelT*) hTunnel ; + + NW_ENTER(thiz); + + pTunnel = RB_REMOVE(NwGtpv2cTunnelMap, &(thiz->tunnelMap), (NwGtpv2cTunnelT*)hTunnel); + NW_ASSERT(pTunnel == (NwGtpv2cTunnelT*)hTunnel); + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Deleting local tunnel with teid '0x%x' and peer IP 0x%x", pTunnel->teid, pTunnel->ipv4AddrRemote); + + rc = nwGtpv2cTunnelDelete(thiz, pTunnel); + NW_ASSERT(NW_OK == rc); + + NW_LEAVE(thiz); + return NW_OK; +} + +/*--------------------------------------------------------------------------- + * ULP API Processing Functions + *--------------------------------------------------------------------------*/ + +/** + Process NW_GTPV2C_ULP_API_INITIAL_REQ Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleUlpInitialReq( NW_IN NwGtpv2cStackT* thiz, NW_IN NwGtpv2cUlpApiT *pUlpReq) +{ + NwRcT rc; + NwGtpv2cTrxnT *pTrxn; + + NW_ENTER(thiz); + + /* Create New Transaction */ + pTrxn = nwGtpv2cTrxnNew(thiz); + + if(pTrxn) + { + if(!pUlpReq->apiInfo.initialReqInfo.hTunnel) + { + rc = nwGtpv2cCreateLocalTunnel(thiz, + pUlpReq->apiInfo.initialReqInfo.teidLocal, + pUlpReq->apiInfo.initialReqInfo.peerIp, + pUlpReq->apiInfo.initialReqInfo.hUlpTunnel, + &pUlpReq->apiInfo.initialReqInfo.hTunnel); + NW_ASSERT(NW_OK == rc); + } + + pTrxn->pMsg = (NwGtpv2cMsgT*) pUlpReq->hMsg; + pTrxn->hTunnel = pUlpReq->apiInfo.initialReqInfo.hTunnel; + pTrxn->hUlpTrxn = pUlpReq->apiInfo.initialReqInfo.hUlpTrxn; + pTrxn->peerIp = ((NwGtpv2cTunnelT*)(pTrxn->hTunnel))->ipv4AddrRemote; + pTrxn->peerPort = NW_GTPV2C_UDP_PORT; + + if(pUlpReq->apiType & NW_GTPV2C_ULP_API_FLAG_IS_COMMAND_MESSAGE) + { + pTrxn->seqNum |= 0x00100000UL; + } + + rc = nwGtpv2cCreateAndSendMsg(thiz, + pTrxn->seqNum, + pTrxn->peerIp, + pTrxn->peerPort, + pTrxn->pMsg); + + if(NW_OK == rc) + { + /* Start guard timer */ + rc = nwGtpv2cTrxnStartPeerRspWaitTimer(pTrxn); + NW_ASSERT(NW_OK == rc); + + /* Insert into search tree */ + pTrxn = RB_INSERT(NwGtpv2cOutstandingTxSeqNumTrxnMap, &(thiz->outstandingTxSeqNumMap), pTrxn); + NW_ASSERT(pTrxn == NULL); + } + else + { + rc = nwGtpv2cTrxnDelete(&pTrxn); + NW_ASSERT(NW_OK == rc); + } + } + else + { + rc = NW_FAILURE; + } + + NW_LEAVE(thiz); + + return rc; +} + +/** + Process NW_GTPV2C_ULP_API_TRIGGERED_REQ Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleUlpTriggeredReq( NW_IN NwGtpv2cStackT* thiz, NW_IN NwGtpv2cUlpApiT *pUlpReq) +{ + NwRcT rc; + NwGtpv2cTrxnT *pTrxn; + NwGtpv2cTrxnT *pReqTrxn; + + NW_ENTER(thiz); + + /* Create New Transaction */ + pTrxn = nwGtpv2cTrxnWithSeqNumNew(thiz, (((NwGtpv2cMsgT*)(pUlpReq->hMsg))->seqNum)); + + if(pTrxn) + { + pReqTrxn = (NwGtpv2cTrxnT*) pUlpReq->apiInfo.triggeredReqInfo.hTrxn; + + pTrxn->hUlpTrxn = pUlpReq->apiInfo.triggeredReqInfo.hUlpTrxn; + pTrxn->peerIp = pReqTrxn->peerIp; + pTrxn->peerPort = pReqTrxn->peerPort; + pTrxn->pMsg = (NwGtpv2cMsgT*) pUlpReq->hMsg; + + rc = nwGtpv2cCreateAndSendMsg(thiz, + pTrxn->seqNum, + pTrxn->peerIp, + pTrxn->peerPort, + pTrxn->pMsg); + + if(NW_OK == rc) + { + /* Start guard timer */ + rc = nwGtpv2cTrxnStartPeerRspWaitTimer(pTrxn); + NW_ASSERT(NW_OK == rc); + + /* Insert into search tree */ + RB_INSERT(NwGtpv2cOutstandingTxSeqNumTrxnMap, &(thiz->outstandingTxSeqNumMap), pTrxn); + + if(!pUlpReq->apiInfo.triggeredReqInfo.hTunnel) + { + rc = nwGtpv2cCreateLocalTunnel(thiz, + pUlpReq->apiInfo.triggeredReqInfo.teidLocal, + pReqTrxn->peerIp, + pUlpReq->apiInfo.triggeredReqInfo.hUlpTunnel, + &pUlpReq->apiInfo.triggeredReqInfo.hTunnel); + } + } + else + { + rc = nwGtpv2cTrxnDelete(&pTrxn); + NW_ASSERT(NW_OK == rc); + } + } + else + { + rc = NW_FAILURE; + } + + NW_LEAVE(thiz); + + return rc; +} + +/** + Process NW_GTPV2C_ULP_API_TRIGGERED_RSP Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleUlpTriggeredRsp( NW_IN NwGtpv2cStackT* thiz, NW_IN NwGtpv2cUlpApiT *pUlpRsp) +{ + NwRcT rc; + NwGtpv2cTrxnT *pReqTrxn; + + NW_ENTER(thiz); + + pReqTrxn = (NwGtpv2cTrxnT*) pUlpRsp->apiInfo.triggeredRspInfo.hTrxn; + NW_ASSERT(pReqTrxn != NULL); + + if(((NwGtpv2cMsgT*) pUlpRsp->hMsg)->seqNum == 0) + ((NwGtpv2cMsgT*) pUlpRsp->hMsg)->seqNum = pReqTrxn->seqNum; + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Sending response message over seq '0x%x'", pReqTrxn->seqNum); + + rc = nwGtpv2cCreateAndSendMsg(thiz, + pReqTrxn->seqNum, + pReqTrxn->peerIp, + pReqTrxn->peerPort, + (NwGtpv2cMsgT*) pUlpRsp->hMsg); + + pReqTrxn->pMsg = (NwGtpv2cMsgT*) pUlpRsp->hMsg; + + rc = nwGtpv2cTrxnStartDulpicateRequestWaitTimer(pReqTrxn); + + if((pUlpRsp->apiType & 0xFF000000) == NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL) + { + rc = nwGtpv2cCreateLocalTunnel(thiz, + pUlpRsp->apiInfo.triggeredRspInfo.teidLocal, + pReqTrxn->peerIp, + pUlpRsp->apiInfo.triggeredRspInfo.hUlpTunnel, + &pUlpRsp->apiInfo.triggeredRspInfo.hTunnel); + } + + return rc; +} + +/** + Process NW_GTPV2C_ULP_CREATE_LOCAL_TUNNEL Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleUlpCreateLocalTunnel( NW_IN NwGtpv2cStackT* thiz, NW_IN NwGtpv2cUlpApiT *pUlpReq) +{ + NwRcT rc; + NwGtpv2cTunnelT *pTunnel, *pCollision; + + NW_ENTER(thiz); + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Creating local tunnel with teid '0x%x' and peer IP 0x%x", pUlpReq->apiInfo.createLocalTunnelInfo.teidLocal, pUlpReq->apiInfo.createLocalTunnelInfo.peerIp); + + pTunnel = nwGtpv2cTunnelNew(thiz, pUlpReq->apiInfo.createLocalTunnelInfo.teidLocal, + pUlpReq->apiInfo.createLocalTunnelInfo.peerIp, + pUlpReq->apiInfo.triggeredRspInfo.hUlpTunnel); + NW_ASSERT(pTunnel); + + pCollision = RB_INSERT(NwGtpv2cTunnelMap, &(thiz->tunnelMap), pTunnel); + + if(pCollision) + { + rc = nwGtpv2cTunnelDelete(thiz, pTunnel); + NW_ASSERT(NW_OK == rc); + + pUlpReq->apiInfo.createLocalTunnelInfo.hTunnel = (NwGtpv2cTunnelHandleT) 0; + NW_LEAVE(thiz); + return NW_FAILURE; + } + + pUlpReq->apiInfo.createLocalTunnelInfo.hTunnel = (NwGtpv2cTunnelHandleT) pTunnel; + NW_LEAVE(thiz); + return NW_OK; +} + +/** + Process NW_GTPV2C_ULP_DELETE_LOCAL_TUNNEL Request from ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @param[in] pUlpReq : Pointer to Ulp Req. + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleUlpDeleteLocalTunnel( NW_IN NwGtpv2cStackT* thiz, NW_IN NwGtpv2cUlpApiT *pUlpReq) +{ + NwRcT rc; + + NW_ENTER(thiz); + + rc = nwGtpv2cDeleteLocalTunnel(thiz, pUlpReq->apiInfo.deleteLocalTunnelInfo.hTunnel); + + NW_LEAVE(thiz); + return rc; +} + +/** + Send GTPv2c Initial Request Message Indication to ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cSendInitialReqIndToUlp( NW_IN NwGtpv2cStackT *thiz, + NW_IN NwGtpv2cErrorT *pError, + NW_IN NwGtpv2cTrxnT *pTrxn, + NW_IN NwU32T hUlpTunnel, + NW_IN NwU32T msgType, + NW_IN NwU32T peerIp, + NW_IN NwU16T peerPort, + NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulpApi; + + NW_ENTER(thiz); + + ulpApi.hMsg = hMsg; + ulpApi.apiType = NW_GTPV2C_ULP_API_INITIAL_REQ_IND; + ulpApi.apiInfo.initialReqIndInfo.msgType = msgType; + ulpApi.apiInfo.initialReqIndInfo.hTrxn = (NwGtpv2cTrxnHandleT) pTrxn; + ulpApi.apiInfo.initialReqIndInfo.hUlpTunnel = hUlpTunnel; + ulpApi.apiInfo.initialReqIndInfo.peerIp = peerIp; + ulpApi.apiInfo.initialReqIndInfo.peerPort = peerPort; + + ulpApi.apiInfo.triggeredRspIndInfo.error = *pError; + + rc = thiz->ulp.ulpReqCallback(thiz->ulp.hUlp, &ulpApi); + + NW_LEAVE(thiz); + + return rc; +} + +/** + Send GTPv2c Triggered Response Indication to ULP entity. + + @param[in] hGtpcStackHandle : Stack handle + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cSendTriggeredRspIndToUlp( NW_IN NwGtpv2cStackT* thiz, + NW_IN NwGtpv2cErrorT *pError, + NW_IN NwU32T hUlpTrxn, + NW_IN NwU32T hUlpTunnel, + NW_IN NwU32T msgType, + NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulpApi; + + NW_ENTER(thiz); + + ulpApi.hMsg = hMsg; + ulpApi.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND; + ulpApi.apiInfo.triggeredRspIndInfo.msgType = msgType; + ulpApi.apiInfo.triggeredRspIndInfo.hUlpTrxn = hUlpTrxn; + ulpApi.apiInfo.triggeredRspIndInfo.hUlpTunnel = hUlpTunnel; + + ulpApi.apiInfo.triggeredRspIndInfo.error = *pError; + + rc = thiz->ulp.ulpReqCallback(thiz->ulp.hUlp, &ulpApi); + + NW_LEAVE(thiz); + + return rc; +} + +/** + Handle Echo Request from Peer Entity. + + @param[in] thiz : Stack context + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleEchoReq(NW_IN NwGtpv2cStackT *thiz, + NW_IN NwU32T msgType, + NW_IN NwU8T* msgBuf, + NW_IN NwU32T msgBufLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwRcT rc; + NwU32T seqNum = 0; + NwGtpv2cMsgHandleT hMsg = 0; + + seqNum = ntohl(*((NwU32T*)(msgBuf + (((*msgBuf) & 0x08) ? 8 : 4)))) >> 8; + + /* Send Echo Response */ + + rc = nwGtpv2cMsgNew( (NwGtpv2cStackHandleT)thiz, + NW_FALSE, /* TEID present flag */ + NW_GTP_ECHO_RSP, /* Msg Type */ + 0x00, /* TEID */ + seqNum, /* Seq Number */ + (&hMsg)); + + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgAddIeTV1(hMsg, NW_GTPV2C_IE_RECOVERY, 0, thiz->restartCounter); + + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, "Sending NW_GTP_ECHO_RSP message to "NW_IPV4_ADDR":%u with seq %u", NW_IPV4_ADDR_FORMAT(peerIp), peerPort, (seqNum)); + + rc = nwGtpv2cCreateAndSendMsg(thiz, + (seqNum), + peerIp, + peerPort, + (NwGtpv2cMsgT*) hMsg); + + rc = nwGtpv2cMsgDelete((NwGtpv2cStackHandleT)thiz, hMsg); + NW_ASSERT(NW_OK == rc); + + return rc; +} + +/** + Handle Initial Request from Peer Entity. + + @param[in] thiz : Stack context + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleInitialReq(NW_IN NwGtpv2cStackT *thiz, + NW_IN NwU32T msgType, + NW_IN NwU8T* msgBuf, + NW_IN NwU32T msgBufLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwRcT rc; + NwU32T seqNum = 0; + NwU32T teidLocal = 0; + NwGtpv2cTrxnT *pTrxn; + NwGtpv2cTunnelT *pLocalTunnel, keyTunnel; + NwGtpv2cMsgHandleT hMsg = 0; + NwGtpv2cUlpTunnelHandleT hUlpTunnel; + NwGtpv2cErrorT error; + + teidLocal = *((NwU32T*)(msgBuf + 4)); + + if(teidLocal) + { + keyTunnel.teid = ntohl(teidLocal); + keyTunnel.ipv4AddrRemote = peerIp; + pLocalTunnel = RB_FIND(NwGtpv2cTunnelMap, &(thiz->tunnelMap), &keyTunnel); + + if(!pLocalTunnel) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Request message received on non-existent teid 0x%x from peer 0x%x received! Discarding.", ntohl(teidLocal), htonl(peerIp)); + return NW_OK; + } + hUlpTunnel = pLocalTunnel->hUlpTunnel; + } + else + { + hUlpTunnel = 0; + } + + seqNum = ntohl(*((NwU32T*)(msgBuf + (((*msgBuf) & 0x08) ? 8 : 4)))) >> 8; + pTrxn = nwGtpv2cTrxnOutstandingRxNew(thiz, ntohl(teidLocal), peerIp, peerPort, (seqNum)); + + if(pTrxn) + { + + rc = nwGtpv2cMsgFromBufferNew((NwGtpv2cStackHandleT)thiz, msgBuf, msgBufLen, &(hMsg)); + + NW_ASSERT(thiz->pGtpv2cMsgIeParseInfo[msgType]); + + rc = nwGtpv2cMsgIeParse(thiz->pGtpv2cMsgIeParseInfo[msgType], hMsg, &error); + if(rc != NW_OK) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Malformed request message received on TEID %u from peer 0x%x. Notifying ULP.", ntohl(teidLocal), htonl(peerIp)); + } + + rc = nwGtpv2cSendInitialReqIndToUlp( thiz, + &error, + pTrxn, + hUlpTunnel, + msgType, + peerIp, + peerPort, + hMsg); + } + + return NW_OK; +} + +/** + Handle Triggered Response from Peer Entity. + + @param[in] thiz : Stack context + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cHandleTriggeredRsp(NW_IN NwGtpv2cStackT *thiz, + NW_IN NwU32T msgType, + NW_IN NwU8T* msgBuf, + NW_IN NwU32T msgBufLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwRcT rc; + NwGtpv2cTrxnT *pTrxn, keyTrxn; + NwGtpv2cMsgHandleT hMsg = 0; + NwGtpv2cErrorT error; + + keyTrxn.seqNum = ntohl(*((NwU32T*)(msgBuf + (((*msgBuf) & 0x08) ? 8 : 4)))) >> 8;; + keyTrxn.peerIp = peerIp; + + pTrxn = RB_FIND(NwGtpv2cOutstandingTxSeqNumTrxnMap, &(thiz->outstandingTxSeqNumMap), &keyTrxn); + + if(pTrxn) + { + NwU32T hUlpTrxn; + NwU32T hUlpTunnel; + + hUlpTrxn = pTrxn->hUlpTrxn; + hUlpTunnel = (pTrxn->hTunnel ? ((NwGtpv2cTunnelT*)(pTrxn->hTunnel))->hUlpTunnel : 0); + + RB_REMOVE(NwGtpv2cOutstandingTxSeqNumTrxnMap, &(thiz->outstandingTxSeqNumMap), pTrxn); + rc = nwGtpv2cTrxnDelete(&pTrxn); + NW_ASSERT(NW_OK == rc); + + NW_ASSERT(msgBuf && msgBufLen); + rc = nwGtpv2cMsgFromBufferNew((NwGtpv2cStackHandleT)thiz, msgBuf, msgBufLen, &(hMsg)); + + NW_ASSERT(thiz->pGtpv2cMsgIeParseInfo[msgType]); + rc = nwGtpv2cMsgIeParse(thiz->pGtpv2cMsgIeParseInfo[msgType], hMsg, &error); + if(rc != NW_OK) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Malformed message received on TEID %u from peer 0x%x. Notifying ULP.", ntohl((*((NwU32T*)(msgBuf + 4)))), htonl(peerIp)); + } + + rc = nwGtpv2cSendTriggeredRspIndToUlp( thiz, + &error, + hUlpTrxn, + hUlpTunnel, + msgType, + hMsg); + } + else + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Response message without a matching outstanding request received! Discarding."); + rc = NW_OK; + } + + return rc; +} + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/** + * Constructor + */ + +NwRcT +nwGtpv2cInitialize( NW_INOUT NwGtpv2cStackHandleT* hGtpcStackHandle) +{ + NwRcT rc = NW_OK; + NwGtpv2cStackT* thiz; + + thiz = (NwGtpv2cStackT*) malloc( sizeof(NwGtpv2cStackT)); + + memset(thiz, 0, sizeof(NwGtpv2cStackT)); + + if(thiz) + { + thiz->id = (NwU32T) thiz; + thiz->seqNum = ((NwU32T) thiz) & 0x0000FFFF; + + RB_INIT(&(thiz->tunnelMap)); + RB_INIT(&(thiz->outstandingTxSeqNumMap)); + RB_INIT(&(thiz->outstandingRxSeqNumMap)); + RB_INIT(&(thiz->activeTimerList)); + + thiz->hTmrMinHeap = (NwHandleT) nwGtpv2cTmrMinHeapNew(10000); + + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_ECHO_RSP); + + /* For S11 interface */ + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_CREATE_SESSION_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_CREATE_SESSION_RSP); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_DELETE_SESSION_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_DELETE_SESSION_RSP); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_MODIFY_BEARER_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_MODIFY_BEARER_RSP); + + /* For S10 interface */ + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_FORWARD_RELOCATION_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_FORWARD_RELOCATION_RSP); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_FORWARD_RELOCATION_COMPLETE_NTF); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_FORWARD_RELOCATION_COMPLETE_ACK); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_CONTEXT_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_CONTEXT_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_CONTEXT_ACK); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_IDENTIFICATION_REQ); + NW_GTPV2C_INIT_MSG_IE_PARSE_INFO(thiz, NW_GTP_IDENTIFICATION_RSP); + + nwGtpv2cDisplayBanner(thiz); + } + else + { + rc = NW_FAILURE; + } + + *hGtpcStackHandle = (NwGtpv2cStackHandleT) thiz; + return rc; +} + + +/** + * Destructor + */ + +NwRcT +nwGtpv2cFinalize( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle) +{ + if(!hGtpcStackHandle) + return NW_FAILURE; + + free((void*)hGtpcStackHandle); + return NW_OK; +} + + +/** + * Set ULP entity + */ + +NwRcT +nwGtpv2cSetUlpEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUlpEntityT* pUlpEntity) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + if(!pUlpEntity) + return NW_FAILURE; + + thiz->ulp = *(pUlpEntity); + return NW_OK; +} + +/** + * Set UDP entity + */ + +NwRcT +nwGtpv2cSetUdpEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUdpEntityT* pUdpEntity) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + if(!pUdpEntity) + return NW_FAILURE; + + thiz->udp = *(pUdpEntity); + return NW_OK; +} + +/** + * Set MEM MGR entity + */ + +NwRcT +nwGtpv2cSetMemMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMemMgrEntityT* pMemMgrEntity) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + if(!pMemMgrEntity) + return NW_FAILURE; + + thiz->memMgr = *(pMemMgrEntity); + return NW_OK; +} + +/** + * Set TMR MGR entity + */ + +NwRcT +nwGtpv2cSetTimerMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cTimerMgrEntityT* pTmrMgrEntity) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + if(!pTmrMgrEntity) + return NW_FAILURE; + + thiz->tmrMgr = *(pTmrMgrEntity); + return NW_OK; +} + + +/** + * Set LOG MGR entity + */ + +NwRcT +nwGtpv2cSetLogMgrEntity( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cLogMgrEntityT* pLogMgrEntity) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + if(!pLogMgrEntity) + return NW_FAILURE; + + thiz->logMgr = *(pLogMgrEntity); + return NW_OK; +} + +/** + Set log level for the stack. + */ + +NwRcT +nwGtpv2cSetLogLevel( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU32T logLevel) +{ + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + thiz->logLevel = logLevel; + return NW_OK; +} + +/** + * Process Request from Udp Layer + */ + +NwRcT +nwGtpv2cProcessUdpReq( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T* udpData, + NW_IN NwU32T udpDataLen, + NW_IN NwU16T peerPort, + NW_IN NwU32T peerIp) +{ + NwRcT rc; + NwGtpv2cStackT* thiz; + NwU16T msgType; + + thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + NW_ASSERT(thiz); + + NW_ENTER(thiz); + + if(udpDataLen < NW_GTPV2C_MINIMUM_HEADER_SIZE) + { + /* + * TS 29.274 Section 7.7.3: + * If a GTP entity receives a message, which is too short to + * contain the respective GTPv2 header, the GTP-PDU shall be + * silently discarded + */ + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received message too small! Discarding."); + return NW_OK; + } + + if( (ntohs(*((NwU16T*)((NwU8T*)udpData + 2))) /* Length */ + + ((*((NwU8T*)(udpData)) & 0x08) ? 4 : 0) /* Extra Header length if TEID present */) > udpDataLen) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received message with errneous length of %u against expected length of %u! Discarding", udpDataLen, ntohs(*((NwU16T*)((NwU8T*)udpData + 2))) + ((*((NwU8T*)(udpData)) & 0x08) ? 4 : 0)); + return NW_OK; + } + + if(((*((NwU8T*)(udpData)) & 0xE0) >> 5) != NW_GTP_VERSION) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received unsupported GTP version '%u' message! Discarding.", ((*((NwU8T*)(udpData)) & 0xE0) >> 5)); + /* Send Version Not Supported Message to peer */ + rc = nwGtpv2cSendVersionNotSupportedInd( + thiz, + peerIp, + peerPort, + *((NwU32T*)(udpData + ((*((NwU8T*)(udpData)) & 0x08) ? 8 : 4))) /* Seq Num */); + + return NW_OK; + } + + msgType = *((NwU8T*)(udpData + 1)); + + switch(msgType) + { + case NW_GTP_ECHO_REQ: + { + rc = nwGtpv2cHandleEchoReq(thiz, msgType, udpData, udpDataLen, peerPort, peerIp); + } + break; + case NW_GTP_CREATE_SESSION_REQ: + case NW_GTP_MODIFY_BEARER_REQ: + case NW_GTP_DELETE_SESSION_REQ: + case NW_GTP_CREATE_BEARER_REQ: + case NW_GTP_UPDATE_BEARER_REQ: + case NW_GTP_DELETE_BEARER_REQ: + { + rc = nwGtpv2cHandleInitialReq(thiz, msgType, udpData, udpDataLen, peerPort, peerIp); + } + break; + + case NW_GTP_ECHO_RSP: + case NW_GTP_CREATE_SESSION_RSP: + case NW_GTP_MODIFY_BEARER_RSP: + case NW_GTP_DELETE_SESSION_RSP: + case NW_GTP_CREATE_BEARER_RSP: + case NW_GTP_UPDATE_BEARER_RSP: + case NW_GTP_DELETE_BEARER_RSP: + { + rc = nwGtpv2cHandleTriggeredRsp(thiz, msgType, udpData, udpDataLen, peerPort, peerIp); + } + break; + default: + { + /* + * TS 29.274 Section 7.7.4: + * If a GTP entity receives a message with an unknown Message Type + * value, it shall silently discard the message. + */ + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received unknown message type %u from UDP! Ignoring.", msgType); + rc = NW_OK; + } + } + + NW_LEAVE(thiz); + return rc; +} + + +/* + * Process Request from Upper Layer + */ + +NwRcT +nwGtpv2cProcessUlpReq( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cUlpApiT *pUlpReq) +{ + NwRcT rc; + NwGtpv2cStackT* thiz = (NwGtpv2cStackT*) hGtpcStackHandle; + + NW_ASSERT(thiz); + NW_ASSERT(pUlpReq != NULL); + + NW_ENTER(thiz); + + switch(pUlpReq->apiType & 0x00FFFFFFL) + { + case NW_GTPV2C_ULP_API_INITIAL_REQ: + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received initial request from ulp"); + rc = nwGtpv2cHandleUlpInitialReq(thiz, pUlpReq); + } + break; + + case NW_GTPV2C_ULP_API_TRIGGERED_REQ: + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received triggered request from ulp"); + rc = nwGtpv2cHandleUlpTriggeredReq(thiz, pUlpReq); + } + break; + + case NW_GTPV2C_ULP_API_TRIGGERED_RSP: + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received triggered response from ulp"); + rc = nwGtpv2cHandleUlpTriggeredRsp(thiz, pUlpReq); + } + break; + + case NW_GTPV2C_ULP_CREATE_LOCAL_TUNNEL: + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received create local tunnel from ulp"); + rc = nwGtpv2cHandleUlpCreateLocalTunnel(thiz, pUlpReq); + } + break; + + case NW_GTPV2C_ULP_DELETE_LOCAL_TUNNEL: + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Received delete local tunnel from ulp"); + rc = nwGtpv2cHandleUlpDeleteLocalTunnel(thiz, pUlpReq); + } + break; + + default: + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received unhandled API 0x%x from ULP! Ignoring.", pUlpReq->apiType); + rc = NW_FAILURE; + } + break; + } + + NW_LEAVE(thiz); + + return rc; +} + +/** + * Process Timer timeout Request from Timer ULP Manager + */ + +NwRcT +nwGtpv2cProcessTimeoutOld(void* arg) +{ + NwRcT rc; + NwGtpv2cStackT* thiz; + NwGtpv2cTimeoutInfoT* timeoutInfo = (NwGtpv2cTimeoutInfoT*) arg; + NwGtpv2cTimeoutInfoT* pNextTimeoutInfo; + struct timeval tv; + + NW_ASSERT(timeoutInfo != NULL); + thiz = (NwGtpv2cStackT*) (((NwGtpv2cTimeoutInfoT*) timeoutInfo)->hStack); + + NW_ASSERT(thiz != NULL); + + NW_ENTER(thiz); + + if(thiz->activeTimerInfo == timeoutInfo) + { + thiz->activeTimerInfo = NULL; + RB_REMOVE(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + rc = ((timeoutInfo)->timeoutCallbackFunc) (timeoutInfo->timeoutArg); + + } + else + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, + "Received timeout event from ULP for non-existent timeoutInfo 0x%p and activeTimer 0x%p!", + timeoutInfo, thiz->activeTimerInfo); + return NW_OK; + } + + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + + for ((timeoutInfo) = RB_MIN(NwGtpv2cActiveTimerList, &(thiz->activeTimerList)); + (timeoutInfo) != NULL; ) + + { + if(NW_GTPV2C_TIMER_CMP_P(&timeoutInfo->tvTimeout, &tv, >)) + break; + + pNextTimeoutInfo = RB_NEXT(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + RB_REMOVE(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + rc = ((timeoutInfo)->timeoutCallbackFunc) (timeoutInfo->timeoutArg); + + timeoutInfo = pNextTimeoutInfo; + } + + /* activeTimerInfo may be reset by the timeoutCallbackFunc call above */ + if(thiz->activeTimerInfo == NULL) + { + timeoutInfo = RB_MIN(NwGtpv2cActiveTimerList, &(thiz->activeTimerList)); + if(timeoutInfo) + { + NW_GTPV2C_TIMER_SUB(&timeoutInfo->tvTimeout, &tv, &tv); + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, tv.tv_sec, tv.tv_usec, timeoutInfo->tmrType, (void*)timeoutInfo, &timeoutInfo->hTimer); + NW_ASSERT(NW_OK == rc); + + thiz->activeTimerInfo = timeoutInfo; + } + } + + NW_LEAVE(thiz); + + return rc; +} + +NwRcT +nwGtpv2cProcessTimeout(void* arg) +{ + NwRcT rc; + NwGtpv2cStackT* thiz; + NwGtpv2cTimeoutInfoT* timeoutInfo = (NwGtpv2cTimeoutInfoT*) arg; + struct timeval tv; + + NW_ASSERT(timeoutInfo != NULL); + + thiz = (NwGtpv2cStackT*) (timeoutInfo->hStack); + + NW_ASSERT(thiz != NULL); + NW_ENTER(thiz); + + if(thiz->activeTimerInfo == timeoutInfo) + { + thiz->activeTimerInfo = NULL; + rc = nwGtpv2cTmrMinHeapRemove(thiz->hTmrMinHeap, timeoutInfo->timerMinHeapIndex); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + rc = ((timeoutInfo)->timeoutCallbackFunc) (timeoutInfo->timeoutArg); + } + else + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Received timeout event from ULP for " + "non-existent timeoutInfo 0x%p and activeTimer 0x%p!", + timeoutInfo, thiz->activeTimerInfo); + + NW_LEAVE(thiz); + + return NW_OK; + } + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + + //printf("------ Start -------\n"); + timeoutInfo = nwGtpv2cTmrMinHeapPeek(thiz->hTmrMinHeap); + while((timeoutInfo) != NULL) + { + if(NW_GTPV2C_TIMER_CMP_P(&timeoutInfo->tvTimeout, &tv, >)) + break; + + rc = nwGtpv2cTmrMinHeapRemove(thiz->hTmrMinHeap, timeoutInfo->timerMinHeapIndex); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + rc = ((timeoutInfo)->timeoutCallbackFunc) (timeoutInfo->timeoutArg); + + timeoutInfo = nwGtpv2cTmrMinHeapPeek(thiz->hTmrMinHeap); + //printf("-- %p --\n", timeoutInfo); + } + //printf("------ End -------\n"); + + /* activeTimerInfo may be reset by the timeoutCallbackFunc call above */ + if(thiz->activeTimerInfo == NULL) + { + timeoutInfo = nwGtpv2cTmrMinHeapPeek(thiz->hTmrMinHeap); + if(timeoutInfo) + { + NW_GTPV2C_TIMER_SUB(&timeoutInfo->tvTimeout, &tv, &tv); + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, tv.tv_sec, tv.tv_usec, timeoutInfo->tmrType, (void*)timeoutInfo, &timeoutInfo->hTimer); + NW_ASSERT(NW_OK == rc); + + thiz->activeTimerInfo = timeoutInfo; + } + } + + NW_LEAVE(thiz); + + return rc; +} + +/** + * Start Timer with ULP Timer Manager + */ + + + + + +NwRcT +nwGtpv2cStartTimer(NwGtpv2cStackT* thiz, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + NwRcT (*timeoutCallbackFunc)(void*), + void* timeoutCallbackArg, + NwGtpv2cTimerHandleT *phTimer) +{ + NwRcT rc = NW_OK; + struct timeval tv; + NwGtpv2cTimeoutInfoT *timeoutInfo; + NwGtpv2cTimeoutInfoT *collision; + + NW_ENTER(thiz); + + if(gpGtpv2cTimeoutInfoPool) + { + timeoutInfo = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = gpGtpv2cTimeoutInfoPool->next; + } + else + { + NW_GTPV2C_MALLOC(thiz, sizeof(NwGtpv2cTimeoutInfoT), timeoutInfo, NwGtpv2cTimeoutInfoT*); + } + + if(timeoutInfo) + { + timeoutInfo->tmrType = tmrType; + timeoutInfo->timeoutArg = timeoutCallbackArg; + timeoutInfo->timeoutCallbackFunc = timeoutCallbackFunc; + timeoutInfo->hStack = (NwGtpv2cStackHandleT)thiz; + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + NW_ASSERT(gettimeofday(&timeoutInfo->tvTimeout, NULL) == 0); + + timeoutInfo->tvTimeout.tv_sec = timeoutSec; + timeoutInfo->tvTimeout.tv_usec = timeoutUsec; + NW_GTPV2C_TIMER_ADD(&tv, &timeoutInfo->tvTimeout, &timeoutInfo->tvTimeout); + + rc = nwGtpv2cTmrMinHeapInsert(thiz->hTmrMinHeap, timeoutInfo); +#if 0 + do { + collision = RB_INSERT(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + if(!collision) + break; + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "timer collision!"); + timeoutInfo->tvTimeout.tv_usec++; /* HACK: In case there is a collision, schedule this event 1 usec later */ + if(timeoutInfo->tvTimeout.tv_usec > (999999 /*1000000 - 1*/)) + { + timeoutInfo->tvTimeout.tv_usec = 0; + timeoutInfo->tvTimeout.tv_sec++; + } + } while (1); +#endif + + if(thiz->activeTimerInfo) + { + if(NW_GTPV2C_TIMER_CMP_P(&(thiz->activeTimerInfo->tvTimeout), &(timeoutInfo->tvTimeout), >)) + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + thiz->activeTimerInfo->hTimer, thiz->activeTimerInfo); + rc = thiz->tmrMgr.tmrStopCallback(thiz->tmrMgr.tmrMgrHandle, thiz->activeTimerInfo->hTimer); + NW_ASSERT(NW_OK == rc); + } + else + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Already Started timer 0x%"PRIxPTR" for info 0x%p!", + thiz->activeTimerInfo->hTimer, thiz->activeTimerInfo); + *phTimer = (NwGtpv2cTimerHandleT) timeoutInfo; + NW_LEAVE(thiz); + return NW_OK; + } + } + + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, + timeoutSec, + timeoutUsec, + tmrType, + (void*)timeoutInfo, + &timeoutInfo->hTimer); + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Started timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + NW_ASSERT(NW_OK == rc); + thiz->activeTimerInfo = timeoutInfo; + + } + + *phTimer = (NwGtpv2cTimerHandleT) timeoutInfo; + NW_LEAVE(thiz); + + return rc; +} + +NwRcT +nwGtpv2cStartTimerOld(NwGtpv2cStackT* thiz, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + NwRcT (*timeoutCallbackFunc)(void*), + void* timeoutCallbackArg, + NwGtpv2cTimerHandleT *phTimer) +{ + NwRcT rc = NW_OK; + struct timeval tv; + NwGtpv2cTimeoutInfoT *timeoutInfo; + NwGtpv2cTimeoutInfoT *collision; + + NW_ASSERT(thiz != NULL); + + NW_ENTER(thiz); + + if(gpGtpv2cTimeoutInfoPool) + { + timeoutInfo = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = gpGtpv2cTimeoutInfoPool->next; + } + else + { + NW_GTPV2C_MALLOC(thiz, sizeof(NwGtpv2cTimeoutInfoT), timeoutInfo, NwGtpv2cTimeoutInfoT*); + } + + if(timeoutInfo) + { + timeoutInfo->tmrType = tmrType; + timeoutInfo->timeoutArg = timeoutCallbackArg; + timeoutInfo->timeoutCallbackFunc = timeoutCallbackFunc; + timeoutInfo->hStack = (NwGtpv2cStackHandleT)thiz; + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + NW_ASSERT(gettimeofday(&timeoutInfo->tvTimeout, NULL) == 0); + + timeoutInfo->tvTimeout.tv_sec = timeoutSec; + timeoutInfo->tvTimeout.tv_usec = timeoutUsec; + NW_GTPV2C_TIMER_ADD(&tv, &timeoutInfo->tvTimeout, &timeoutInfo->tvTimeout); + + do { + collision = RB_INSERT(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + if(!collision) + break; + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "timer collision!"); + timeoutInfo->tvTimeout.tv_usec++; /* HACK: In case there is a collision, schedule this event 1 usec later */ + if(timeoutInfo->tvTimeout.tv_usec > (999999 /*1000000 - 1*/)) + { + timeoutInfo->tvTimeout.tv_usec = 0; + timeoutInfo->tvTimeout.tv_sec++; + } + } while (1); + + if(thiz->activeTimerInfo) + { + if(NW_GTPV2C_TIMER_CMP_P(&(thiz->activeTimerInfo->tvTimeout), &(timeoutInfo->tvTimeout), >)) + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + thiz->activeTimerInfo->hTimer, thiz->activeTimerInfo); + rc = thiz->tmrMgr.tmrStopCallback(thiz->tmrMgr.tmrMgrHandle, thiz->activeTimerInfo->hTimer); + NW_ASSERT(NW_OK == rc); + } + else + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Already Started timer 0x%"PRIxPTR" for info 0x%p!", + thiz->activeTimerInfo->hTimer, thiz->activeTimerInfo); + *phTimer = (NwGtpv2cTimerHandleT) timeoutInfo; + NW_LEAVE(thiz); + return NW_OK; + } + } + + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, timeoutSec, timeoutUsec, tmrType, (void*)timeoutInfo, &timeoutInfo->hTimer); + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Started timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + NW_ASSERT(NW_OK == rc); + thiz->activeTimerInfo = timeoutInfo; + + } + + *phTimer = (NwGtpv2cTimerHandleT) timeoutInfo; + NW_LEAVE(thiz); + + return rc; +} + +/** + * Stop Timer with ULP Timer Manager + */ +NwRcT +nwGtpv2cStopTimer(NwGtpv2cStackT* thiz, + NwGtpv2cTimerHandleT hTimer) +{ + NwRcT rc = NW_OK; + struct timeval tv; + NwGtpv2cTimeoutInfoT *timeoutInfo; + + NW_ASSERT(thiz != NULL); + + NW_ENTER(thiz); + + timeoutInfo = (NwGtpv2cTimeoutInfoT*) hTimer; + + rc = nwGtpv2cTmrMinHeapRemove(thiz->hTmrMinHeap, timeoutInfo->timerMinHeapIndex); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + if(thiz->activeTimerInfo == timeoutInfo) + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + rc = thiz->tmrMgr.tmrStopCallback(thiz->tmrMgr.tmrMgrHandle, timeoutInfo->hTimer); + thiz->activeTimerInfo = NULL; + NW_ASSERT(NW_OK == rc); + + timeoutInfo = nwGtpv2cTmrMinHeapPeek(thiz->hTmrMinHeap); + if(timeoutInfo) + { + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + if(NW_GTPV2C_TIMER_CMP_P(&timeoutInfo->tvTimeout, &tv, <)) + { + thiz->activeTimerInfo = timeoutInfo; + rc = nwGtpv2cProcessTimeout(timeoutInfo); + NW_ASSERT(NW_OK == rc); + } + else + { + NW_GTPV2C_TIMER_SUB(&timeoutInfo->tvTimeout, &tv, &tv); + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, tv.tv_sec, tv.tv_usec, timeoutInfo->tmrType, (void*)timeoutInfo, &timeoutInfo->hTimer); + NW_ASSERT(NW_OK == rc); + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Started timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + thiz->activeTimerInfo = timeoutInfo; + } + } + } + + NW_LEAVE(thiz); + + return rc; +} + +NwRcT +nwGtpv2cStopTimerOld(NwGtpv2cStackT* thiz, + NwGtpv2cTimerHandleT hTimer) +{ + NwRcT rc = NW_OK; + struct timeval tv; + NwGtpv2cTimeoutInfoT *timeoutInfo; + + NW_ASSERT(thiz != NULL); + + NW_ENTER(thiz); + + timeoutInfo = (NwGtpv2cTimeoutInfoT*) hTimer; + + RB_REMOVE(NwGtpv2cActiveTimerList, &(thiz->activeTimerList), timeoutInfo); + timeoutInfo->next = gpGtpv2cTimeoutInfoPool; + gpGtpv2cTimeoutInfoPool = timeoutInfo; + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + if(thiz->activeTimerInfo == timeoutInfo) + { + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Stopping active timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + rc = thiz->tmrMgr.tmrStopCallback(thiz->tmrMgr.tmrMgrHandle, timeoutInfo->hTimer); + thiz->activeTimerInfo = NULL; + NW_ASSERT(NW_OK == rc); + + timeoutInfo = RB_MIN(NwGtpv2cActiveTimerList, &(thiz->activeTimerList)); + if(timeoutInfo) + { + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + if(NW_GTPV2C_TIMER_CMP_P(&timeoutInfo->tvTimeout, &tv, <)) + { + thiz->activeTimerInfo = timeoutInfo; + rc = nwGtpv2cProcessTimeout(timeoutInfo); + NW_ASSERT(NW_OK == rc); + } + else + { + NW_GTPV2C_TIMER_SUB(&timeoutInfo->tvTimeout, &tv, &tv); + rc = thiz->tmrMgr.tmrStartCallback(thiz->tmrMgr.tmrMgrHandle, tv.tv_sec, tv.tv_usec, timeoutInfo->tmrType, (void*)timeoutInfo, &timeoutInfo->hTimer); + NW_ASSERT(NW_OK == rc); + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Started timer 0x%"PRIxPTR" for info 0x%p!", + timeoutInfo->hTimer, timeoutInfo); + thiz->activeTimerInfo = timeoutInfo; + } + } + } + + NW_LEAVE(thiz); + + return rc; +} + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsg.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsg.c new file mode 100644 index 0000000000..9f3ee41a2f --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsg.c @@ -0,0 +1,734 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <inttypes.h> + +#include "NwTypes.h" +#include "NwLog.h" +#include "NwUtils.h" +#include "NwGtpv2cLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/*----------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *----------------------------------------------------------------------------*/ + +static NwGtpv2cMsgT* gpGtpv2cMsgPool = NULL; + +/*----------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *----------------------------------------------------------------------------*/ + +NwRcT +nwGtpv2cMsgNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T teidPresent, + NW_IN NwU8T msgType, + NW_IN NwU32T teid, + NW_IN NwU32T seqNum, + NW_OUT NwGtpv2cMsgHandleT *phMsg) +{ + NwGtpv2cStackT* pStack = (NwGtpv2cStackT*) hGtpcStackHandle; + NwGtpv2cMsgT *pMsg; + + NW_ASSERT(pStack); + + if(gpGtpv2cMsgPool) + { + pMsg = gpGtpv2cMsgPool; + gpGtpv2cMsgPool = gpGtpv2cMsgPool->next; + } + else + { + NW_GTPV2C_MALLOC(pStack, sizeof(NwGtpv2cMsgT), pMsg, NwGtpv2cMsgT*); + } + + if(pMsg) + { + pMsg->version = NW_GTP_VERSION; + pMsg->teidPresent = teidPresent; + pMsg->msgType = msgType; + pMsg->teid = teid; + pMsg->seqNum = seqNum; + pMsg->msgLen = (NW_GTPV2C_EPC_SPECIFIC_HEADER_SIZE - (teidPresent ? 0 : 4)); + + pMsg->groupedIeEncodeStack.top = 0; + pMsg->hStack = hGtpcStackHandle; + + *phMsg = (NwGtpv2cMsgHandleT) pMsg; + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Created message %p!", pMsg); + return NW_OK; + } + + return NW_FAILURE; +} + +NwRcT +nwGtpv2cMsgFromBufferNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T* pBuf, + NW_IN NwU32T bufLen, + NW_OUT NwGtpv2cMsgHandleT *phMsg) +{ + NwGtpv2cStackT* pStack = (NwGtpv2cStackT*) hGtpcStackHandle; + NwGtpv2cMsgT *pMsg; + + NW_ASSERT(pStack); + + if(gpGtpv2cMsgPool) + { + pMsg = gpGtpv2cMsgPool; + gpGtpv2cMsgPool = gpGtpv2cMsgPool->next; + } + else + { + NW_GTPV2C_MALLOC(pStack, sizeof(NwGtpv2cMsgT), pMsg, NwGtpv2cMsgT*); + } + + if(pMsg) + { + *phMsg = (NwGtpv2cMsgHandleT) pMsg; + memcpy(pMsg->msgBuf, pBuf, bufLen); + pMsg->msgLen = bufLen; + + pMsg->version = ((*pBuf) & 0xE0) >> 5; + pMsg->teidPresent = ((*pBuf) & 0x08) >> 3; + pBuf++; + + pMsg->msgType = *(pBuf); + pBuf += 3; + + if(pMsg->teidPresent) + { + pMsg->teid = ntohl(*((NwU32T*)(pBuf))); + pBuf += 4; + } + + memcpy(((NwU8T*)&pMsg->seqNum) + 1, pBuf, 3); + pMsg->seqNum = ntohl(pMsg->seqNum); + + pMsg->hStack = hGtpcStackHandle; + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Created message %p!", pMsg); + return NW_OK; + } + return NW_FAILURE; +} + +NwRcT +nwGtpv2cMsgDelete( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cStackT* pStack = (NwGtpv2cStackT*) hGtpcStackHandle; + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Purging message %"PRIxPTR"!", hMsg); + + ((NwGtpv2cMsgT*)hMsg)->next = gpGtpv2cMsgPool; + gpGtpv2cMsgPool = (NwGtpv2cMsgT*) hMsg; + + return NW_OK; +} + + /** + * Set TEID for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] teid: TEID value. + */ + +NwRcT +nwGtpv2cMsgSetTeid(NW_IN NwGtpv2cMsgHandleT hMsg, NwU32T teid) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + thiz->teid = teid; + return NW_OK; +} + + /** + * Set TEID present flag for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] teidPesent: Flag boolean value. + */ + +NwRcT +nwGtpv2cMsgSetTeidPresent(NW_IN NwGtpv2cMsgHandleT hMsg, NwBoolT teidPresent) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + thiz->teidPresent = teidPresent; + return NW_OK; +} + + /** + * Set sequence for gtpv2c message. + * + * @param[in] hMsg : Message handle. + * @param[in] seqNum: Flag boolean value. + */ + +NwRcT +nwGtpv2cMsgSetSeqNumber(NW_IN NwGtpv2cMsgHandleT hMsg, NwU32T seqNum) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + thiz->seqNum = seqNum; + return NW_OK; +} + + /** + * Get TEID present for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetTeid(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + return (thiz->teid); +} + + /** + * Get TEID present for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwBoolT +nwGtpv2cMsgGetTeidPresent(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + return (thiz->teidPresent); +} + + /** + * Get sequence number for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetSeqNumber(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + return (thiz->seqNum); +} + + /** + * Get msg type for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetMsgType(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + return (thiz->msgType); +} + + /** + * Get msg type for gtpv2c message. + * + * @param[in] hMsg : Message handle. + */ + +NwU32T +nwGtpv2cMsgGetLength(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + return (thiz->msgLen); +} + + +NwRcT +nwGtpv2cMsgAddIeTV1(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU8T value) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv1T *pIe; + + pIe = (NwGtpv2cIeTv1T*) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->l = htons(0x0001); + pIe->i = instance & 0x00ff; + pIe->v = value; + + pMsg->msgLen += sizeof(NwGtpv2cIeTv1T); + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgAddIeTV2(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU16T value) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv2T *pIe; + + pIe = (NwGtpv2cIeTv2T*) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->l = htons(0x0002); + pIe->i = instance & 0x00ff; + pIe->v = htons(value); + + pMsg->msgLen += sizeof(NwGtpv2cIeTv2T); + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgAddIeTV4(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU32T value) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv4T *pIe; + + pIe = (NwGtpv2cIeTv4T*) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->l = htons(0x0004); + pIe->i = instance & 0x00ff; + pIe->v = htonl(value); + + pMsg->msgLen += sizeof(NwGtpv2cIeTv4T); + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgAddIe(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU16T length, + NW_IN NwU8T instance, + NW_IN NwU8T* pVal) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + + pIe = (NwGtpv2cIeTlvT*) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->l = htons(length); + pIe->i = instance & 0x00ff; + + memcpy(((NwU8T*)pIe) + 4, pVal, length); + pMsg->msgLen += (4 + length); + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgGroupedIeStart(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + + pIe = (NwGtpv2cIeTlvT*) (pMsg->msgBuf + pMsg->msgLen); + + pIe->t = type; + pIe->i = instance & 0x00ff; + pMsg->msgLen += (4); + pIe->l = (pMsg->msgLen); + + NW_ASSERT(pMsg->groupedIeEncodeStack.top < NW_GTPV2C_MAX_GROUPED_IE_DEPTH); + + pMsg->groupedIeEncodeStack.pIe[pMsg->groupedIeEncodeStack.top] = pIe; + pMsg->groupedIeEncodeStack.top++; + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgGroupedIeEnd(NW_IN NwGtpv2cMsgHandleT hMsg) +{ + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + + NW_ASSERT(pMsg->groupedIeEncodeStack.top > 0); + + pMsg->groupedIeEncodeStack.top--; + pIe = pMsg->groupedIeEncodeStack.pIe[pMsg->groupedIeEncodeStack.top]; + + pIe->l = htons(pMsg->msgLen - pIe->l); + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgAddIeCause(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_IN NwU8T causeValue, + NW_IN NwU8T bitFlags, + NW_IN NwU8T offendingIeType, + NW_IN NwU8T offendingIeInstance) +{ + NwU8T causeBuf[8]; + + causeBuf[0] = causeValue; + causeBuf[1] = bitFlags; + + if(offendingIeType) + { + causeBuf[2] = offendingIeType; + causeBuf[3] = 0; + causeBuf[4] = 0; + causeBuf[5] = (offendingIeInstance & 0x0f); + } + + return (nwGtpv2cMsgAddIe(hMsg, NW_GTPV2C_IE_CAUSE, (offendingIeType? 6 : 2), instance, causeBuf)); +} + +NwRcT +nwGtpv2cMsgAddIeFteid(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_IN NwU8T ifType, + NW_IN NwU32T teidOrGreKey, + NW_IN NwU32T ipv4Addr, + NW_IN NwU8T* pIpv6Addr) +{ + + NwU8T fteidBuf[32]; + NwU8T *pFteidBuf = fteidBuf; + + fteidBuf[0] = (ifType & 0x1F); + pFteidBuf++; + + *((NwU32T*)(pFteidBuf)) = htonl((teidOrGreKey)); + pFteidBuf += 4; + + if(ipv4Addr) + { + fteidBuf[0] |= (0x01 << 7); + *((NwU32T*)(pFteidBuf)) = htonl(ipv4Addr); + pFteidBuf += 4; + } + + if(pIpv6Addr) + { + fteidBuf[0] |= (0x01 << 6); + memcpy((pFteidBuf), pIpv6Addr, 16); + pFteidBuf += 16; + } + return (nwGtpv2cMsgAddIe(hMsg, NW_GTPV2C_IE_FTEID, (pFteidBuf - fteidBuf), instance, fteidBuf)); +} + + +NwBoolT +nwGtpv2cMsgIsIePresent(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + if((NwGtpv2cIeTv1T*) thiz->pIe[type][instance]) + return NW_TRUE; + return NW_FALSE; +} + +NwRcT +nwGtpv2cMsgGetIeTV1(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU8T* pVal) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv1T *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTv1T*) thiz->pIe[type][instance]; + if(ntohs(pIe->l) != 0x01) + return NW_GTPV2C_IE_INCORRECT; + + if(pVal) *pVal = pIe->v; + return NW_OK; + } + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeTV2( NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU16T* pVal) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv2T *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTv2T*) thiz->pIe[type][instance]; + if(ntohs(pIe->l) != 0x02) + return NW_GTPV2C_IE_INCORRECT; + + if(pVal) *pVal = ntohs(pIe->v); + return NW_OK; + } + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeTV4( NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU32T* pVal) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv4T *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTv4T*) thiz->pIe[type][instance]; + if(ntohs(pIe->l) != 0x04) + return NW_GTPV2C_IE_INCORRECT; + + if(pVal) *pVal = ntohl(pIe->v); + return NW_OK; + } + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeTV8( NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU64T* pVal) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTv8T *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTv8T*) thiz->pIe[type][instance]; + if(ntohs(pIe->l) != 0x08) + return NW_GTPV2C_IE_INCORRECT; + + if(pVal) *pVal = NW_NTOHLL((pIe->v)); + return NW_OK; + } + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Cannot retrieve IE of type %u instance %u !", type, instance); + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeTlv( NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_IN NwU16T maxLen, + NW_OUT NwU8T* pVal, + NW_OUT NwU16T* pLen) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTlvT*) thiz->pIe[type][instance]; + if(ntohs(pIe->l) <= maxLen) + { + if(pVal) memcpy(pVal, ((NwU8T*) pIe) + 4, ntohs(pIe->l)); + if(pLen) *pLen = ntohs(pIe->l); + return NW_OK; + } + } + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeTlvP( NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T type, + NW_IN NwU8T instance, + NW_OUT NwU8T** ppVal, + NW_OUT NwU16T* pLen) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[type][instance]) + { + pIe = (NwGtpv2cIeTlvT*) thiz->pIe[type][instance]; + if(ppVal) *ppVal = ((NwU8T*) pIe) + 4; + if(pLen) *pLen = ntohs(pIe->l); + return NW_OK; + } + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeCause(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_OUT NwU8T* causeValue, + NW_OUT NwU8T* flags, + NW_OUT NwU8T* offendingIeType, + NW_OUT NwU8T* offendingIeInstance) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + if(thiz->isIeValid[NW_GTPV2C_IE_CAUSE][instance]) + { + pIe = (NwGtpv2cIeTlvT*) thiz->pIe[NW_GTPV2C_IE_CAUSE][instance]; + *causeValue = *((NwU8T*)(((NwU8T*)pIe) + 4)); + *flags = *((NwU8T*)(((NwU8T*)pIe) + 5)); + if(pIe->l == 6) + { + *offendingIeType = *((NwU8T*)(((NwU8T*)pIe) + 6)); + *offendingIeType = *((NwU8T*)(((NwU8T*)pIe) + 8)); + } + return NW_OK; + } + + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgGetIeFteid(NW_IN NwGtpv2cMsgHandleT hMsg, + NW_IN NwU8T instance, + NW_OUT NwU8T* ifType, + NW_OUT NwU32T* teidOrGreKey, + NW_OUT NwU32T* ipv4Addr, + NW_OUT NwU8T* pIpv6Addr) +{ + NwGtpv2cMsgT *thiz = (NwGtpv2cMsgT*) hMsg; + NwGtpv2cIeTlvT *pIe; + + NW_ASSERT(instance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + + if(thiz->isIeValid[NW_GTPV2C_IE_FTEID][instance]) + { + pIe = (NwGtpv2cIeTlvT*) thiz->pIe[NW_GTPV2C_IE_FTEID][instance]; + NwU8T flags; + NwU8T* pIeValue = ((NwU8T*) pIe) + 4; + flags = (*pIeValue) & 0xE0; + *ifType = (*pIeValue) & 0x1F; + pIeValue += 1; + + *teidOrGreKey = ntohl(*((NwU32T*)(pIeValue))); + pIeValue += 4; + + if(flags & 0x80) + { + *ipv4Addr = ntohl(*((NwU32T*)(pIeValue))); + pIeValue += 4; + } + return NW_OK; + } + + return NW_GTPV2C_IE_MISSING; +} + +NwRcT +nwGtpv2cMsgHexDump(NwGtpv2cMsgHandleT hMsg, FILE* fp) +{ + + NwGtpv2cMsgT* pMsg = (NwGtpv2cMsgT*) hMsg; + NwU8T* data = pMsg->msgBuf; + NwU32T size = pMsg->msgLen; + + unsigned char *p = (unsigned char*)data; + unsigned char c; + int n; + char bytestr[4] = {0}; + char addrstr[10] = {0}; + char hexstr[ 16*3 + 5] = {0}; + char charstr[16*1 + 5] = {0}; + fprintf((FILE*)fp, "\n"); + for(n=1;n<=size;n++) { + if (n%16 == 1) { + /* store address for this line */ + snprintf(addrstr, sizeof(addrstr), "%.4lx", + ((unsigned long)p-(unsigned long)data) ); + } + + c = *p; + if (isalnum(c) == 0) { + c = '.'; + } + + /* store hex str (for left side) */ + snprintf(bytestr, sizeof(bytestr), "%02X ", *p); + strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); + + /* store char str (for right side) */ + snprintf(bytestr, sizeof(bytestr), "%c", c); + strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); + if(n%16 == 0) { + /* line completed */ + fprintf((FILE*)fp, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + hexstr[0] = 0; + charstr[0] = 0; + } else if(n%8 == 0) { + /* half line: add whitespaces */ + strncat(hexstr, " ", sizeof(hexstr)-strlen(hexstr)-1); + strncat(charstr, " ", sizeof(charstr)-strlen(charstr)-1); + } + p++; /* next byte */ + } + + if (strlen(hexstr) > 0) { + /* print rest of buffer if not empty */ + fprintf((FILE*)fp, "[%4.4s] %-50.50s %s\n", addrstr, hexstr, charstr); + + } + fprintf((FILE*)fp, "\n"); + + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgIeParseInfo.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgIeParseInfo.c new file mode 100644 index 0000000000..62a8892ab3 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgIeParseInfo.c @@ -0,0 +1,737 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwLog.h" +#include "NwUtils.h" +#include "NwGtpv2cLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct NwGtpv2cMsgIeInfo +{ + NwU8T ieType; + NwU8T ieMinLength; + NwU8T ieInstance; + NwU8T iePresence; + struct NwGtpv2cMsgIeInfo *pGroupedIeInfo; +} NwGtpv2cMsgIeInfoT; + +static +NwGtpv2cMsgIeInfoT createSessionReqBearerCtxtTobeCreatedIeInfoTbl[] = +{ + { NW_GTPV2C_IE_EBI , 1, NW_GTPV2C_IE_INSTANCE_ZERO , NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_BEARER_TFT , 0, NW_GTPV2C_IE_INSTANCE_ZERO , NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_THREE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_FOUR , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + { NW_GTPV2C_IE_BEARER_LEVEL_QOS, 18, NW_GTPV2C_IE_INSTANCE_ZERO , NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, +// { NW_GTPV2C_IE_IMSI , 0, NW_GTPV2C_IE_INSTANCE_ZERO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL}, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT createSessionReqBearerCtxtTobeRemovedIeInfoTbl[] = +{ + { NW_GTPV2C_IE_IMSI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT echoRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY, NULL}, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT createSessionReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_IMSI , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_MSISDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_MEI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_RAT_TYPE , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_INDICATION , 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_APN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_APN_RESTRICTION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_SELECTION_MODE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_PDN_TYPE , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_PAA , 5, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_AMBR , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_EBI , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_PCO , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_TRACE_INFORMATION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_FQ_CSID , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_FQ_CSID , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , createSessionReqBearerCtxtTobeCreatedIeInfoTbl}, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, createSessionReqBearerCtxtTobeRemovedIeInfoTbl}, + { NW_GTPV2C_IE_SERVING_NETWORK, 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL}, + { NW_GTPV2C_IE_RECOVERY , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_CHARGING_CHARACTERISTICS, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_LDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_LDN , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT modifyBearerReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_MEI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_SERVING_NETWORK, 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL}, + { NW_GTPV2C_IE_ULI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RAT_TYPE , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_INDICATION , 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT deleteSessionReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_EBI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_ULI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PCO , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT createSessionRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_PAA , 5, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_APN_RESTRICTION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT modifyBearerRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_PAA , 5, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_APN_RESTRICTION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT deleteSessionRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PCO , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +/* Message sent over s10 interface */ +static +NwGtpv2cMsgIeInfoT identificationReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_GUTI , 6, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_COMPLETE_REQUEST_MESSAGE, 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_SERVING_NETWORK, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT identificationRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_IMSI , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_MM_CONTEXT , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_TRACE_INFORMATION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT contextReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_IMSI , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_GUTI , 5, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_ULI , 7, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PTMSI , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_COMPLETE_REQUEST_MESSAGE, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_UDP_SOURCE_PORT_NUMBER, 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RAT_TYPE , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_HOP_COUNTER , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_SERVING_NETWORK, 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_LDN , 3, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT contextRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_IMSI , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_MM_CONTEXT , 4, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_PDN_CONNECTION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_FQDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_TRACE_INFORMATION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_IP_ADDRESS , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_IP_ADDRESS , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL , NULL }, + { NW_GTPV2C_IE_RFSP_INDEX , 2, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_RFSP_INDEX , 2, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_UE_TIME_ZONE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_LDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT contextAckIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT forwardRelocationReqIeInfoTbl[] = +{ + { NW_GTPV2C_IE_IMSI , 8, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_PDN_CONNECTION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_FQDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_MM_CONTEXT , 4, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_TARGET_IDENTIFICATION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_IP_ADDRESS , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_IP_ADDRESS , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_SOURCE_IDENTIFICATION, 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_SELECTED_PLMN_ID, 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_TRACE_INFORMATION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_RFSP_INDEX , 2, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_RFSP_INDEX , 2, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_CSG_ID , 4, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_CSG_MEMBERSHIP_INDICATION, 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_UE_TIME_ZONE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_LDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_ADDITIONAL_MM_CTXT_FOR_SRVCC,0,NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_ADDITIONAL_FLAGS_FOR_SRVCC, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_MSISDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL_OPTIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0 } +}; + +static +NwGtpv2cMsgIeInfoT forwardRelocationRspIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_FTEID , 9, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_BEARER_CONTEXT , 0, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_ONE , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CONTAINER , 1, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_F_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_TWO , NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_LDN , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT forwardRelocationCompleteNtfIeInfoTbl[] = +{ + { NW_GTPV2C_IE_INDICATION , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_CONDITIONAL, NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +static +NwGtpv2cMsgIeInfoT forwardRelocationCompleteAckIeInfoTbl[] = +{ + { NW_GTPV2C_IE_CAUSE , 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY , NULL }, + { NW_GTPV2C_IE_RECOVERY , 1, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + { NW_GTPV2C_IE_PRIVATE_EXTENSION, 0, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_OPTIONAL , NULL }, + + /* Do not add below this */ + { 0, 0, 0} +}; + +/*----------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *----------------------------------------------------------------------------*/ + +static NwU32T +nwGtpv2cMsgGroupedIeCount(NwGtpv2cMsgIeInfoT *pMsgIeInfo) +{ + NwU32T count = 0; + NwGtpv2cMsgIeInfoT *pGroupedIeInfo = pMsgIeInfo; + while (pGroupedIeInfo++) { + if (pGroupedIeInfo->ieType == 0) { + break; + } + count ++; + } + + return count; +} + +static NwRcT +nwGtpv2cMsgIeParseInfoUpdate(NwGtpv2cMsgIeParseInfoT *thiz, + NwGtpv2cMsgIeInfoT *pMsgIeInfo) +{ + NwU32T i, j; + + for (i = 0; pMsgIeInfo[i].ieType; i++) + { + if (pMsgIeInfo[i].pGroupedIeInfo) { + NwGtpv2cGroupedIeParseInfoT *pMsgIeParseInfo; + + NW_GTPV2C_MALLOC(thiz->hStack, sizeof(NwGtpv2cGroupedIeParseInfoT), + pMsgIeParseInfo, NwGtpv2cGroupedIeParseInfoT*); + + pMsgIeParseInfo->groupedIeType = pMsgIeInfo[i].ieType; + pMsgIeParseInfo->hStack = thiz->hStack; + + for (j = 0; pMsgIeInfo[i].pGroupedIeInfo[j].ieType; j++) { + pMsgIeParseInfo->ieParseInfo[pMsgIeInfo[i].pGroupedIeInfo[j].ieType][pMsgIeInfo[i].pGroupedIeInfo[j].ieInstance].ieMinLength = + pMsgIeInfo[i].pGroupedIeInfo[j].ieMinLength; + pMsgIeParseInfo->ieParseInfo[pMsgIeInfo[i].pGroupedIeInfo[j].ieType][pMsgIeInfo[i].pGroupedIeInfo[j].ieInstance].iePresence = + pMsgIeInfo[i].pGroupedIeInfo[j].iePresence; + + if(pMsgIeInfo[i].pGroupedIeInfo[j].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + pMsgIeParseInfo->mandatoryIeCount++; + } + thiz->ieParseInfo[pMsgIeInfo[i].ieType][pMsgIeInfo[i].ieInstance].pGroupedIeInfo = pMsgIeParseInfo; + } else { + thiz->ieParseInfo[pMsgIeInfo[i].ieType][pMsgIeInfo[i].ieInstance].pGroupedIeInfo = NULL; + } + thiz->ieParseInfo[pMsgIeInfo[i].ieType][pMsgIeInfo[i].ieInstance].iePresence = pMsgIeInfo[i].iePresence; + thiz->ieParseInfo[pMsgIeInfo[i].ieType][pMsgIeInfo[i].ieInstance].ieMinLength = pMsgIeInfo[i].ieMinLength; + + if(pMsgIeInfo[i].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + thiz->mandatoryIeCount++; + } + + return NW_OK; +} + +static NwRcT +nwGtpv2cMsgGroupedIeParse(NW_IN NwGtpv2cGroupedIeParseInfoT* thiz, + NW_IN NwU8T ieType, + NW_IN NwU16T ieLength, + NW_IN NwU8T ieInstance, + NW_IN NwU8T *pIeValue) +{ + NW_ASSERT(thiz); + + NW_LOG(thiz->hStack, NW_LOG_LEVEL_DEBG, "Received grouped IE %u with instance %u of length %u in msg-type %u!", + ieType, ieInstance, ieLength, thiz->groupedIeType); + + return NW_OK; +} + +/*----------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *----------------------------------------------------------------------------*/ + +/** + * Constructor + * @return Pointer to the object on success. + */ + +NwGtpv2cMsgIeParseInfoT* +nwGtpv2cMsgIeParseInfoNew(NwGtpv2cStackHandleT hStack, NwU8T msgType) +{ + NwRcT rc; + NwGtpv2cMsgIeParseInfoT *thiz; + + NW_GTPV2C_MALLOC(hStack, sizeof(NwGtpv2cMsgIeParseInfoT), thiz, NwGtpv2cMsgIeParseInfoT*); + + if(thiz) + { + memset(thiz, 0, sizeof(NwGtpv2cMsgIeParseInfoT)); + + thiz->hStack = hStack; + thiz->msgType = msgType; + + switch(msgType) + { + case NW_GTP_ECHO_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, echoRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_CREATE_SESSION_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, createSessionReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_CREATE_SESSION_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, createSessionRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_DELETE_SESSION_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, deleteSessionReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_DELETE_SESSION_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, deleteSessionRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_MODIFY_BEARER_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, modifyBearerReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_MODIFY_BEARER_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, modifyBearerRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_FORWARD_RELOCATION_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, forwardRelocationReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_FORWARD_RELOCATION_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, forwardRelocationRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_FORWARD_RELOCATION_COMPLETE_NTF: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, forwardRelocationCompleteNtfIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_FORWARD_RELOCATION_COMPLETE_ACK: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, forwardRelocationCompleteAckIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_CONTEXT_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, contextReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_CONTEXT_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, contextRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_CONTEXT_ACK: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, contextAckIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_IDENTIFICATION_REQ: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, identificationReqIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + case NW_GTP_IDENTIFICATION_RSP: + { + rc = nwGtpv2cMsgIeParseInfoUpdate(thiz, identificationRspIeInfoTbl); + NW_ASSERT(NW_OK == rc); + } + break; + + default: + { + free(thiz); + thiz = NULL; + } + break; + } + } + + return thiz; +} + +/** + * Destructor + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cMsgIeParseInfoDelete(NwGtpv2cMsgIeParseInfoT* thiz) +{ + NW_GTPV2C_FREE(thiz->hStack, thiz); + return NW_OK; +} + +/** + * Parse message + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cMsgIeParse(NW_IN NwGtpv2cMsgIeParseInfoT* thiz, + NW_IN NwGtpv2cMsgHandleT hMsg, + NW_INOUT NwGtpv2cErrorT *pError) +{ + NwRcT rc = NW_OK; + NwU16T mandatoryIeCount =0; + NwU8T *pIeBufStart; + NwU8T *pIeBufEnd; + NwU16T ieType; + NwU16T ieLength; + NwU16T ieInstance; + NwGtpv2cIeTlvT *pIe; + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + NwU8T flags = *((NwU8T*)(pMsg->msgBuf)); + + pIeBufStart = (NwU8T *) (pMsg->msgBuf + (flags & 0x08 ? 12: 8)); + pIeBufEnd = (NwU8T *) (pMsg->msgBuf + pMsg->msgLen); + + //memset(pMsg->pIe, 0, sizeof(NwU8T*) * (NW_GTPV2C_IE_TYPE_MAXIMUM) * (NW_GTPV2C_IE_INSTANCE_MAXIMUM)); + memset(pMsg->isIeValid, (NW_FALSE), sizeof(NwU8T) * (NW_GTPV2C_IE_TYPE_MAXIMUM) * (NW_GTPV2C_IE_INSTANCE_MAXIMUM)); + + while (pIeBufStart < pIeBufEnd) + { + pIe = (NwGtpv2cIeTlvT*) pIeBufStart; + ieType = pIe->t; + ieLength = ntohs(pIe->l); + ieInstance = pIe->i & 0x0F; + + NW_ASSERT(NW_GTPV2C_IE_INSTANCE_MAXIMUM >= ieInstance); + + NW_LOG(thiz->hStack, NW_LOG_LEVEL_DEBG, "Received IE %u with instance %u of length %u in msg-type %u!", ieType, ieInstance, ieLength, thiz->msgType); + if(pIeBufStart + 4 + ieLength > pIeBufEnd) + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Invalid length for IE of type %u and instance %u!", ieType, ieInstance); + pError->cause = NW_GTPV2C_CAUSE_INVALID_LENGTH; + pError->offendingIe.type = ieType; + pError->offendingIe.instance = ieInstance; + return NW_FAILURE; + } + + if((thiz->ieParseInfo[ieType][ieInstance].iePresence)) + { + if((ieLength < (thiz->ieParseInfo[ieType][ieInstance].ieMinLength))) + { + if(thiz->ieParseInfo[ieType][ieInstance].iePresence == NW_GTPV2C_IE_PRESENCE_OPTIONAL) + { + /* Ignore TLV */ + pIeBufStart += (ieLength + 4); + continue; + } + else + { + pError->cause = NW_GTPV2C_CAUSE_MANDATORY_IE_INCORRECT; + pError->offendingIe.type = ieType; + pError->offendingIe.instance = ieInstance; + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Mandatory IE of type %u and instance %u incorrect!", ieType, ieInstance); + return NW_FAILURE; + } + } + + if(pMsg->isIeValid[ieType][ieInstance] == NW_TRUE) + { + /* + * If an information element is repeated in a GTP signalling + * message in which repetition of the information element is + * not specified, only the contents of the information element + * appearing first shall be handled and all subsequent repetitions + * of the information element shall be ignored. + * TODO: Add handling for IEs for which repetition is allowed. + */ + pIeBufStart += (ieLength + 4); + continue; + } + pMsg->pIe[ieType][ieInstance] = (NwU8T*) pIeBufStart; + pMsg->isIeValid[ieType][ieInstance] = NW_TRUE; + + if(thiz->ieParseInfo[ieType][ieInstance].pGroupedIeInfo) + { + /* Parse the grouped IE */ + rc = nwGtpv2cMsgGroupedIeParse(thiz->ieParseInfo[ieType][ieInstance].pGroupedIeInfo, ieType, ieLength, ieInstance, ((NwU8T*) pIe) + 4); + if (rc != NW_OK) + { + pError->cause = NW_GTPV2C_CAUSE_MANDATORY_IE_INCORRECT; + pError->offendingIe.type = ieType; + pError->offendingIe.instance = ieInstance; + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Mandatory IE of type %u and instance %u incorrect!", ieType, ieInstance); + return NW_FAILURE; + } + } + + if(thiz->ieParseInfo[ieType][ieInstance].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + { + mandatoryIeCount++; + } + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_WARN, "Unexpected IE %u with instance %u of length %u received in msg %u!", ieType, ieInstance, ieLength, thiz->msgType); + } + + pIeBufStart += (ieLength + 4); + } + + if((NW_OK == rc) && (mandatoryIeCount != thiz->mandatoryIeCount)) + { + for(ieType = 0; ieType < NW_GTPV2C_IE_TYPE_MAXIMUM; ieType++) + { + for(ieInstance = 0; ieInstance < NW_GTPV2C_IE_INSTANCE_MAXIMUM; ieInstance++) + { + if(thiz->ieParseInfo[ieType][ieInstance].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + { + if(pMsg->isIeValid[ieType][ieInstance] == NW_FALSE) + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Mandatory IE of type %u and instance %u missing in msg type %u", ieType, ieInstance, pMsg->msgType); + pError->cause = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + pError->offendingIe.type = ieType; + pError->offendingIe.instance = ieInstance; + return NW_FAILURE; + } + } + } + } + NW_LOG(thiz->hStack, NW_LOG_LEVEL_CRIT, "Unknown mandatory IE missing. Msg parser formed incorrectly!"); + pError->cause = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + pError->offendingIe.type = 0; + pError->offendingIe.instance = 0; + return NW_FAILURE; + } + + pError->cause = NW_GTPV2C_CAUSE_REQUEST_ACCEPTED; + return NW_OK; +} + + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgParser.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgParser.c new file mode 100644 index 0000000000..0cfd7c6ab1 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cMsgParser.c @@ -0,0 +1,316 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwGtpv2cLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * Allocate a gtpv2c message Parser. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] msgType : Message type for this message parser. + * @param[out] pthiz : Pointer to message parser handle. + */ + +NwRcT +nwGtpv2cMsgParserNew( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwU8T msgType, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg, + NW_IN NwGtpv2cMsgParserT **pthiz) +{ + NwGtpv2cMsgParserT* thiz; +// NW_GTPV2C_MALLOC(hGtpcStackHandle, sizeof(NwGtpv2cMsgParserT), thiz, NwGtpv2cMsgParserT*); + thiz = (NwGtpv2cMsgParserT*) malloc (sizeof(NwGtpv2cMsgParserT)); + if(thiz) + { + memset(thiz, 0, sizeof(NwGtpv2cMsgParserT)); + thiz->msgType = msgType; + thiz->hStack = hGtpcStackHandle; + *pthiz = thiz; + thiz->ieReadCallback = ieReadCallback; + thiz->ieReadCallbackArg = ieReadCallbackArg; + return NW_OK; + } + return NW_FAILURE; +} + + /** + * Free a gtpv2c message parser. + * + * @param[in] hGtpcStackHandle : gtpv2c stack handle. + * @param[in] thiz : Message parser handle. + */ + +NwRcT +nwGtpv2cMsgParserDelete( NW_IN NwGtpv2cStackHandleT hGtpcStackHandle, + NW_IN NwGtpv2cMsgParserT* thiz) +{ + NW_GTPV2C_FREE(hGtpcStackHandle, thiz); + return NW_OK; +} + +NwRcT +nwGtpv2cMsgParserUpdateIeReadCallback( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg)) +{ + if(thiz) + { + thiz->ieReadCallback = ieReadCallback; + return NW_OK; + } + return NW_FAILURE; +} + +NwRcT +nwGtpv2cMsgParserUpdateIeReadCallbackArg( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN void* ieReadCallbackArg) +{ + if(thiz) + { + thiz->ieReadCallbackArg = ieReadCallbackArg; + return NW_OK; + } + return NW_FAILURE; +} + +NwRcT +nwGtpv2cMsgParserAddIe( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwU8T ieType, + NW_IN NwU8T ieInstance, + NW_IN NwU8T iePresence, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg) +{ + NW_ASSERT(thiz); + if(thiz->ieParseInfo[ieType][ieInstance].iePresence == 0) + { + NW_ASSERT(ieInstance <= NW_GTPV2C_IE_INSTANCE_MAXIMUM); + + thiz->ieParseInfo[ieType][ieInstance].ieReadCallback = ieReadCallback; + thiz->ieParseInfo[ieType][ieInstance].ieReadCallbackArg = ieReadCallbackArg; + thiz->ieParseInfo[ieType][ieInstance].iePresence = iePresence; + + if (iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + { + thiz->mandatoryIeCount++; + } + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Cannot add IE to parser for type %u and instance %u. IE info already exists!", ieType, ieInstance); + } + + return NW_OK; +} + +NwRcT +nwGtpv2cMsgParserUpdateIe( NW_IN NwGtpv2cMsgParserT* thiz, + NW_IN NwU8T ieType, + NW_IN NwU8T ieInstance, + NW_IN NwU8T iePresence, + NW_IN NwRcT (*ieReadCallback) (NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T* ieValue, + void* ieReadCallbackArg), + NW_IN void* ieReadCallbackArg) +{ + NW_ASSERT(thiz); + if(thiz->ieParseInfo[ieType][ieInstance].iePresence) + { + thiz->ieParseInfo[ieType][ieInstance].ieReadCallback = ieReadCallback; + thiz->ieParseInfo[ieType][ieInstance].ieReadCallbackArg = ieReadCallbackArg; + + thiz->ieParseInfo[ieType][ieInstance].iePresence = iePresence; + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Cannot update IE info for type %u and instance %u. IE info does not exist!", ieType, ieInstance); + } + + + return NW_OK; +} + + + +NwRcT +nwGtpv2cMsgParserRun( NW_IN NwGtpv2cMsgParserT *thiz, + NW_IN NwGtpv2cMsgHandleT hMsg, + NW_OUT NwU8T *pOffendingIeType, + NW_OUT NwU8T *pOffendingIeInstance, + NW_OUT NwU16T *pOffendingIeLength) +{ + NwRcT rc = NW_OK; + NwU8T flags; + NwU16T mandatoryIeCount =0; + NwGtpv2cIeTlvT *pIe; + NwU8T *pIeStart; + NwU8T *pIeEnd; + NwU16T ieLength; + NwGtpv2cMsgT *pMsg = (NwGtpv2cMsgT*) hMsg; + + NW_ASSERT(pMsg); + flags = *((NwU8T*)(pMsg->msgBuf)); + pIeStart = (NwU8T *) (pMsg->msgBuf + (flags & 0x08 ? 12: 8)); + pIeEnd = (NwU8T *) (pMsg->msgBuf + pMsg->msgLen); + + memset(thiz->pIe, 0, sizeof(NwU8T*) * (NW_GTPV2C_IE_TYPE_MAXIMUM) * (NW_GTPV2C_IE_INSTANCE_MAXIMUM)); + memset(pMsg->pIe, 0, sizeof(NwU8T*) * (NW_GTPV2C_IE_TYPE_MAXIMUM) * (NW_GTPV2C_IE_INSTANCE_MAXIMUM)); + + while (pIeStart < pIeEnd) + { + pIe = (NwGtpv2cIeTlvT*) pIeStart; + ieLength = ntohs(pIe->l); + + if(pIeStart + 4 + ieLength > pIeEnd) + { + *pOffendingIeType = pIe->t; + *pOffendingIeLength = pIe->l; + *pOffendingIeInstance = pIe->i; + return NW_GTPV2C_MSG_MALFORMED; + } + + if((thiz->ieParseInfo[pIe->t][pIe->i].iePresence)) + { + thiz->pIe[pIe->t][pIe->i] = (NwU8T*) pIeStart; + pMsg->pIe[pIe->t][pIe->i] = (NwU8T*) pIeStart; + + NW_LOG(thiz->hStack, NW_LOG_LEVEL_DEBG, "Received IE %u of length %u!", pIe->t, ieLength); + if((thiz->ieParseInfo[pIe->t][pIe->i].ieReadCallback) != NULL ) + { + rc = thiz->ieParseInfo[pIe->t][pIe->i].ieReadCallback(pIe->t, ieLength, pIe->i, pIeStart + 4, thiz->ieParseInfo[pIe->t][pIe->i].ieReadCallbackArg); + + if(NW_OK == rc) + { + if(thiz->ieParseInfo[pIe->t][pIe->i].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + mandatoryIeCount++; + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Error while parsing IE %u with instance %u and length %u!", pIe->t, pIe->i, ieLength); + break; + } + } + else + { + if((thiz->ieReadCallback) != NULL ) + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_DEBG, "Received IE %u of length %u!", pIe->t, ieLength); + rc = thiz->ieReadCallback(pIe->t, ieLength, pIe->i, pIeStart + 4, thiz->ieReadCallbackArg); + + if(NW_OK == rc) + { + if(thiz->ieParseInfo[pIe->t][pIe->i].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + mandatoryIeCount++; + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_ERRO, "Error while parsing IE %u of length %u!", pIe->t, ieLength); + break; + } + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_WARN, "No parse method defined for received IE type %u of length %u in message %u!", pIe->t, ieLength, thiz->msgType); + } + } + } + else + { + NW_LOG(thiz->hStack, NW_LOG_LEVEL_WARN, "Unexpected IE %u of length %u received in msg %u!", pIe->t, ieLength, thiz->msgType); + } + + pIeStart += (ieLength + 4); + } + + if((NW_OK == rc) && (mandatoryIeCount != thiz->mandatoryIeCount)) + { + NwU16T t, i; + *pOffendingIeType = 0; + *pOffendingIeInstance = 0; + *pOffendingIeLength = 0; + for(t = 0; t < NW_GTPV2C_IE_TYPE_MAXIMUM; t++) + { + for(i = 0; i < NW_GTPV2C_IE_INSTANCE_MAXIMUM; i++) + { + if(thiz->ieParseInfo[t][i].iePresence == NW_GTPV2C_IE_PRESENCE_MANDATORY) + { + if(thiz->pIe[t][i] == NULL) + { + *pOffendingIeType = t; + *pOffendingIeInstance = i; + return NW_GTPV2C_MANDATORY_IE_MISSING; + } + } + } + } + NW_LOG(thiz->hStack, NW_LOG_LEVEL_WARN, "Unknown mandatory IE missing. Parser formed incorrectly! %u:%u", mandatoryIeCount, thiz->mandatoryIeCount); + return NW_GTPV2C_MANDATORY_IE_MISSING; + } + + return rc; +} + +#ifdef __cplusplus +} +#endif + + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTrxn.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTrxn.c new file mode 100644 index 0000000000..c5a9ebdaaa --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTrxn.c @@ -0,0 +1,405 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwLog.h" +#include "NwUtils.h" +#include "NwGtpv2cLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2cTrxn.h" + +/*--------------------------------------------------------------------------* + * P R I V A T E D E C L A R A T I O N S * + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +static NwGtpv2cTrxnT* gpGtpv2cTrxnPool = NULL; + +/*--------------------------------------------------------------------------* + * P R I V A T E F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------- + * Send msg retransmission to peer via data request to UDP Entity + *--------------------------------------------------------------------------*/ + +static NwRcT +nwGtpv2cTrxnSendMsgRetransmission(NwGtpv2cTrxnT* thiz) +{ + NwRcT rc ; + + NW_ASSERT(thiz); + + NW_ASSERT(thiz->pMsg); + + rc = thiz->pStack->udp.udpDataReqCallback(thiz->pStack->udp.hUdp, + thiz->pMsg->msgBuf, + thiz->pMsg->msgLen, + thiz->peerIp, + thiz->peerPort); + + thiz->maxRetries--; + + return rc; +} + +static NwRcT +nwGtpv2cTrxnPeerRspWaitTimeout(void* arg) +{ + NwRcT rc = NW_OK; + NwGtpv2cTrxnT* thiz; + NwGtpv2cStackT* pStack; + + thiz = ((NwGtpv2cTrxnT*)arg); + pStack = thiz->pStack; + + NW_ASSERT(pStack); + + NW_LOG(pStack, NW_LOG_LEVEL_WARN, "T3 Response timer expired for transaction 0x%p", + thiz); + + thiz->hRspTmr = 0; + + if(thiz->maxRetries) + { + rc = nwGtpv2cTrxnSendMsgRetransmission(thiz); + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cStartTimer(thiz->pStack, thiz->t3Timer, 0, NW_GTPV2C_TMR_TYPE_ONE_SHOT, nwGtpv2cTrxnPeerRspWaitTimeout, thiz, &thiz->hRspTmr); + } + else + { + NwGtpv2cUlpApiT ulpApi; + + ulpApi.hMsg = 0; + ulpApi.apiType = NW_GTPV2C_ULP_API_RSP_FAILURE_IND; + + ulpApi.apiInfo.rspFailureInfo.hUlpTrxn = thiz->hUlpTrxn; + ulpApi.apiInfo.rspFailureInfo.hUlpTunnel = ( (thiz->hTunnel) ? ((NwGtpv2cTunnelT*)(thiz->hTunnel))->hUlpTunnel : 0 ); + + NW_LOG(pStack, NW_LOG_LEVEL_ERRO, "N3 retries expired for transaction 0x%p", + thiz); + RB_REMOVE(NwGtpv2cOutstandingTxSeqNumTrxnMap, &(pStack->outstandingTxSeqNumMap), thiz); + rc = nwGtpv2cTrxnDelete(&thiz); + + rc = pStack->ulp.ulpReqCallback(pStack->ulp.hUlp, &ulpApi); + } + return rc; +} + +static NwRcT +nwGtpv2cTrxnDuplicateRequestWaitTimeout(void* arg) +{ + NwRcT rc = NW_OK; + NwGtpv2cTrxnT* thiz; + NwGtpv2cStackT* pStack; + + thiz = ((NwGtpv2cTrxnT*)arg); + + NW_ASSERT(thiz); + pStack = thiz->pStack; + + NW_ASSERT(pStack); + + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Duplicate request hold timer expired for transaction 0x%p", + thiz); + + thiz->hRspTmr = 0; + + RB_REMOVE(NwGtpv2cOutstandingRxSeqNumTrxnMap, &(pStack->outstandingRxSeqNumMap), thiz); + rc = nwGtpv2cTrxnDelete(&thiz); + NW_ASSERT(NW_OK == rc); + + return rc; +} + +/** + * Start timer to wait for rsp of a req message + * + * @param[in] thiz : Pointer to transaction + * @param[in] timeoutCallbackFunc : Timeout handler callback function. + * @return NW_OK on success. + */ + +NwRcT +nwGtpv2cTrxnStartPeerRspWaitTimer(NwGtpv2cTrxnT* thiz) +{ + NwRcT rc; + rc = nwGtpv2cStartTimer(thiz->pStack, thiz->t3Timer, 0, NW_GTPV2C_TMR_TYPE_ONE_SHOT, nwGtpv2cTrxnPeerRspWaitTimeout, thiz, &thiz->hRspTmr); + return rc; +} + +/** + Start timer to wait before pruginf a req tran for which response has been sent + + @param[in] thiz : Pointer to transaction + @return NW_OK on success. + */ + +NwRcT +nwGtpv2cTrxnStartDulpicateRequestWaitTimer(NwGtpv2cTrxnT* thiz) +{ + NwRcT rc; + + rc = nwGtpv2cStartTimer(thiz->pStack, thiz->t3Timer * thiz->maxRetries, 0, NW_GTPV2C_TMR_TYPE_ONE_SHOT, nwGtpv2cTrxnDuplicateRequestWaitTimeout, thiz, &thiz->hRspTmr); + + return rc; +} + +/** + Send timer stop request to TmrMgr Entity. + + @param[in] thiz : Pointer to transaction + @return NW_OK on success. + */ + +static NwRcT +nwGtpv2cTrxnStopPeerRspTimer(NwGtpv2cTrxnT* thiz) +{ + NwRcT rc; + + NW_ASSERT(thiz->pStack->tmrMgr.tmrStopCallback != NULL); + + rc = nwGtpv2cStopTimer(thiz->pStack, thiz->hRspTmr); + thiz->hRspTmr = 0; + + return rc; +} + +/*--------------------------------------------------------------------------* + * P U B L I C F U N C T I O N S * + *--------------------------------------------------------------------------*/ + +/** + * Constructor + * + * @param[in] thiz : Pointer to stack + * @param[out] ppTrxn : Pointer to pointer to Trxn object. + * @return NW_OK on success. + */ +NwGtpv2cTrxnT* +nwGtpv2cTrxnNew( NW_IN NwGtpv2cStackT* thiz) +{ + NwGtpv2cTrxnT *pTrxn; + + if(gpGtpv2cTrxnPool) + { + pTrxn = gpGtpv2cTrxnPool; + gpGtpv2cTrxnPool = gpGtpv2cTrxnPool->next; + } + else + { + NW_GTPV2C_MALLOC(thiz, sizeof(NwGtpv2cTrxnT), pTrxn, NwGtpv2cTrxnT*); + } + + if (pTrxn) + { + pTrxn->pStack = thiz; + pTrxn->pMsg = NULL; + pTrxn->maxRetries = 2; + pTrxn->t3Timer = 2; + pTrxn->seqNum = thiz->seqNum; + + /* Increment sequence number */ + thiz->seqNum++; + if(thiz->seqNum == 0x800000) + thiz->seqNum = 0; + + } + + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Created transaction 0x%p", pTrxn); + + return pTrxn; +} + +/** + * Overloaded Constructor + * + * @param[in] thiz : Pointer to stack. + * @param[in] seqNum : Sequence number for this transaction. + * @return Pointer to Trxn object. + */ +NwGtpv2cTrxnT* +nwGtpv2cTrxnWithSeqNumNew( NW_IN NwGtpv2cStackT* thiz, + NW_IN NwU32T seqNum) +{ + NwGtpv2cTrxnT *pTrxn; + + if(gpGtpv2cTrxnPool) + { + pTrxn = gpGtpv2cTrxnPool; + gpGtpv2cTrxnPool = gpGtpv2cTrxnPool->next; + } + else + { + NW_GTPV2C_MALLOC(thiz, sizeof(NwGtpv2cTrxnT), pTrxn, NwGtpv2cTrxnT*); + } + + if (pTrxn) + { + pTrxn->pStack = thiz; + pTrxn->pMsg = NULL; + pTrxn->maxRetries = 2; + pTrxn->t3Timer = 2; + pTrxn->seqNum = seqNum; + pTrxn->pMsg = NULL; + } + + NW_LOG(thiz, NW_LOG_LEVEL_ERRO, "Created transaction 0x%p", pTrxn); + + return pTrxn; +} + +/** + * Another overloaded constructor. Create transaction as outstanding + * RX transaction for detecting duplicated requests. + * + * @param[in] thiz : Pointer to stack. + * @param[in] teidLocal : Trxn teid. + * @param[in] peerIp : Peer Ip address. + * @param[in] peerPort : Peer Ip port. + * @param[in] seqNum : Seq Number. + * @return NW_OK on success. + */ + +NwGtpv2cTrxnT* +nwGtpv2cTrxnOutstandingRxNew( NW_IN NwGtpv2cStackT* thiz, + NW_IN NwU32T teidLocal, + NW_IN NwU32T peerIp, + NW_IN NwU32T peerPort, + NW_IN NwU32T seqNum) +{ + NwRcT rc; + NwGtpv2cTrxnT *pTrxn, *pCollision; + + if(gpGtpv2cTrxnPool) + { + pTrxn = gpGtpv2cTrxnPool; + gpGtpv2cTrxnPool = gpGtpv2cTrxnPool->next; + } + else + { + NW_GTPV2C_MALLOC(thiz, sizeof(NwGtpv2cTrxnT), pTrxn, NwGtpv2cTrxnT*); + } + + if (pTrxn) + { + pTrxn->pStack = thiz; + pTrxn->maxRetries = 2; + pTrxn->t3Timer = 2; + pTrxn->seqNum = seqNum; + pTrxn->peerIp = peerIp; + pTrxn->peerPort = peerPort; + pTrxn->pMsg = NULL; + pTrxn->hRspTmr = 0; + + pCollision = RB_INSERT(NwGtpv2cOutstandingRxSeqNumTrxnMap, &(thiz->outstandingRxSeqNumMap), pTrxn); + + if(pCollision) + { + NW_LOG(thiz, NW_LOG_LEVEL_WARN, "Duplicate request message received for seq num 0x%x!", + (NwU32T) seqNum); + /* Case of duplicate request message from peer. Retransmit response. */ + if(pCollision->pMsg) + { + rc = pCollision->pStack->udp.udpDataReqCallback(pCollision->pStack->udp.hUdp, + pCollision->pMsg->msgBuf, + pCollision->pMsg->msgLen, + pCollision->peerIp, + pCollision->peerPort); + } + + rc = nwGtpv2cTrxnDelete(&pTrxn); + NW_ASSERT(NW_OK == rc); + pTrxn = NULL; + } + } + + if(pTrxn) + NW_LOG(thiz, NW_LOG_LEVEL_DEBG, "Created outstanding RX transaction 0x%p", + pTrxn); + + return (pTrxn); +} + +/** + * Destructor + * + * @param[out] pthiz : Pointer to pointer to Trxn object. + * @return NW_OK on success. + */ +NwRcT +nwGtpv2cTrxnDelete( NW_INOUT NwGtpv2cTrxnT **pthiz) +{ + NwRcT rc = NW_OK; + NwGtpv2cStackT* pStack; + NwGtpv2cTrxnT *thiz = *pthiz; + + pStack = thiz->pStack; + + if(thiz->hRspTmr) + { + rc = nwGtpv2cTrxnStopPeerRspTimer(thiz); + NW_ASSERT(NW_OK == rc); + } + + if(thiz->pMsg) + { + rc = nwGtpv2cMsgDelete((NwGtpv2cStackHandleT)pStack, (NwGtpv2cMsgHandleT)thiz->pMsg); + NW_ASSERT(NW_OK == rc); + } + + NW_LOG(pStack, NW_LOG_LEVEL_DEBG, "Purging transaction 0x%p", thiz); + + thiz->next = gpGtpv2cTrxnPool; + gpGtpv2cTrxnPool = thiz; + + *pthiz = NULL; + return rc; +} + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTunnel.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTunnel.c new file mode 100644 index 0000000000..727ea9d115 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/src/NwGtpv2cTunnel.c @@ -0,0 +1,98 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "NwTypes.h" +#include "NwUtils.h" +#include "NwError.h" +#include "NwGtpv2cPrivate.h" +#include "NwGtpv2cTunnel.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static NwGtpv2cTunnelT* gpGtpv2cTunnelPool = NULL; + +NwGtpv2cTunnelT* +nwGtpv2cTunnelNew(struct NwGtpv2cStack *pStack, NwU32T teid, NwU32T ipv4AddrRemote, NwGtpv2cUlpTunnelHandleT hUlpTunnel) +{ + NwGtpv2cTunnelT* thiz; + + if(gpGtpv2cTunnelPool) + { + thiz = gpGtpv2cTunnelPool; + gpGtpv2cTunnelPool = gpGtpv2cTunnelPool->next; + } + else + { + NW_GTPV2C_MALLOC(pStack, sizeof(NwGtpv2cTunnelT), thiz, NwGtpv2cTunnelT*); + } + + if(thiz) + { + memset(thiz, 0, sizeof(NwGtpv2cTunnelT)); + thiz->teid = teid; + thiz->ipv4AddrRemote = ipv4AddrRemote; + thiz->hUlpTunnel = hUlpTunnel; + } + return thiz; +} + +NwRcT +nwGtpv2cTunnelDelete(struct NwGtpv2cStack *pStack, NwGtpv2cTunnelT* thiz) +{ + thiz->next = gpGtpv2cTunnelPool; + gpGtpv2cTunnelPool = thiz; + + return NW_OK; +} + +NwRcT +nwGtpv2cTunnelGetUlpTunnelHandle( NwGtpv2cTunnelT* thiz, NwGtpv2cUlpTunnelHandleT* phUlpTunnel) +{ + *phUlpTunnel = (thiz? thiz->hUlpTunnel : 0x00000000); + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + +/*--------------------------------------------------------------------------* + * E N D O F F I L E * + *--------------------------------------------------------------------------*/ + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/Makefile.am b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/Makefile.am new file mode 100644 index 0000000000..da32172d9a --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/Makefile.am @@ -0,0 +1,6 @@ +# this is example-file: Makefile.am + +# the subdirectories of the project to go into +SUBDIRS = \ + nw-egtping\ + nw-helloworld diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/Makefile.am b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/Makefile.am new file mode 100644 index 0000000000..3674445989 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/Makefile.am @@ -0,0 +1,24 @@ +AM_CFLAGS = -D__WITH_LIBEVENT__ \ + -I$(top_srcdir)/shared \ + -I$(top_srcdir)/include \ + -I$(top_srcdir)/test-app/nw-udp \ + -I$(top_srcdir)/test-app/nw-log \ + @AM_CFLAGS@ + +if ENABLE_TESTS_APP +bin_PROGRAMS = egtping + +egtping_SOURCES = \ + NwEvt.h\ + NwMiniLogMgrEntity.h\ + NwMiniTmrMgrEntity.h\ + NwMiniUlpEntity.h\ + NwMiniUdpEntity.h\ + NwMiniLogMgrEntity.c\ + NwMiniTmrMgrEntity.c\ + NwMiniUlpEntity.c\ + NwMiniUdpEntity.c\ + NwEgtPingMain.c + +egtping_LDADD = $(top_builddir)/src/libNwGtpv2c.a -levent $(AM_LDFLAGS) +endif \ No newline at end of file diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEgtPingMain.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEgtPingMain.c new file mode 100644 index 0000000000..8a0638be33 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEgtPingMain.c @@ -0,0 +1,290 @@ +/*----------------------------------------------------------------------------* + * Copyright (C) 2010 Amit Chawre. * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwEgtPingMain.c + * @brief This is a program demostrating usage of nw-gtpv2c library for eGTP ping. +*/ + +#include <stdio.h> +#include <assert.h> +#include <signal.h> +#include <string.h> +#include "NwEvt.h" +#include "NwLog.h" +#include "NwGtpv2c.h" + +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" +#include "NwMiniUdpEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + + +typedef struct NwEgtPingS +{ + NwU8T localIpStr[20]; + NwU8T targetIpStr[20]; + NwU32T pingInterval; + NwU32T pingCount; + NwGtpv2cNodeUlpT ulpObj; + NwGtpv2cNodeUdpT udpObj; +} NwEgtPingT; + +static NwGtpv2cNodeUlpT ulpObj; +static NwGtpv2cNodeUdpT udpObj; + +static NwEgtPingT egtPing; + +void nwEgtPingHandleSignal(int sigNum) +{ + printf("\n--- %s ("NW_IPV4_ADDR") EGTPING statistics --- ", egtPing.targetIpStr, NW_IPV4_ADDR_FORMAT(inet_addr(egtPing.targetIpStr))); + printf("\n%u requests sent, %u response received, %d%% packet loss \n\n", udpObj.packetsSent, udpObj.packetsRcvd, (udpObj.packetsSent ? 100 * (udpObj.packetsSent - udpObj.packetsRcvd ) / udpObj.packetsSent : 0) ); + exit(sigNum); +} + +NwRcT +nwEgtPingHelp() +{ + printf("Usage: egtping [-i interval] [-c count] [-l local-ip] "); + printf("\n [-t3 t3-time] [-n3 n3-count] destination"); + printf("\n"); + printf("\n -i <interval> : Interval between two echo request messages. (Default: 1 sec)"); + printf("\n -c <count> : Stop after sending count pings. (Default: Infinite)"); + printf("\n -t <t3-time> : GTP T3 timeout value. (Default: 2 sec)"); + printf("\n -n <n3-count> : GTP N3 count value. (Default: 2 sec)"); + printf("\n -l <local-ip> : Local IP adddress to use. (Default: All local IPs)"); + printf("\n -h : Show this message."); + printf("\n"); + printf("\n"); +} + +NwRcT +nwEgtPingParseCmdLineOpts(int argc, char* argv[]) +{ + NwRcT rc = NW_OK; + int i = 0; + i++; + + egtPing.pingInterval = 1; + egtPing.pingCount = 0xffffffff; + + if(argc < 2) + return NW_FAILURE; + + if( (argc == 2) && + ((strcmp("--help", argv[i]) == 0) + || (strcmp(argv[i], "-h") == 0))) + return NW_FAILURE; + + while( i < argc - 1) + { + NW_LOG(NW_LOG_LEVEL_DEBG, "Processing cmdline arg %s", argv[i]); + if((strcmp("--local-ip", argv[i]) == 0) + || (strcmp(argv[i], "-l") == 0)) + { + i++; + if(i >= (argc - 1)) + return NW_FAILURE; + + strcpy(egtPing.localIpStr, (argv[i])); + + } + else if((strcmp("--interval", argv[i]) == 0) + || (strcmp(argv[i], "-i") == 0)) + { + i++; + if(i >= (argc - 1)) + return NW_FAILURE; + + egtPing.pingInterval = atoi(argv[i]); + + } + else if((strcmp("--count", argv[i]) == 0) + || (strcmp(argv[i], "-c") == 0)) + { + i++; + if(i >= (argc - 1)) + return NW_FAILURE; + + egtPing.pingCount = atoi(argv[i]); + } + else if((strcmp("--help", argv[i]) == 0) + || (strcmp(argv[i], "-h") == 0)) + { + rc = NW_FAILURE; + } + else + { + return NW_FAILURE; + } + i++; + } + + strcpy(egtPing.targetIpStr, (argv[i])); + + return rc; +} + +/*--------------------------------------------------------------------------- + * T H E M A I N F U N C T I O N + *--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + NwRcT rc; + NwU32T logLevel; + NwU8T* logLevelStr; + + NwGtpv2cStackHandleT hGtpv2cStack = 0; + + NwGtpv2cUlpEntityT ulp; + NwGtpv2cUdpEntityT udp; + NwGtpv2cTimerMgrEntityT tmrMgr; + NwGtpv2cLogMgrEntityT logMgr; + + printf("EGTPING 0.1, Copyright (C) 2011 Amit Chawre.\n"); + rc = nwEgtPingParseCmdLineOpts(argc, argv); + + if(rc != NW_OK) + { + rc = nwEgtPingHelp(); + exit(rc); + } + + logLevelStr = getenv ("NW_LOG_LEVEL"); + + if(logLevelStr == NULL) + { + logLevel = NW_LOG_LEVEL_INFO; + } + else + { + if(strncmp(logLevelStr, "EMER",4) == 0) + logLevel = NW_LOG_LEVEL_EMER; + else if(strncmp(logLevelStr, "ALER",4) == 0) + logLevel = NW_LOG_LEVEL_ALER; + else if(strncmp(logLevelStr, "CRIT",4) == 0) + logLevel = NW_LOG_LEVEL_CRIT; + else if(strncmp(logLevelStr, "ERRO",4) == 0) + logLevel = NW_LOG_LEVEL_ERRO ; + else if(strncmp(logLevelStr, "WARN",4) == 0) + logLevel = NW_LOG_LEVEL_WARN; + else if(strncmp(logLevelStr, "NOTI",4) == 0) + logLevel = NW_LOG_LEVEL_NOTI; + else if(strncmp(logLevelStr, "INFO",4) == 0) + logLevel = NW_LOG_LEVEL_INFO; + else if(strncmp(logLevelStr, "DEBG",4) == 0) + logLevel = NW_LOG_LEVEL_DEBG; + } + + /*--------------------------------------------------------------------------- + * Initialize event library + *--------------------------------------------------------------------------*/ + + NW_EVT_INIT(); + + /*--------------------------------------------------------------------------- + * Initialize Log Manager + *--------------------------------------------------------------------------*/ + nwMiniLogMgrInit(nwMiniLogMgrGetInstance(), logLevel); + + /*--------------------------------------------------------------------------- + * Initialize Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cInitialize(&hGtpv2cStack); + + if(rc != NW_OK) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Failed to create gtpv2c stack instance. Error '%u' occured", rc); + exit(1); + } + + rc = nwGtpv2cSetLogLevel(hGtpv2cStack, logLevel); + + /*--------------------------------------------------------------------------- + * Set up Ulp Entity + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cUlpInit(&ulpObj, hGtpv2cStack, egtPing.localIpStr); + NW_ASSERT(NW_OK == rc); + + ulp.hUlp = (NwGtpv2cUlpHandleT) &ulpObj; + ulp.ulpReqCallback = nwGtpv2cUlpProcessStackReqCallback; + + rc = nwGtpv2cSetUlpEntity(hGtpv2cStack, &ulp); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Udp Entity + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cUdpInit(&udpObj, hGtpv2cStack, egtPing.localIpStr); + NW_ASSERT(NW_OK == rc); + + udp.hUdp = (NwGtpv2cUdpHandleT) &udpObj; + udp.udpDataReqCallback = nwGtpv2cUdpDataReq; + + rc = nwGtpv2cSetUdpEntity(hGtpv2cStack, &udp); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + tmrMgr.tmrMgrHandle = 0; + tmrMgr.tmrStartCallback = nwTimerStart; + tmrMgr.tmrStopCallback = nwTimerStop; + + rc = nwGtpv2cSetTimerMgrEntity(hGtpv2cStack, &tmrMgr); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + logMgr.logMgrHandle = (NwGtpv2cLogMgrHandleT) nwMiniLogMgrGetInstance(); + logMgr.logReqCallback = nwMiniLogMgrLogRequest; + + rc = nwGtpv2cSetLogMgrEntity(hGtpv2cStack, &logMgr); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Send Message Request to Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + NW_LOG(NW_LOG_LEVEL_NOTI, "EGTPING %s ("NW_IPV4_ADDR")", egtPing.targetIpStr, NW_IPV4_ADDR_FORMAT(inet_addr(egtPing.targetIpStr))); + rc = nwGtpv2cUlpPing(&ulpObj, + inet_addr(egtPing.targetIpStr), + egtPing.pingCount, + egtPing.pingInterval, + 2, + 3); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Install signal handler + *--------------------------------------------------------------------------*/ + signal(SIGINT, nwEgtPingHandleSignal); + + /*--------------------------------------------------------------------------- + * Event loop + *--------------------------------------------------------------------------*/ + + NW_EVT_LOOP(); + NW_LOG(NW_LOG_LEVEL_ERRO, "Exit from eventloop, no events to process!"); + + /*--------------------------------------------------------------------------- + * Destroy Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cFinalize(hGtpv2cStack); + if(rc != NW_OK) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Failed to finalize gtpv2c stack instance. Error '%u' occured", rc); + } + + return rc; +} diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEvt.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEvt.h new file mode 100644 index 0000000000..da02372e2a --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwEvt.h @@ -0,0 +1,81 @@ +/*----------------------------------------------------------------------------* + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_EVT_H__ +#define __NW_EVT_H__ +/** + * @file NwEvt.h + * @brief +*/ + +#ifdef __WITH_LIBEVENT__ + +#include <event.h> + +typedef struct event NwEventT; + +#define NW_EVT_READ (EV_READ) +#define NW_EVT_PERSIST (EV_PERSIST) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) + +#define NW_EVT_INIT event_init +#define NW_EVT_LOOP event_dispatch + +#define NW_EVENT_ADD(__ev, __evSelObj, __evCallback, __evCallbackArg, __evFlags) \ + do { \ + event_set(&(__ev), __evSelObj, __evFlags, __evCallback, __evCallbackArg); \ + event_add(&(__ev), NULL); \ + } while(0) + +#else + +#warning "Event library not defined!" + +/* HACK : Defining dummy values for compilation!*/ + +typedef struct +{ + int __tbd; +} NwEventT; + +#define NW_EVT_READ (0) +#define NW_EVT_PERSIST (1) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(void *arg) + + +#define NW_EVT_INIT() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVT_LOOP() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVENT_ADD(...) do { printf("error: Event library not defined!\n"); exit (0); } while(0) + + +#endif + +#endif /* __NW_EVT_H__ */ diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.c new file mode 100644 index 0000000000..693e17997b --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.c @@ -0,0 +1,69 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwTypes.h" +#include "NwError.h" +#include "NwLog.h" +#include "NwGtpv2c.h" + +#include "NwMiniLogMgrEntity.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +NwMiniLogMgrT __gLogMgr; + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwMiniLogMgrT* nwMiniLogMgrGetInstance() +{ + return &(__gLogMgr); +} + +NwRcT nwMiniLogMgrInit(NwMiniLogMgrT* thiz, NwU32T logLevel ) +{ + thiz->logLevel = logLevel; + return NW_OK; +} + +NwRcT nwMiniLogMgrSetLogLevel(NwMiniLogMgrT* thiz, NwU32T logLevel) +{ + thiz->logLevel = logLevel; +} + +NwRcT nwMiniLogMgrLogRequest (NwGtpv2cLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr) +{ + NwMiniLogMgrT* thiz = (NwMiniLogMgrT*) hLogMgr; + if(thiz->logLevel >= logLevel) + //printf("NWEGTPSTK %s - %s <%s,%u>\n", gLogLevelStr[logLevel], logStr, basename(file), line); + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.h new file mode 100644 index 0000000000..62324e10f3 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniLogMgrEntity.h @@ -0,0 +1,90 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_LOG_MGR_H__ +#define __NW_MINI_LOG_MGR_H__ + +#define NW_LOG( _logLevel, ...) \ + do { \ + if((nwMiniLogMgrGetInstance())->logLevel >= _logLevel) \ + { \ + char _logStr[1024]; \ + snprintf(_logStr, 1024, __VA_ARGS__); \ + printf("%s \n", _logStr);\ + } \ + } while(0) + +/** + * MiniLogMgr Class Definition + */ +typedef struct NwMiniLogMgr +{ + NwU8T logLevel; /*< Log level */ +} NwMiniLogMgrT; + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get global singleton MiniLogMgr instance + */ +NwMiniLogMgrT* nwMiniLogMgrGetInstance(); + +/** + * Initialize MiniLogMgr + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + */ +NwRcT nwMiniLogMgrInit(NwMiniLogMgrT* thiz, NwU32T logLevel ); + +/** + * Set MiniLogMgr log level + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + */ +NwRcT nwMiniLogMgrSetLogLevel(NwMiniLogMgrT* thiz, NwU32T logLevel); + +/** + * Process log request from stack + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + * @param file : Filename + * @param line : Line Number + * @param logStr : Log string + */ +NwRcT nwMiniLogMgrLogRequest (NwGtpv2cLogMgrHandleT logMgrHandle, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.c new file mode 100644 index 0000000000..5501fcd5a7 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.c @@ -0,0 +1,97 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static void +NW_TMR_CALLBACK(nwGtpv2cNodeHandleStackTimerTimeout) +{ + NwRcT rc; + NwGtpv2cNodeTmrT *pTmr = (NwGtpv2cNodeTmrT*) arg; + + /* + * Send Timeout Request to Gtpv2c Stack Instance + */ + rc = nwGtpv2cProcessTimeout(pTmr->timeoutArg); + NW_ASSERT(NW_OK == rc); + + free(pTmr); + + return; +} + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwRcT nwTimerStart( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void* timeoutArg, + NwGtpv2cTimerHandleT* hTmr) +{ + NwRcT rc = NW_OK; + NwGtpv2cNodeTmrT *pTmr; + struct timeval tv; + + pTmr = (NwGtpv2cNodeTmrT*) malloc(sizeof(NwGtpv2cNodeTmrT)); + + /* set the timevalues*/ + timerclear(&tv); + tv.tv_sec = timeoutSec; + tv.tv_usec = timeoutUsec; + + pTmr->timeoutArg = timeoutArg; + evtimer_set(&pTmr->ev, nwGtpv2cNodeHandleStackTimerTimeout, pTmr); + + /*add event*/ + + event_add(&(pTmr->ev), &tv); + + *hTmr = (NwGtpv2cTimerHandleT)pTmr; + + return rc; +} + +NwRcT nwTimerStop( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT hTmr) +{ + evtimer_del(&(((NwGtpv2cNodeTmrT*)hTmr)->ev)); + free((void*)hTmr); + return NW_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.h new file mode 100644 index 0000000000..5f1ea1254c --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniTmrMgrEntity.h @@ -0,0 +1,59 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_TMR_MGR_H__ +#define __NW_MINI_TMR_MGR_H__ + +typedef struct +{ + NwU8T _tbd; +} NwGtpv2cNodeTmrMgrT; + +typedef struct +{ + NwEventT ev; + void* timeoutArg; +} NwGtpv2cNodeTmrT; + + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT nwTimerStart( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void* timeoutArg, + NwGtpv2cTimerHandleT* hTmr); + + +NwRcT nwTimerStop( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT hTmr); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.c new file mode 100644 index 0000000000..c203523241 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.c @@ -0,0 +1,225 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUdpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#define MAX_UDP_PAYLOAD_LEN (4096) + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +static int yes = 1; +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static +void NW_EVT_CALLBACK(nwUdpDataIndicationCallbackData) +{ + NwRcT rc; + NwU8T udpBuf[MAX_UDP_PAYLOAD_LEN]; + NwS32T bytesRead; + struct sockaddr_in peer; + NwU32T peerLen; + NwGtpv2cNodeUdpT* thiz = (NwGtpv2cNodeUdpT*) arg; + + peerLen = sizeof(peer); + + bytesRead = recvfrom(fd, udpBuf, MAX_UDP_PAYLOAD_LEN , 0, (struct sockaddr *) &peer,(socklen_t*) &peerLen); + if(bytesRead > 0) + { + thiz->packetsRcvd++; + NW_LOG(NW_LOG_LEVEL_DEBG, "Received UDP message of size %u from peer %u.%u.%u.%u:%u", bytesRead, + (peer.sin_addr.s_addr & 0x000000ff), + (peer.sin_addr.s_addr & 0x0000ff00) >> 8, + (peer.sin_addr.s_addr & 0x00ff0000) >> 16, + (peer.sin_addr.s_addr & 0xff000000) >> 24, + ntohs(peer.sin_port)); + rc = nwGtpv2cProcessUdpReq(thiz->hGtpv2cStack, udpBuf, bytesRead, ntohs(peer.sin_port), ntohl(peer.sin_addr.s_addr)); + } + else + { + switch (errno) + { + + case ENETUNREACH: + NW_LOG(NW_LOG_LEVEL_ERRO, "Network not reachable", errno, strerror(errno)); + break; + + case EHOSTUNREACH: + NW_LOG(NW_LOG_LEVEL_ERRO, "Host not reachable", errno, strerror(errno)); + break; + + case ECONNREFUSED: + NW_LOG(NW_LOG_LEVEL_ERRO, "Port not reachable", errno, strerror(errno)); + break; + + default: + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + } + nwGtpv2cUdpReset(thiz); + } + return; +} + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwRcT nwGtpv2cUdpInit(NwGtpv2cNodeUdpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, NwU8T* ipAddrStr) +{ + int sd; + struct sockaddr_in addr; + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(2123); + addr.sin_addr.s_addr = (strlen(ipAddrStr) ? inet_addr(ipAddrStr) : INADDR_ANY); + memset(addr.sin_zero, '\0', sizeof (addr.sin_zero)); + + if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Error - %s", strerror(errno)); + NW_ASSERT(0); + } + + yes = 1; + if (setsockopt(sd, SOL_IP, IP_RECVERR, &yes, sizeof(yes))) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + NW_EVENT_ADD((thiz->ev), sd, nwUdpDataIndicationCallbackData, thiz, NW_EVT_READ | NW_EVT_PERSIST); + + thiz->ipv4Addr = addr.sin_addr.s_addr; + thiz->hSocket = sd; + thiz->hGtpv2cStack = hGtpv2cStack; + + return NW_OK; +} + +NwRcT nwGtpv2cUdpDestroy(NwGtpv2cNodeUdpT* thiz) +{ + close(thiz->hSocket); +} + +NwRcT nwGtpv2cUdpReset(NwGtpv2cNodeUdpT* thiz) +{ + int sd; + struct sockaddr_in addr; + + event_del(&thiz->ev); + close(thiz->hSocket); + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(2123); + addr.sin_addr.s_addr = (thiz->ipv4Addr); + memset(addr.sin_zero, '\0', sizeof (addr.sin_zero)); + + if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + yes = 1; + if (setsockopt(sd, SOL_IP, IP_RECVERR, &yes, sizeof(yes))) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + NW_EVENT_ADD((thiz->ev), sd, nwUdpDataIndicationCallbackData, thiz, (NW_EVT_READ | NW_EVT_PERSIST)); + + thiz->hSocket = sd; + + return NW_OK; +} + +NwRcT nwGtpv2cUdpDataReq(NwGtpv2cUdpHandleT udpHandle, + NwU8T* dataBuf, + NwU32T dataSize, + NwU32T peerIp, + NwU32T peerPort) +{ + struct sockaddr_in peerAddr; + NwS32T bytesSent; + NwGtpv2cNodeUdpT* thiz = (NwGtpv2cNodeUdpT*) udpHandle; + + NW_LOG(NW_LOG_LEVEL_DEBG, "Sending %u bytes of data to %u.%u.%u.%u:%u", dataSize, + (peerIp & 0xff000000) >> 24, + (peerIp & 0x00ff0000) >> 16, + (peerIp & 0x0000ff00) >> 8, + (peerIp & 0x000000ff), + peerPort); + + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(peerPort); + peerAddr.sin_addr.s_addr = htonl(peerIp); + memset(peerAddr.sin_zero, '\0', sizeof (peerAddr.sin_zero)); + + bytesSent = sendto (thiz->hSocket, dataBuf, dataSize, 0, (struct sockaddr *) &peerAddr, sizeof(peerAddr)); + if(bytesSent < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "sendto - %s", strerror(errno)); + } + else + { + thiz->packetsSent++; + } + + return NW_OK; +} + + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.h new file mode 100644 index 0000000000..53a260f194 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUdpEntity.h @@ -0,0 +1,57 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_UDP_ENTITY_H__ +#define __NW_MINI_UDP_ENTITY_H__ + +typedef struct +{ + NwU32T ipv4Addr; + NwU32T hSocket; + NwEventT ev; + NwGtpv2cStackHandleT hGtpv2cStack; + NwU32T packetsSent; + NwU32T packetsRcvd; +} NwGtpv2cNodeUdpT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT nwGtpv2cUdpInit(NwGtpv2cNodeUdpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, NwU8T* ipAddrStr); + +NwRcT nwGtpv2cUdpDestroy(NwGtpv2cNodeUdpT* thiz); + +NwRcT nwGtpv2cUdpDataReq(NwGtpv2cUdpHandleT udpHandle, + NwU8T* dataBuf, + NwU32T dataSize, + NwU32T peerIp, + NwU32T peerPort); + +NwRcT nwGtpv2cUdpReset(NwGtpv2cNodeUdpT* thiz); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.c new file mode 100644 index 0000000000..563cc265ce --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.c @@ -0,0 +1,222 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/time.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * Public Functions + *--------------------------------------------------------------------------*/ + +NwRcT +nwGtpv2cUlpInit(NwGtpv2cNodeUlpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, char* peerIpStr) +{ + NwRcT rc; + thiz->hGtpv2cStack = hGtpv2cStack; + strcpy(thiz->peerIpStr, peerIpStr); + return NW_OK; +} + +NwRcT +nwGtpv2cUlpDestroy(NwGtpv2cNodeUlpT* thiz) +{ + NW_ASSERT(thiz); + memset(thiz, 0, sizeof(NwGtpv2cNodeUlpT)); + return NW_OK; +} + +typedef struct NwGtpv2cPeerS +{ + NwU32T ipv4Addr; + NwU32T pingCount; + NwU32T pingInterval; + NwU32T t3Time; + NwU32T n3Count; + + NwU32T sendTimeStamp; + NwGtpv2cTunnelHandleT hTunnel; +} NwGtpv2cPeerT; + +NwGtpv2cPeerT* +nwGtpv2cUlpCreatePeerContext(NwGtpv2cNodeUlpT* thiz, NwU32T peerIp) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulpReq; + NwGtpv2cPeerT *pPeer = (NwGtpv2cPeerT*) malloc(sizeof(NwGtpv2cPeerT)); + + if(pPeer) + { + pPeer->ipv4Addr = peerIp; + + /* + * Send Message Request to Gtpv2c Stack Instance + */ + + ulpReq.apiType = NW_GTPV2C_ULP_CREATE_LOCAL_TUNNEL; + + ulpReq.apiInfo.createLocalTunnelInfo.hTunnel = 0; + ulpReq.apiInfo.createLocalTunnelInfo.hUlpTunnel = (NwGtpv2cUlpTrxnHandleT)thiz; + ulpReq.apiInfo.createLocalTunnelInfo.teidLocal = (NwGtpv2cUlpTrxnHandleT)0; + ulpReq.apiInfo.createLocalTunnelInfo.peerIp = htonl(peerIp); + + rc = nwGtpv2cProcessUlpReq(thiz->hGtpv2cStack, &ulpReq); + NW_ASSERT(NW_OK == rc); + pPeer->hTunnel = ulpReq.apiInfo.createLocalTunnelInfo.hTunnel; + } + return pPeer; + +} + +NwRcT +nwGtpv2cUlpSendEchoRequestToPeer(NwGtpv2cNodeUlpT* thiz, NwGtpv2cPeerT *pPeer) +{ + NwRcT rc; + struct timeval tv; + NwGtpv2cUlpApiT ulpReq; + /* + * Send Message Request to Gtpv2c Stack Instance + */ + + ulpReq.apiType = NW_GTPV2C_ULP_API_INITIAL_REQ; + + ulpReq.apiInfo.initialReqInfo.hTunnel = pPeer->hTunnel; + ulpReq.apiInfo.initialReqInfo.hUlpTrxn = (NwGtpv2cUlpTrxnHandleT)pPeer; + ulpReq.apiInfo.initialReqInfo.hUlpTunnel = (NwGtpv2cUlpTunnelHandleT)pPeer; + + rc = nwGtpv2cMsgNew( thiz->hGtpv2cStack, + NW_FALSE, + NW_GTP_ECHO_REQ, + 0, + 0, + &(ulpReq.hMsg)); + + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgAddIeTV1((ulpReq.hMsg), NW_GTPV2C_IE_RECOVERY, 0, thiz->restartCounter); + NW_ASSERT(NW_OK == rc); + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + pPeer->sendTimeStamp = (tv.tv_sec * 1000000) + tv.tv_usec; + + rc = nwGtpv2cProcessUlpReq(thiz->hGtpv2cStack, &ulpReq); + NW_ASSERT(NW_OK == rc); + + return NW_OK; +} + +NwRcT +nwGtpv2cUlpPing(NwGtpv2cNodeUlpT* thiz, + NwU32T peerIp, + NwU32T pingCount, + NwU32T pingInterval, + NwU32T t3Time, + NwU32T n3Count) +{ + NwRcT rc; + NwGtpv2cPeerT *pPeer; + NwGtpv2cUlpApiT ulpReq; + + pPeer = nwGtpv2cUlpCreatePeerContext(thiz, peerIp); + + pPeer->pingCount = pingCount; + pPeer->pingInterval = pingInterval; + pPeer->t3Time = t3Time; + pPeer->n3Count = n3Count; + /* + * Send Echo Request to peer + */ + + rc = nwGtpv2cUlpSendEchoRequestToPeer(thiz, pPeer); + + return rc; +} + +NwRcT +nwGtpv2cUlpProcessStackReqCallback (NwGtpv2cUlpHandleT hUlp, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc; + NwU32T seqNum; + NwU32T len; + NwU32T recvTimeStamp; + struct timeval tv; + NwGtpv2cPeerT *pPeer; + NwGtpv2cNodeUlpT* thiz; + NW_ASSERT(pUlpApi != NULL); + + thiz = (NwGtpv2cNodeUlpT*) hUlp; + + switch(pUlpApi->apiType) + { + case NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND: + { + pPeer = (NwGtpv2cPeerT*)pUlpApi->apiInfo.triggeredRspIndInfo.hUlpTrxn; + + if(pUlpApi->apiInfo.triggeredRspIndInfo.msgType == NW_GTP_ECHO_RSP) + { + seqNum = nwGtpv2cMsgGetSeqNumber(pUlpApi->hMsg); + len = nwGtpv2cMsgGetLength(pUlpApi->hMsg); + + NW_ASSERT(gettimeofday(&tv, NULL) == 0); + recvTimeStamp = (tv.tv_sec * 1000000) + tv.tv_usec; + + NW_LOG(NW_LOG_LEVEL_NOTI, "%u bytes of response from "NW_IPV4_ADDR": gtp_seq=%u time=%2.2f ms", len, NW_IPV4_ADDR_FORMAT(pPeer->ipv4Addr), seqNum, (float) (recvTimeStamp - pPeer->sendTimeStamp) / 1000 ); + if(pPeer->pingCount) + { + sleep(pPeer->pingInterval); + rc = nwGtpv2cUlpSendEchoRequestToPeer(thiz, pPeer); + if(pPeer->pingCount != 0xffffffff) pPeer->pingCount--; + } + } + + } + break; + + case NW_GTPV2C_ULP_API_RSP_FAILURE_IND: + { + pPeer = (NwGtpv2cPeerT*)pUlpApi->apiInfo.rspFailureInfo.hUlpTrxn; + NW_LOG(NW_LOG_LEVEL_DEBG, "No response from "NW_IPV4_ADDR" (2123)!", NW_IPV4_ADDR_FORMAT(pPeer->ipv4Addr)); + rc = nwGtpv2cUlpSendEchoRequestToPeer(thiz, pPeer); + } + break; + + default: + NW_LOG(NW_LOG_LEVEL_WARN, "Received undefined UlpApi from gtpv2c stack!"); + } + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.h new file mode 100644 index 0000000000..94c4deca80 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-egtping/NwMiniUlpEntity.h @@ -0,0 +1,55 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.h + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef __NW_MINI_ULP_H__ +#define __NW_MINI_ULP_H__ + +typedef struct +{ + NwU8T peerIpStr[16]; + NwU32T restartCounter; + NwGtpv2cStackHandleT hGtpv2cStack; +} NwGtpv2cNodeUlpT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT +nwGtpv2cUlpInit(NwGtpv2cNodeUlpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, char* peerIpStr ); + +NwRcT +nwGtpv2cUlpDestroy(NwGtpv2cNodeUlpT* thiz); + +NwRcT +nwGtpv2cUlpProcessStackReqCallback (NwGtpv2cUlpHandleT hUlp, + NwGtpv2cUlpApiT *pUlpApi); + +NwRcT +nwGtpv2cUlpPing(NwGtpv2cNodeUlpT* thiz, + NwU32T peerIp, + NwU32T pingCount, + NwU32T pingInterval, + NwU32T t3Time, + NwU32T n3Count); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/Makefile.am b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/Makefile.am new file mode 100644 index 0000000000..0cf90d9111 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/Makefile.am @@ -0,0 +1,21 @@ +AM_CFLAGS = -D__WITH_LIBEVENT__ \ + -I$(top_srcdir)/shared -I$(top_srcdir)/include \ + -I$(top_srcdir)/test-app/nw-udp -I$(top_srcdir)/test-app/nw-log \ + @AM_CFLAGS@ + +if ENABLE_TESTS_APP +bin_PROGRAMS = helloworld +helloworld_SOURCES = \ + NwEvt.h\ + NwMiniLogMgrEntity.h\ + NwMiniTmrMgrEntity.h\ + NwMiniUlpEntity.h\ + NwMiniUdpEntity.h\ + NwMiniLogMgrEntity.c\ + NwMiniTmrMgrEntity.c\ + NwMiniUlpEntity.c\ + NwMiniUdpEntity.c\ + helloworld.c + +helloworld_LDADD = $(top_builddir)/src/libNwGtpv2c.a -levent $(AM_LDFLAGS) +endif \ No newline at end of file diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwEvt.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwEvt.h new file mode 100644 index 0000000000..da02372e2a --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwEvt.h @@ -0,0 +1,81 @@ +/*----------------------------------------------------------------------------* + * * + * Copyright (c) 2010-2011 Amit Chawre * + * All rights reserved. * + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright * + * notice, this list of conditions and the following disclaimer. * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * 3. The name of the author may not be used to endorse or promote products * + * derived from this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + *----------------------------------------------------------------------------*/ + +#ifndef __NW_EVT_H__ +#define __NW_EVT_H__ +/** + * @file NwEvt.h + * @brief +*/ + +#ifdef __WITH_LIBEVENT__ + +#include <event.h> + +typedef struct event NwEventT; + +#define NW_EVT_READ (EV_READ) +#define NW_EVT_PERSIST (EV_PERSIST) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(int fd, short event, void *arg) + +#define NW_EVT_INIT event_init +#define NW_EVT_LOOP event_dispatch + +#define NW_EVENT_ADD(__ev, __evSelObj, __evCallback, __evCallbackArg, __evFlags) \ + do { \ + event_set(&(__ev), __evSelObj, __evFlags, __evCallback, __evCallbackArg); \ + event_add(&(__ev), NULL); \ + } while(0) + +#else + +#warning "Event library not defined!" + +/* HACK : Defining dummy values for compilation!*/ + +typedef struct +{ + int __tbd; +} NwEventT; + +#define NW_EVT_READ (0) +#define NW_EVT_PERSIST (1) +#define NW_EVT_CALLBACK(__cbFunc) __cbFunc(void *arg) +#define NW_TMR_CALLBACK(__cbFunc) __cbFunc(void *arg) + + +#define NW_EVT_INIT() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVT_LOOP() do { printf("error: Event library not defined!\n"); exit (0); } while(0) +#define NW_EVENT_ADD(...) do { printf("error: Event library not defined!\n"); exit (0); } while(0) + + +#endif + +#endif /* __NW_EVT_H__ */ diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.c new file mode 100644 index 0000000000..f7e0571ac3 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.c @@ -0,0 +1,69 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwTypes.h" +#include "NwError.h" +#include "NwLog.h" +#include "NwGtpv2c.h" + +#include "NwMiniLogMgrEntity.h" + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +NwMiniLogMgrT __gLogMgr; + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwMiniLogMgrT* nwMiniLogMgrGetInstance() +{ + return &(__gLogMgr); +} + +NwRcT nwMiniLogMgrInit(NwMiniLogMgrT* thiz, NwU32T logLevel ) +{ + thiz->logLevel = logLevel; + return NW_OK; +} + +NwRcT nwMiniLogMgrSetLogLevel(NwMiniLogMgrT* thiz, NwU32T logLevel) +{ + thiz->logLevel = logLevel; +} + +NwRcT nwMiniLogMgrLogRequest (NwGtpv2cLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr) +{ + NwMiniLogMgrT* thiz = (NwMiniLogMgrT*) hLogMgr; + if(thiz->logLevel >= logLevel) + printf("NWGTPV2C-STK %s - %s <%s,%u>\n", gLogLevelStr[logLevel], logStr, basename(file), line); + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.h new file mode 100644 index 0000000000..1865c9915e --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniLogMgrEntity.h @@ -0,0 +1,90 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C L O G M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file hello-world.c + * @brief This file contains example of a minimalistic log manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_LOG_MGR_H__ +#define __NW_MINI_LOG_MGR_H__ + +#define NW_LOG( _logLevel, ...) \ + do { \ + if((nwMiniLogMgrGetInstance())->logLevel >= _logLevel) \ + { \ + char _logStr[1024]; \ + snprintf(_logStr, 1024, __VA_ARGS__); \ + printf("NWGTPV2C-APP %s - %s <%s,%u>\n", gLogLevelStr[_logLevel], _logStr, basename(__FILE__), __LINE__);\ + } \ + } while(0) + +/** + * MiniLogMgr Class Definition + */ +typedef struct NwMiniLogMgr +{ + NwU8T logLevel; /*< Log level */ +} NwMiniLogMgrT; + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get global singleton MiniLogMgr instance + */ +NwMiniLogMgrT* nwMiniLogMgrGetInstance(); + +/** + * Initialize MiniLogMgr + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + */ +NwRcT nwMiniLogMgrInit(NwMiniLogMgrT* thiz, NwU32T logLevel ); + +/** + * Set MiniLogMgr log level + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + */ +NwRcT nwMiniLogMgrSetLogLevel(NwMiniLogMgrT* thiz, NwU32T logLevel); + +/** + * Process log request from stack + * @param thiz : Pointer to global singleton MiniLogMgr instance + * @param logLevel : Log Level + * @param file : Filename + * @param line : Line Number + * @param logStr : Log string + */ +NwRcT nwMiniLogMgrLogRequest (NwGtpv2cLogMgrHandleT logMgrHandle, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.c new file mode 100644 index 0000000000..63aa2bac2e --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.c @@ -0,0 +1,100 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static void +NW_TMR_CALLBACK(nwGtpv2cNodeHandleStackTimerTimeout) +{ + NwRcT rc; + NwGtpv2cNodeTmrT *pTmr = (NwGtpv2cNodeTmrT*) arg; + + /* + * Send Timeout Request to Gtpv2c Stack Instance + */ + rc = nwGtpv2cProcessTimeout(pTmr->timeoutArg); + NW_ASSERT(NW_OK == rc); + + free(pTmr); + + return; +} + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwRcT nwTimerStart( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void* timeoutArg, + NwGtpv2cTimerHandleT* hTmr) +{ + NwRcT rc = NW_OK; + NwGtpv2cNodeTmrT *pTmr; + struct timeval tv; + + NW_LOG(NW_LOG_LEVEL_DEBG, "Received start timer request from stack with timer type %u, arg %x, for %u sec and %u usec", tmrType, timeoutArg, timeoutSec, timeoutUsec); + + pTmr = (NwGtpv2cNodeTmrT*) malloc(sizeof(NwGtpv2cNodeTmrT)); + + /* set the timevalues*/ + timerclear(&tv); + tv.tv_sec = timeoutSec; + tv.tv_usec = timeoutUsec; + + pTmr->timeoutArg = timeoutArg; + evtimer_set(&pTmr->ev, nwGtpv2cNodeHandleStackTimerTimeout, pTmr); + + /*add event*/ + + event_add(&(pTmr->ev), &tv); + + *hTmr = (NwGtpv2cTimerHandleT)pTmr; + + return rc; +} + +NwRcT nwTimerStop( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT hTmr) +{ + NW_LOG(NW_LOG_LEVEL_DEBG, "Received stop timer request from stack for timer handle %u", hTmr); + evtimer_del(&(((NwGtpv2cNodeTmrT*)hTmr)->ev)); + free((void*)hTmr); + return NW_OK; +} + +#ifdef __cplusplus +} +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.h new file mode 100644 index 0000000000..5f1ea1254c --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniTmrMgrEntity.h @@ -0,0 +1,59 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C T M R M G R E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniTmrMgrEntity.c + * @brief This file ontains example of a minimalistic timer manager entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_TMR_MGR_H__ +#define __NW_MINI_TMR_MGR_H__ + +typedef struct +{ + NwU8T _tbd; +} NwGtpv2cNodeTmrMgrT; + +typedef struct +{ + NwEventT ev; + void* timeoutArg; +} NwGtpv2cNodeTmrT; + + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT nwTimerStart( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void* timeoutArg, + NwGtpv2cTimerHandleT* hTmr); + + +NwRcT nwTimerStop( NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT hTmr); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.c new file mode 100644 index 0000000000..7842505b61 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.c @@ -0,0 +1,153 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUdpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#define MAX_UDP_PAYLOAD_LEN (4096) + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * Private functions + *--------------------------------------------------------------------------*/ + +static +void NW_EVT_CALLBACK(nwUdpDataIndicationCallbackData) +{ + NwRcT rc; + NwU8T udpBuf[MAX_UDP_PAYLOAD_LEN]; + NwS32T bytesRead; + NwU32T peerLen; + struct sockaddr_in peer; + NwGtpv2cNodeUdpT* thiz = (NwGtpv2cNodeUdpT*) arg; + + peerLen = sizeof(peer); + + bytesRead = recvfrom(fd, udpBuf, MAX_UDP_PAYLOAD_LEN , 0, (struct sockaddr *) &peer,(socklen_t*) &peerLen); + if(bytesRead) + { + NwU32T peerIp = (peer.sin_addr.s_addr); + NW_LOG(NW_LOG_LEVEL_DEBG, "Received UDP message of size %u from peer %u.%u.%u.%u:%u", bytesRead, + (peerIp & 0x000000ff), + (peerIp & 0x0000ff00) >> 8, + (peerIp & 0x00ff0000) >> 16, + (peerIp & 0xff000000) >> 24, + ntohs(peer.sin_port)); + rc = nwGtpv2cProcessUdpReq(thiz->hGtpv2cStack, udpBuf, bytesRead, ntohs(peer.sin_port), ntohl(peer.sin_addr.s_addr)); + } + else + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + } +} + + +/*--------------------------------------------------------------------------- + * Public functions + *--------------------------------------------------------------------------*/ + +NwRcT nwGtpv2cUdpInit(NwGtpv2cNodeUdpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, NwU8T* ipv4Addr) +{ + int sd; + struct sockaddr_in addr; + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + if (sd < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(2123); + addr.sin_addr.s_addr = inet_addr(ipv4Addr); + memset(addr.sin_zero, '\0', sizeof (addr.sin_zero)); + + if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + + NW_EVENT_ADD((thiz->ev), sd, nwUdpDataIndicationCallbackData, thiz, NW_EVT_READ | NW_EVT_PERSIST); + + thiz->hSocket = sd; + thiz->hGtpv2cStack = hGtpv2cStack; + + return NW_OK; +} + +NwRcT nwGtpv2cUdpDestroy(NwGtpv2cNodeUdpT* thiz) +{ + close(thiz->hSocket); +} + +NwRcT nwGtpv2cUdpDataReq(NwGtpv2cUdpHandleT udpHandle, + NwU8T* dataBuf, + NwU32T dataSize, + NwU32T peerIp, + NwU32T peerPort) +{ + struct sockaddr_in peerAddr; + NwS32T bytesSent; + NwGtpv2cNodeUdpT* thiz = (NwGtpv2cNodeUdpT*) udpHandle; + + NW_LOG(NW_LOG_LEVEL_DEBG, "Sending buf of size %u for on handle %x to peer %u.%u.%u.%u:%u", dataSize, udpHandle, + (peerIp & 0xff000000) >> 24, + (peerIp & 0x00ff0000) >> 16, + (peerIp & 0x0000ff00) >> 8, + (peerIp & 0x000000ff), + peerPort); + + peerAddr.sin_family = AF_INET; + peerAddr.sin_port = htons(peerPort); + peerAddr.sin_addr.s_addr = htonl(peerIp); + memset(peerAddr.sin_zero, '\0', sizeof (peerAddr.sin_zero)); + + bytesSent = sendto (thiz->hSocket, dataBuf, dataSize, 0, (struct sockaddr *) &peerAddr, sizeof(peerAddr)); + + if(bytesSent < 0) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "%s", strerror(errno)); + NW_ASSERT(0); + } + return NW_OK; +} + + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.h new file mode 100644 index 0000000000..7c032b4843 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUdpEntity.h @@ -0,0 +1,52 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U D P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file NwMiniUdpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifndef __NW_MINI_UDP_ENTITY_H__ +#define __NW_MINI_UDP_ENTITY_H__ + +typedef struct +{ + NwU32T hSocket; + NwEventT ev; + NwGtpv2cStackHandleT hGtpv2cStack; +} NwGtpv2cNodeUdpT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT nwGtpv2cUdpInit(NwGtpv2cNodeUdpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, NwU8T* ipv4Addr); + +NwRcT nwGtpv2cUdpDestroy(NwGtpv2cNodeUdpT* thiz); + +NwRcT nwGtpv2cUdpDataReq(NwGtpv2cUdpHandleT udpHandle, + NwU8T* dataBuf, + NwU32T dataSize, + NwU32T peerIp, + NwU32T peerPort); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.c new file mode 100644 index 0000000000..3873d960da --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.c @@ -0,0 +1,285 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.c + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <string.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" +#include "NwMiniLogMgrEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +static NwRcT +nwGtpv2cCreateSessionRequestIeIndication(NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T* ieValue, void* arg) +{ + NW_LOG(NW_LOG_LEVEL_DEBG, "Received IE Parse Indication for of type %u, length %u, instance %u!", ieType, ieLength, ieInstance); + return NW_OK; +} + +/*--------------------------------------------------------------------------- + * Public Functions + *--------------------------------------------------------------------------*/ + +NwRcT +nwGtpv2cUlpInit(NwGtpv2cNodeUlpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, char* peerIpStr) +{ + NwRcT rc; + thiz->hGtpv2cStack = hGtpv2cStack; + strcpy(thiz->peerIpStr, peerIpStr); + return NW_OK; +} + +NwRcT +nwGtpv2cUlpDestroy(NwGtpv2cNodeUlpT* thiz) +{ + NW_ASSERT(thiz); + memset(thiz, 0, sizeof(NwGtpv2cNodeUlpT)); + return NW_OK; +} + +NwRcT +nwGtpv2cUlpSenEchoRequestToPeer(NwGtpv2cNodeUlpT* thiz, NwU32T peerIp) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulpReq; + /* + * Send Message Request to Gtpv2c Stack Instance + */ + + ulpReq.apiType = NW_GTPV2C_ULP_API_INITIAL_REQ; + + ulpReq.apiInfo.initialReqInfo.hTunnel = 0; + ulpReq.apiInfo.initialReqInfo.hUlpTrxn = (NwGtpv2cUlpTrxnHandleT)thiz; + ulpReq.apiInfo.initialReqInfo.hUlpTunnel = (NwGtpv2cUlpTrxnHandleT)thiz; + ulpReq.apiInfo.initialReqInfo.teidLocal = (NwGtpv2cUlpTrxnHandleT)0; + ulpReq.apiInfo.initialReqInfo.peerIp = htonl(peerIp); + + rc = nwGtpv2cMsgNew( thiz->hGtpv2cStack, + NW_FALSE, + NW_GTP_ECHO_REQ, + 0, + 0, + &(ulpReq.hMsg)); + + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgAddIeTV1((ulpReq.hMsg), NW_GTPV2C_IE_RECOVERY, 0, thiz->restartCounter); + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cProcessUlpReq(thiz->hGtpv2cStack, &ulpReq); + NW_ASSERT(NW_OK == rc); + + return NW_OK; +} + +NwRcT +nwGtpv2cUlpCreateSessionRequestToPeer(NwGtpv2cNodeUlpT* thiz) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulpReq; + + /* + * Send Message Request to Gtpv2c Stack Instance + */ + + ulpReq.apiType = (NW_GTPV2C_ULP_API_INITIAL_REQ | NW_GTPV2C_ULP_API_FLAG_CREATE_LOCAL_TUNNEL); + + ulpReq.apiInfo.initialReqInfo.hUlpTrxn = (NwGtpv2cUlpTrxnHandleT)thiz; + ulpReq.apiInfo.initialReqInfo.teidLocal = (NwGtpv2cUlpTrxnHandleT)thiz; + ulpReq.apiInfo.initialReqInfo.peerIp = ntohl(inet_addr(thiz->peerIpStr)); + + rc = nwGtpv2cMsgNew( thiz->hGtpv2cStack, + NW_TRUE, + NW_GTP_CREATE_SESSION_REQ, + 0, + 0, + &(ulpReq.hMsg)); + + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgAddIeTV1((ulpReq.hMsg), NW_GTPV2C_IE_RECOVERY, 0, thiz->restartCounter); + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cProcessUlpReq(thiz->hGtpv2cStack, &ulpReq); + NW_ASSERT(NW_OK == rc); + + return NW_OK; +} + +NwRcT +nwGtpv2cUlpProcessStackReqCallback (NwGtpv2cUlpHandleT hUlp, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc; + NwGtpv2cNodeUlpT* thiz; + NW_ASSERT(pUlpApi != NULL); + + thiz = (NwGtpv2cNodeUlpT*) hUlp; + + switch(pUlpApi->apiType) + { + + case NW_GTPV2C_ULP_API_INITIAL_REQ_IND: + { + NwGtpv2cUlpApiT ulpReq; + NwGtpv2cMsgParserT *pMsgParser; + NW_LOG(NW_LOG_LEVEL_DEBG, "Received NW_GTPV2C_ULP_API_INITIAL_REQ_IND from gtpv2c stack! %X:%u", pUlpApi->apiInfo.initialReqIndInfo.peerIp, pUlpApi->apiInfo.initialReqIndInfo.peerPort); + + rc = nwGtpv2cMsgParserNew(thiz->hGtpv2cStack, NW_GTP_CREATE_SESSION_REQ, nwGtpv2cCreateSessionRequestIeIndication, NULL, &pMsgParser); + NW_ASSERT(NW_OK == rc); + + if(pUlpApi->apiInfo.initialReqIndInfo.msgType == NW_GTP_CREATE_SESSION_REQ) + { + + struct + { + NwU8T causeValue; + NwU8T spare:5; + NwU8T pce:1; + NwU8T bce:1; + NwU8T cs:1; + } cause; + + + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_RECOVERY, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY, nwGtpv2cCreateSessionRequestIeIndication, NULL); + NW_ASSERT(NW_OK == rc); + + NwU8T offendingIeType, OffendingIeLength; + rc = nwGtpv2cMsgParserRun(pMsgParser, (pUlpApi->hMsg), &offendingIeType, &OffendingIeLength); + if( rc != NW_OK ) + { + switch(rc) + { + case NW_GTPV2C_MANDATORY_IE_MISSING: + NW_LOG(NW_LOG_LEVEL_ERRO, "Mandatory IE type '%u' of instance '%u' missing!", offendingIeType, OffendingIeLength); + cause.causeValue = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + break; + default: + NW_LOG(NW_LOG_LEVEL_ERRO, "Unknown message parse error!"); + cause.causeValue = 0; + break; + } + + } + else + { + cause.causeValue = NW_GTPV2C_CAUSE_REQUEST_ACCEPTED; + } + + /* + * Send Message Request to Gtpv2c Stack Instance + */ + ulpReq.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulpReq.apiInfo.triggeredRspInfo.hTrxn = pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + + rc = nwGtpv2cMsgNew( thiz->hGtpv2cStack, + NW_TRUE, + NW_GTP_CREATE_SESSION_RSP, + 0, + nwGtpv2cMsgGetSeqNumber(pUlpApi->hMsg), + &(ulpReq.hMsg)); + + rc = nwGtpv2cMsgAddIe((ulpReq.hMsg), NW_GTPV2C_IE_CAUSE, 2, 0, (NwU8T*)&cause); + NW_ASSERT(NW_OK == rc); + + NW_LOG(NW_LOG_LEVEL_NOTI, "Received NW_GTP_CREATE_SESSION_REQ, Sending NW_GTP_CREATE_SESSION_RSP!"); + rc = nwGtpv2cProcessUlpReq(thiz->hGtpv2cStack, &ulpReq); + NW_ASSERT(NW_OK == rc); + } + + rc = nwGtpv2cMsgParserDelete(thiz->hGtpv2cStack, pMsgParser); + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(thiz->hGtpv2cStack, (pUlpApi->hMsg)); + NW_ASSERT(NW_OK == rc); + + } + break; + + case NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND: + { + NwGtpv2cUlpApiT ulpReq; + NwGtpv2cMsgParserT *pMsgParser; + NW_LOG(NW_LOG_LEVEL_DEBG, "Received NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND from gtpv2c stack!", pUlpApi->apiInfo.triggeredRspIndInfo, pUlpApi->apiInfo.triggeredRspIndInfo); + + rc = nwGtpv2cMsgParserNew(thiz->hGtpv2cStack, NW_GTP_CREATE_SESSION_REQ, nwGtpv2cCreateSessionRequestIeIndication, NULL, &pMsgParser); + NW_ASSERT(NW_OK == rc); + + if(pUlpApi->apiInfo.triggeredRspIndInfo.msgType == NW_GTP_CREATE_SESSION_RSP) + { + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_CAUSE, NW_GTPV2C_IE_INSTANCE_ZERO, NW_GTPV2C_IE_PRESENCE_MANDATORY, nwGtpv2cCreateSessionRequestIeIndication, NULL); + NW_ASSERT(NW_OK == rc); + + NwU8T offendingIeType, OffendingIeLength; + rc = nwGtpv2cMsgParserRun(pMsgParser, (pUlpApi->hMsg), &offendingIeType, &OffendingIeLength); + if( rc != NW_OK ) + { + switch(rc) + { + case NW_GTPV2C_MANDATORY_IE_MISSING: + NW_LOG(NW_LOG_LEVEL_ERRO, "Mandatory IE Missing!"); + break; + default: + NW_LOG(NW_LOG_LEVEL_ERRO, "Unknown message parse error!"); + break; + + } + + } + + /* + * Send Message Request to Gtpv2c Stack Instance + */ + NW_LOG(NW_LOG_LEVEL_NOTI, "Received NW_GTP_CREATE_SESSION_RSP, Sending NW_GTP_CREATE_SESSION_REQ!"); + nwGtpv2cUlpCreateSessionRequestToPeer(thiz); + } + rc = nwGtpv2cMsgParserDelete(thiz->hGtpv2cStack, pMsgParser); + NW_ASSERT(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(thiz->hGtpv2cStack, (pUlpApi->hMsg)); + NW_ASSERT(NW_OK == rc); + + } + break; + + case NW_GTPV2C_ULP_API_RSP_FAILURE_IND: + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Received NW_GTPV2C_ULP_API_RSP_FAILURE from gtpv2c stack for transaction '%x'!", thiz); + } + break; + + default: + NW_LOG(NW_LOG_LEVEL_WARN, "Received undefined UlpApi from gtpv2c stack!"); + } + return NW_OK; +} + +#ifdef __cplusplus +} +#endif + diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.h b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.h new file mode 100644 index 0000000000..496271f5b5 --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/NwMiniUlpEntity.h @@ -0,0 +1,50 @@ +/*----------------------------------------------------------------------------* + * * + * M I N I M A L I S T I C U L P E N T I T Y * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + +/** + * @file NwMiniUlpEntity.h + * @brief This file contains example of a minimalistic ULP entity. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" + +#ifndef __NW_MINI_ULP_H__ +#define __NW_MINI_ULP_H__ + +typedef struct +{ + NwU8T peerIpStr[16]; + NwU32T restartCounter; + NwGtpv2cStackHandleT hGtpv2cStack; +} NwGtpv2cNodeUlpT; + +#ifdef __cplusplus +extern "C" { +#endif + +NwRcT +nwGtpv2cUlpInit(NwGtpv2cNodeUlpT* thiz, NwGtpv2cStackHandleT hGtpv2cStack, char* peerIpStr ); + +NwRcT +nwGtpv2cUlpDestroy(NwGtpv2cNodeUlpT* thiz); + +NwRcT +nwGtpv2cUlpCreateSessionRequestToPeer(NwGtpv2cNodeUlpT* thiz); + +NwRcT +nwGtpv2cUlpProcessStackReqCallback (NwGtpv2cUlpHandleT hUlp, + NwGtpv2cUlpApiT *pUlpApi); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/helloworld.c b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/helloworld.c new file mode 100644 index 0000000000..de4302379b --- /dev/null +++ b/openair-cn/GTPV2-C/nwgtpv2c-0.11/test-app/nw-helloworld/helloworld.c @@ -0,0 +1,185 @@ +/*----------------------------------------------------------------------------* + * * + * n w - g t p v 2 c * + * G P R S T u n n e l i n g P r o t o c o l v 2 c S t a c k * + * * + * M I N I M A L I S T I C D E M O N S T R A T I O N * + * * + * Copyright (C) 2010 Amit Chawre. * + * * + *----------------------------------------------------------------------------*/ + + +/** + * @file hello-world.c + * @brief This is a test program demostrating usage of nw-gtpv2c library. +*/ + +#include <stdio.h> +#include <assert.h> +#include "NwEvt.h" +#include "NwLog.h" +#include "NwGtpv2c.h" + +#include "NwMiniLogMgrEntity.h" +#include "NwMiniTmrMgrEntity.h" +#include "NwMiniUdpEntity.h" +#include "NwMiniUlpEntity.h" + +#ifndef NW_ASSERT +#define NW_ASSERT assert +#endif + +static +NwCharT* gLogLevelStr[] = {"EMER", "ALER", "CRIT", "ERRO", "WARN", "NOTI", "INFO", "DEBG"}; + +/*--------------------------------------------------------------------------- + * T H E M A I N F U N C T I O N + *--------------------------------------------------------------------------*/ + +int main(int argc, char* argv[]) +{ + NwRcT rc; + NwU32T logLevel; + NwU8T* logLevelStr; + + NwGtpv2cStackHandleT hGtpv2cStack = 0; + + NwGtpv2cNodeUlpT ulpObj; + NwGtpv2cNodeUdpT udpObj; + + + NwGtpv2cUlpEntityT ulp; + NwGtpv2cUdpEntityT udp; + NwGtpv2cTimerMgrEntityT tmrMgr; + NwGtpv2cLogMgrEntityT logMgr; + + if(argc != 3) + { + printf("Usage: %s <local-ip> <peer-ip>\n", argv[0]); + exit(0); + } + + logLevelStr = getenv ("NW_LOG_LEVEL"); + + if(logLevelStr == NULL) + { + logLevel = NW_LOG_LEVEL_INFO; + } + else + { + if(strncmp(logLevelStr, "EMER",4) == 0) + logLevel = NW_LOG_LEVEL_EMER; + else if(strncmp(logLevelStr, "ALER",4) == 0) + logLevel = NW_LOG_LEVEL_ALER; + else if(strncmp(logLevelStr, "CRIT",4) == 0) + logLevel = NW_LOG_LEVEL_CRIT; + else if(strncmp(logLevelStr, "ERRO",4) == 0) + logLevel = NW_LOG_LEVEL_ERRO ; + else if(strncmp(logLevelStr, "WARN",4) == 0) + logLevel = NW_LOG_LEVEL_WARN; + else if(strncmp(logLevelStr, "NOTI",4) == 0) + logLevel = NW_LOG_LEVEL_NOTI; + else if(strncmp(logLevelStr, "INFO",4) == 0) + logLevel = NW_LOG_LEVEL_INFO; + else if(strncmp(logLevelStr, "DEBG",4) == 0) + logLevel = NW_LOG_LEVEL_DEBG; + } + + /*--------------------------------------------------------------------------- + * Initialize event library + *--------------------------------------------------------------------------*/ + + NW_EVT_INIT(); + + /*--------------------------------------------------------------------------- + * Initialize Log Manager + *--------------------------------------------------------------------------*/ + nwMiniLogMgrInit(nwMiniLogMgrGetInstance(), logLevel); + + /*--------------------------------------------------------------------------- + * Initialize Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cInitialize(&hGtpv2cStack); + + if(rc != NW_OK) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Failed to create gtpv2c stack instance. Error '%u' occured", rc); + exit(1); + } + NW_LOG(NW_LOG_LEVEL_INFO, "Gtpv2c Stack Handle '%X' Creation Successful!", hGtpv2cStack); + + rc = nwGtpv2cSetLogLevel(hGtpv2cStack, logLevel); + + /*--------------------------------------------------------------------------- + * Set up Ulp Entity + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cUlpInit(&ulpObj, hGtpv2cStack, argv[2]); + NW_ASSERT(NW_OK == rc); + + ulp.hUlp = (NwGtpv2cUlpHandleT) &ulpObj; + ulp.ulpReqCallback = nwGtpv2cUlpProcessStackReqCallback; + + rc = nwGtpv2cSetUlpEntity(hGtpv2cStack, &ulp); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Udp Entity + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cUdpInit(&udpObj, hGtpv2cStack, (argv[1])); + NW_ASSERT(NW_OK == rc); + + udp.hUdp = (NwGtpv2cUdpHandleT) &udpObj; + udp.udpDataReqCallback = nwGtpv2cUdpDataReq; + + rc = nwGtpv2cSetUdpEntity(hGtpv2cStack, &udp); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + tmrMgr.tmrMgrHandle = 0; + tmrMgr.tmrStartCallback = nwTimerStart; + tmrMgr.tmrStopCallback = nwTimerStop; + + rc = nwGtpv2cSetTimerMgrEntity(hGtpv2cStack, &tmrMgr); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Set up Log Entity + *--------------------------------------------------------------------------*/ + logMgr.logMgrHandle = (NwGtpv2cLogMgrHandleT) nwMiniLogMgrGetInstance(); + logMgr.logReqCallback = nwMiniLogMgrLogRequest; + + rc = nwGtpv2cSetLogMgrEntity(hGtpv2cStack, &logMgr); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Send Message Request to Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + //rc = nwGtpv2cUlpCreateSessionRequestToPeer(&ulpObj); + rc = nwGtpv2cUlpSenEchoRequestToPeer(&ulpObj, inet_addr(argv[2])); + NW_ASSERT(NW_OK == rc); + + /*--------------------------------------------------------------------------- + * Event loop + *--------------------------------------------------------------------------*/ + + NW_EVT_LOOP(); + NW_LOG(NW_LOG_LEVEL_ERRO, "Exit from eventloop, no events to process!"); + + /*--------------------------------------------------------------------------- + * Destroy Gtpv2c Stack Instance + *--------------------------------------------------------------------------*/ + rc = nwGtpv2cFinalize(hGtpv2cStack); + if(rc != NW_OK) + { + NW_LOG(NW_LOG_LEVEL_ERRO, "Failed to finalize gtpv2c stack instance. Error '%u' occured", rc); + } + else + { + NW_LOG(NW_LOG_LEVEL_INFO, "Gtpv2c Stack Handle '%X' Finalize Successful!", hGtpv2cStack); + } + + return rc; +} diff --git a/openair-cn/INSTALL b/openair-cn/INSTALL new file mode 100644 index 0000000000..6e90e07d27 --- /dev/null +++ b/openair-cn/INSTALL @@ -0,0 +1,370 @@ +Installation Instructions +************************* + +Copyright (C) 1994-1996, 1999-2002, 2004-2012 Free Software Foundation, +Inc. + + Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. This file is offered as-is, +without warranty of any kind. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. Some packages provide this +`INSTALL' file but do not implement all of the features documented +below. The lack of an optional feature in a given package is not +necessarily a bug. More recommendations for GNU packages can be found +in *note Makefile Conventions: (standards)Makefile Conventions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + + The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package, generally using the just-built uninstalled binaries. + + 4. Type `make install' to install the programs and any data files and + documentation. When installing into a prefix owned by root, it is + recommended that the package be configured and built as a regular + user, and only the `make install' phase executed with root + privileges. + + 5. Optionally, type `make installcheck' to repeat any self-tests, but + this time using the binaries in their final installed location. + This target does not install anything. Running this target as a + regular user, particularly if the prior `make install' required + root privileges, verifies that the installation completed + correctly. + + 6. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 7. Often, you can also type `make uninstall' to remove the installed + files again. In practice, not all packages have tested that + uninstallation works correctly, even though it is required by the + GNU Coding Standards. + + 8. Some packages, particularly those that use Automake, provide `make + distcheck', which can by used by developers to test that all other + targets like `make install' and `make uninstall' work correctly. + This target is generally not run by end users. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. This +is known as a "VPATH" build. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX', where PREFIX must be an +absolute file name. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. In general, the +default for these options is expressed in terms of `${prefix}', so that +specifying just `--prefix' will affect all of the other directory +specifications that were not explicitly provided. + + The most portable way to affect installation locations is to pass the +correct locations to `configure'; however, many packages provide one or +both of the following shortcuts of passing variable assignments to the +`make install' command line to change installation locations without +having to reconfigure or recompile. + + The first method involves providing an override variable for each +affected directory. For example, `make install +prefix=/alternate/directory' will choose an alternate location for all +directory configuration variables that were expressed in terms of +`${prefix}'. Any directories that were specified during `configure', +but not in terms of `${prefix}', must each be overridden at install +time for the entire installation to be relocated. The approach of +makefile variable overrides for each directory variable is required by +the GNU Coding Standards, and ideally causes no recompilation. +However, some platforms have known limitations with the semantics of +shared libraries that end up requiring recompilation when using this +method, particularly noticeable in packages that use GNU Libtool. + + The second method involves providing the `DESTDIR' variable. For +example, `make install DESTDIR=/alternate/directory' will prepend +`/alternate/directory' before all installation names. The approach of +`DESTDIR' overrides is not required by the GNU Coding Standards, and +does not work on platforms that have drive letters. On the other hand, +it does better at avoiding recompilation issues, and works well even +when some directory options were not specified in terms of `${prefix}' +at `configure' time. + +Optional Features +================= + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + + Some packages offer the ability to configure how verbose the +execution of `make' will be. For these packages, running `./configure +--enable-silent-rules' sets the default to minimal output, which can be +overridden with `make V=1'; while running `./configure +--disable-silent-rules' sets the default to verbose, which can be +overridden with `make V=0'. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + HP-UX `make' updates targets which have the same time stamps as +their prerequisites, which makes it generally unusable when shipped +generated files such as `configure' are involved. Use GNU `make' +instead. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf limitation. Until the limitation is lifted, you can use +this workaround: + + CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. diff --git a/openair-cn/INTERTASK_INTERFACE/Makefile.am b/openair-cn/INTERTASK_INTERFACE/Makefile.am new file mode 100644 index 0000000000..eddb2eda7e --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/Makefile.am @@ -0,0 +1,20 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/COMMON + +noinst_LTLIBRARIES = libitti.la + +libitti_la_LDFLAGS = -all-static +libitti_la_SOURCES = \ + gtpv1_u_messages_def.h gtpv1_u_messages_types.h \ + nas_messages_def.h nas_messages_types.h \ + timer_messages_def.h timer_messages_types.h \ + s11_messages_def.h s11_messages_types.h \ + s1ap_messages_def.h s1ap_messages_types.h \ + s6a_messages_def.h s6a_messages_types.h \ + sgw_lite_def.h sgw_lite_messages_types.h \ + sctp_messages_def.h sctp_messages_types.h \ + udp_message_def.h udp_messages_types.h \ + intertask_interface.c intertask_interface.h \ + intertask_interface_dump.c intertask_interface_dump.h \ + timer.c timer.h \ No newline at end of file diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface.c b/openair-cn/INTERTASK_INTERFACE/intertask_interface.c new file mode 100644 index 0000000000..b7d6b4400f --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface.c @@ -0,0 +1,459 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include "queue.h" +#include "assertions.h" + +#include "intertask_interface.h" +#include "intertask_interface_dump.h" +/* Includes "intertask_interface_init.h" to check prototype coherence, but disable threads and messages information generation */ +#define CHECK_PROTOTYPE_ONLY +#include "intertask_interface_init.h" +#undef CHECK_PROTOTYPE_ONLY + +#include "timer.h" + +int itti_debug = 1; + +#define ITTI_DEBUG(x, args...) do { if (itti_debug) fprintf(stdout, "[ITTI][D]"x, ##args); } \ + while(0) +#define ITTI_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); } \ + while(0) + +/* Global message size */ +#define MESSAGE_SIZE(mESSAGEiD) (sizeof(MessageHeader) + itti_desc.messages_info[mESSAGEiD].size) + +typedef enum task_state_s { + TASK_STATE_NOT_CONFIGURED, + TASK_STATE_STARTING, + TASK_STATE_READY, + TASK_STATE_MAX, +} task_state_t; + +/* This list acts as a FIFO of messages received by tasks (RRC, NAS, ...) */ +struct message_list_s { + STAILQ_ENTRY(message_list_s) next_element; + + MessageDef *msg; ///< Pointer to the message + + message_number_t message_number; ///< Unique message number + uint32_t message_priority; ///< Message priority +}; + +typedef struct task_desc_s { + /* Queue of messages belonging to the task */ + STAILQ_HEAD(message_queue_head, message_list_s) message_queue; + + /* Number of messages in the queue */ + volatile uint32_t message_in_queue; + /* Mutex for the message queue */ + pthread_mutex_t message_queue_mutex; + /* Conditional var for message queue and task synchro */ + pthread_cond_t message_queue_cond_var; + pthread_t task_thread; + volatile task_state_t task_state; +} task_desc_t; + +struct itti_desc_s { + task_desc_t *tasks; + /* Current message number. Incremented every call to send_msg_to_task */ + message_number_t message_number __attribute__((aligned(8))); + + thread_id_t thread_max; + MessagesIds messages_id_max; + + const char * const *threads_name; + const message_info_t *messages_info; +}; + +static struct itti_desc_s itti_desc; + +static inline +message_number_t increment_message_number(void) +{ + /* Atomic operation supported by GCC: returns the current message number + * and then increment it by 1. + * This can be done without mutex. + */ + return __sync_fetch_and_add(&itti_desc.message_number, 1); +} + +static inline uint32_t get_message_priority(MessagesIds message_id) +{ + DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0); + + return (itti_desc.messages_info[message_id].priority); +} + +char *get_message_name(MessagesIds message_id) +{ + DevCheck(message_id < itti_desc.messages_id_max, message_id, itti_desc.messages_id_max, 0); + + return (itti_desc.messages_info[message_id].name); +} + +int send_broadcast_message(MessageDef *message_p) +{ + uint32_t i; + int ret = 0; + int temp; + + for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) + { + MessageDef *new_message_p; + + /* Skip tasks which are not running */ + if (itti_desc.tasks[i].task_state != TASK_STATE_READY) + continue; + + new_message_p = malloc(sizeof(MessageDef)); + + if (new_message_p == NULL) { + ITTI_ERROR("Failed to allocate memory (%s:%d)\n", + __FILE__, __LINE__); + return -1; + } + memcpy(new_message_p, message_p, sizeof(MessageDef)); + temp = send_msg_to_task(i, INSTANCE_DEFAULT, new_message_p); + if (temp < 0) { + ITTI_ERROR("Failed to send broadcast message (%s) to queue (%u:%s)\n", + itti_desc.messages_info[message_p->header.messageId].name, i, itti_desc.threads_name[i]); + ret = temp; + free(new_message_p); + } + } + + return ret; +} + +inline MessageDef *alloc_new_message( + task_id_t origin_task_id, + MessagesIds message_id) +{ + MessageDef *temp = NULL; + + if ((TASK_GET_THREAD_ID(origin_task_id) >= itti_desc.thread_max) || + (message_id >= itti_desc.messages_id_max)) + { + return NULL; + } + + temp = calloc(1, MESSAGE_SIZE(message_id)); + + if (temp == NULL) { + ITTI_ERROR("Cannot allocate memory for new message (%s:%d)\n", + __FILE__, __LINE__); + return NULL; + } + + temp->header.messageId = message_id; + temp->header.originTaskId = origin_task_id; + temp->header.size = itti_desc.messages_info[message_id].size; + + return temp; +} + +int send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message) +{ + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); + struct message_list_s *new; + uint32_t priority; + message_number_t message_number; + uint32_t message_id; + + if (thread_id >= itti_desc.thread_max) + { + return -1; + } + + message->header.destinationTaskId = task_id; + message->header.instance = instance; + message_id = message->header.messageId; + + DevAssert(message != NULL); + DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0); + DevCheck(message_id < itti_desc.messages_id_max, itti_desc.messages_id_max, message_id, 0); + + priority = get_message_priority(message_id); + + /* Lock the mutex to get exclusive access to the list */ + pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex); + + /* We cannot send a message if the task is not running */ + DevCheck(itti_desc.tasks[thread_id].task_state == TASK_STATE_READY, + itti_desc.tasks[thread_id].task_state, TASK_STATE_READY, thread_id); + + /* Check the number of messages in the queue */ + DevCheck((itti_desc.tasks[thread_id].message_in_queue * sizeof(MessageDef)) + < ITTI_QUEUE_SIZE_PER_TASK, + (itti_desc.tasks[thread_id].message_in_queue * sizeof(MessageDef)), + ITTI_QUEUE_SIZE_PER_TASK, + itti_desc.tasks[thread_id].message_in_queue); + + /* Allocate new list element */ + if ((new = (struct message_list_s *)malloc(sizeof(struct message_list_s))) == NULL) + { + ITTI_ERROR("Cannot allocate memory for new message (%s:%d)\n", + __FILE__, __LINE__); + return -1; + } + + /* Increment the global message number */ + message_number = increment_message_number(); + + /* Fill in members */ + new->msg = message; + new->message_number = message_number; + new->message_priority = priority; + + itti_dump_queue_message(message_number, message, itti_desc.messages_info[message_id].name, MESSAGE_SIZE(message_id)); + + if (STAILQ_EMPTY(&itti_desc.tasks[thread_id].message_queue)) { + STAILQ_INSERT_HEAD(&itti_desc.tasks[thread_id].message_queue, new, next_element); + } else { +// struct message_list_s *insert_after = NULL; +// struct message_list_s *temp; +// +// /* This method is inefficient... */ +// STAILQ_FOREACH(temp, &itti_desc.tasks[thread_id].message_queue, next_element) { +// struct message_list_s *next; +// next = STAILQ_NEXT(temp, next_element); +// /* Increment message priority to create a sort of +// * priority based scheduler */ +// // if (temp->message_priority < TASK_PRIORITY_MAX) { +// // temp->message_priority++; +// // } +// if (next && next->message_priority < priority) { +// insert_after = temp; +// break; +// } +// } +// if (insert_after == NULL) { + STAILQ_INSERT_TAIL(&itti_desc.tasks[thread_id].message_queue, new, next_element); +// } else { +// STAILQ_INSERT_AFTER(&itti_desc.tasks[thread_id].message_queue, insert_after, new, +// next_element); +// } + } + + /* Update the number of messages in the queue */ + itti_desc.tasks[thread_id].message_in_queue++; + if (itti_desc.tasks[thread_id].message_in_queue == 1) { + /* Emit a signal to wake up target task thread */ + pthread_cond_signal(&itti_desc.tasks[thread_id].message_queue_cond_var); + } + /* Release the mutex */ + pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex); + ITTI_DEBUG("Message %s, number %lu with priority %d successfully sent to queue (%u:%s)\n", + itti_desc.messages_info[message_id].name, message_number, + priority, thread_id, itti_desc.threads_name[thread_id]); + return 0; +} + +void receive_msg(task_id_t task_id, MessageDef **received_msg) +{ + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); + + DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0); + DevAssert(received_msg != NULL); + + // Lock the mutex to get exclusive access to the list + pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex); + + if (itti_desc.tasks[thread_id].message_in_queue == 0) { + ITTI_DEBUG("Message in queue[(%u:%s)] == 0, waiting\n", + thread_id, itti_desc.threads_name[thread_id]); + // Wait while list == 0 + pthread_cond_wait(&itti_desc.tasks[thread_id].message_queue_cond_var, + &itti_desc.tasks[thread_id].message_queue_mutex); + ITTI_DEBUG("Receiver queue[(%u:%s)] got new message notification for task %x\n", + thread_id, itti_desc.threads_name[thread_id], task_id); + } + + if (!STAILQ_EMPTY(&itti_desc.tasks[thread_id].message_queue)) { + struct message_list_s *temp = STAILQ_FIRST( + &itti_desc.tasks[thread_id].message_queue); + + /* Update received_msg reference */ + *received_msg = temp->msg; + + /* Remove message from queue */ + STAILQ_REMOVE_HEAD(&itti_desc.tasks[thread_id].message_queue, next_element); + free(temp); + itti_desc.tasks[thread_id].message_in_queue--; + } + // Release the mutex + pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex); +} + +void poll_msg(task_id_t task_id, instance_t instance, MessageDef **received_msg) +{ + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); + + DevCheck (thread_id < itti_desc.thread_max, thread_id, 0, 0); + DevAssert (received_msg != NULL); + + *received_msg = NULL; + + if (itti_desc.tasks[thread_id].message_in_queue != 0) + { + struct message_list_s *temp; + + // Lock the mutex to get exclusive access to the list + pthread_mutex_lock (&itti_desc.tasks[thread_id].message_queue_mutex); + + STAILQ_FOREACH(temp, &itti_desc.tasks[thread_id].message_queue, next_element) + { + if ((temp->msg->header.destinationTaskId == task_id) + && ((instance == INSTANCE_ALL) || (temp->msg->header.instance == instance))) + { + /* Update received_msg reference */ + *received_msg = temp->msg; + + /* Remove message from queue */ + STAILQ_REMOVE(&itti_desc.tasks[thread_id].message_queue, temp, message_list_s, next_element); + free (temp); + itti_desc.tasks[thread_id].message_in_queue--; + + ITTI_DEBUG("Receiver queue[(%u:%s)] got new message %s, number %lu for task %x\n", + thread_id, itti_desc.threads_name[thread_id], itti_desc.messages_info[temp->msg->header.messageId].name, + temp->message_number, task_id); + break; + } + } + + // Release the mutex + pthread_mutex_unlock (&itti_desc.tasks[thread_id].message_queue_mutex); + } + + if (*received_msg == NULL) + { + ITTI_DEBUG("No message in queue[(%u:%s)] for task %x\n", thread_id, itti_desc.threads_name[thread_id], task_id); + } +} + +int intertask_interface_create_task(task_id_t task_id, + void *(*start_routine) (void *), + void *args_p) +{ + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); + + DevAssert(start_routine != NULL); + DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0); + + if (itti_desc.tasks[thread_id].task_state != TASK_STATE_NOT_CONFIGURED) { + ITTI_ERROR("You are attempting to start an already configured thread" + " for %s thread\n", itti_desc.threads_name[thread_id]); + return -1; + } + + itti_desc.tasks[thread_id].task_state = TASK_STATE_STARTING; + + if (pthread_create(&itti_desc.tasks[thread_id].task_thread, NULL, start_routine, + args_p) < 0) { + ITTI_ERROR("Failed to initialize %s thread: %s:%d\n", itti_desc.threads_name[thread_id], + strerror(errno), + errno); + return -1; + } + + /* Wait till the thread is completely ready */ + while (itti_desc.tasks[thread_id].task_state != TASK_STATE_READY); + return 0; +} + +void intertask_interface_mark_task_ready(task_id_t task_id) +{ + thread_id_t thread_id = TASK_GET_THREAD_ID(task_id); + + DevCheck(thread_id < itti_desc.thread_max, thread_id, 0, 0); + // Lock the mutex to get exclusive access to the list + pthread_mutex_lock(&itti_desc.tasks[thread_id].message_queue_mutex); + itti_desc.tasks[thread_id].task_state = TASK_STATE_READY; + // Release the mutex + pthread_mutex_unlock(&itti_desc.tasks[thread_id].message_queue_mutex); +} + +int intertask_interface_init(thread_id_t thread_max, MessagesIds messages_id_max, + const char * const *threads_name, + const message_info_t *messages_info, + const char * const messages_definition_xml) +{ + int i; + itti_desc.message_number = 0; + + /* Saves threads and messages max values */ + itti_desc.thread_max = thread_max; + itti_desc.messages_id_max = messages_id_max; + itti_desc.threads_name = threads_name; + itti_desc.messages_info = messages_info; + + /* Allocates memory for tasks info */ + itti_desc.tasks = calloc(itti_desc.thread_max, sizeof(task_desc_t)); + + /* Initializing each queue and related stuff */ + for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) { + STAILQ_INIT(&itti_desc.tasks[i].message_queue); + itti_desc.tasks[i].message_in_queue = 0; + // Initialize mutexes + pthread_mutex_init(&itti_desc.tasks[i].message_queue_mutex, NULL); + // Initialize Cond vars + pthread_cond_init(&itti_desc.tasks[i].message_queue_cond_var, NULL); + itti_desc.tasks[i].task_state = TASK_STATE_NOT_CONFIGURED; + } + itti_dump_init(messages_definition_xml); + + timer_init(); + + return 0; +} + +void intertask_interface_send_quit_signal(void) +{ + int i; + MessageDef *terminate_message_p; + + terminate_message_p = alloc_new_message(TASK_UNKNOWN, TERMINATE_MESSAGE); + + send_broadcast_message(terminate_message_p); + + for (i = THREAD_FIRST; i < itti_desc.thread_max; i++) { + /* Skip tasks which are not running */ + if (itti_desc.tasks[i].task_state != TASK_STATE_READY) + continue; + } +} diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface.h b/openair-cn/INTERTASK_INTERFACE/intertask_interface.h new file mode 100644 index 0000000000..84edb96495 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface.h @@ -0,0 +1,142 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms + * Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef INTERTASK_INTERFACE_H_ +#define INTERTASK_INTERFACE_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "mme_config.h" +#include "common_types.h" + +#include "intertask_interface_types.h" + +/* Make the message number platform specific */ +typedef unsigned long message_number_t; +#define MESSAGE_NUMBER_SIZE (sizeof(unsigned long)) + +enum message_priorities { + MESSAGE_PRIORITY_MAX = 100, + MESSAGE_PRIORITY_MAX_LEAST = 85, + MESSAGE_PRIORITY_MED_PLUS = 70, + MESSAGE_PRIORITY_MED = 55, + MESSAGE_PRIORITY_MED_LEAST = 40, + MESSAGE_PRIORITY_MIN_PLUS = 25, + MESSAGE_PRIORITY_MIN = 10, +}; + +typedef struct message_info_s { + task_id_t id; + uint32_t priority; + /* Message payload size */ + MessageHeaderSize size; + /* Printable name */ + char *name; +} message_info_t; + +enum task_priorities { + TASK_PRIORITY_MAX = 100, + TASK_PRIORITY_MAX_LEAST = 85, + TASK_PRIORITY_MED_PLUS = 70, + TASK_PRIORITY_MED = 55, + TASK_PRIORITY_MED_LEAST = 40, + TASK_PRIORITY_MIN_PLUS = 25, + TASK_PRIORITY_MIN = 10, +}; + +/** \brief Send a broadcast message to every task + \param message_p Pointer to the message to send + @returns < 0 on failure, 0 otherwise + **/ +int send_broadcast_message(MessageDef *message_p); + +/** \brief Send a message to a task (could be itself) + \param task_id Task ID + \param instance Instance of the task used for virtualization + \param message Pointer to the message to send + @returns -1 on failure, 0 otherwise + **/ +int send_msg_to_task(task_id_t task_id, instance_t instance, MessageDef *message); + +/** \brief Retrieves a message in the queue associated to task_id. + * If the queue is empty, the thread is blocked till a new message arrives. + \param task_id Task ID of the receiving task + \param received_msg Pointer to the allocated message + **/ +void receive_msg(task_id_t task_id, MessageDef **received_msg); + +/** \brief Try to retrieves a message in the queue associated to task_id and matching requested instance. + \param task_id Task ID of the receiving task + \param instance Instance of the task used for virtualization + \param received_msg Pointer to the allocated message + **/ +void poll_msg(task_id_t task_id, instance_t instance, MessageDef **received_msg); + +/** \brief Start thread associated to the task + * \param task_id task to start + * \param start_routine entry point for the task + * \param args_p Optional argument to pass to the start routine + * @returns -1 on failure, 0 otherwise + **/ +int intertask_interface_create_task(task_id_t task_id, + void *(*start_routine) (void *), + void *args_p); + +/** \brief Mark the task as in ready state + * \param task_id task to mark as ready + **/ +void intertask_interface_mark_task_ready(task_id_t task_id); + +/** \brief Return the printable string associated with the message + * \param message_id Id of the message + **/ +char *get_message_name(MessagesIds message_id); + +/** \brief Alloc and memset(0) a new itti message. + \param origin_task_id Task ID of the sending task + \param message_id Message ID + @returns NULL in case of failure or newly allocated mesage ref + **/ +inline MessageDef *alloc_new_message( + task_id_t origin_task_id, + MessagesIds message_id); + +void intertask_interface_send_quit_signal(void); + +#endif /* INTERTASK_INTERFACE_H_ */ +/* @} */ diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.c b/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.c new file mode 100644 index 0000000000..3f30c0365a --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.c @@ -0,0 +1,503 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/** @brief Intertask Interface Signal Dumper + * Allows users to connect their itti_debugger to this process and dump + * signals exchanged between tasks. + * @author Sebastien Roux <sebastien.roux@eurecom.fr> + */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <error.h> + +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <sys/types.h> +#include <arpa/inet.h> + +#include "assertions.h" +#include "queue.h" + +#include "mme_default_values.h" + +#include "intertask_interface.h" +#include "intertask_interface_dump.h" + +#define SIGNAL_NAME_LENGTH 50 + +/* Declared in intertask_interface.c */ +extern int itti_debug; + +#define ITTI_DEBUG(x, args...) do { fprintf(stdout, "[ITTI][D]"x, ##args); } \ + while(0) +#define ITTI_ERROR(x, args...) do { fprintf(stdout, "[ITTI][E]"x, ##args); } \ + while(0) + +typedef struct itti_queue_item_s { + STAILQ_ENTRY(itti_queue_item_s) entry; + void *data; + uint32_t data_size; + uint32_t message_number; + char message_name[SIGNAL_NAME_LENGTH]; +} itti_queue_item_t; + +typedef struct { + int sd; + uint32_t last_message_number; +} itti_client_desc_t; + +typedef struct itti_desc_s { + /* The acceptor thread */ + pthread_t itti_acceptor_thread; + pthread_t itti_write_thread; + + /* Protect the circular queue */ + pthread_mutex_t queue_mutex; + + /* List of messages to dump. + * NOTE: we limit the size of this queue to retain only the last exchanged + * messages. The size can be increased by setting up the ITTI_QUEUE_SIZE_MAX + * in mme_default_values.h or by putting a custom in the configuration file. + */ + STAILQ_HEAD(itti_queue_s, itti_queue_item_s) itti_message_queue; + struct itti_queue_item_s *itti_queue_last; + uint32_t queue_size; + + int nb_connected; + + itti_client_desc_t itti_clients[ITTI_DUMP_MAX_CON]; +} itti_desc_t; + +static itti_desc_t itti_queue; + +/* Message sent is an intertask dump type */ +#define ITTI_DUMP_MESSAGE_TYPE 0x1 +#define ITTI_STATISTIC_MESSAGE_TYPE 0x2 +#define ITTI_DUMP_XML_DEFINITION 0x3 + +typedef struct { + /* The size of this structure */ + uint32_t message_size; + uint32_t message_type; +} itti_socket_header_t; + +typedef struct { + itti_socket_header_t header; + + uint32_t message_number; + char signal_name[SIGNAL_NAME_LENGTH]; + + /* Message payload is added here, this struct is used as an header */ +} itti_dump_message_t; + +typedef struct { + itti_socket_header_t header; + +} itti_statistic_message_t; + +static int itti_dump_send_message(int sd, itti_queue_item_t *message); +static int itti_dump_handle_new_connection(int sd, const char *xml_definition, + uint32_t xml_definition_length); +static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml, + const uint32_t message_definition_xml_length); + +static +int itti_dump_send_message(int sd, itti_queue_item_t *message) +{ + int result = 0; + itti_dump_message_t *new_message; + + /* Allocate memory for message header and payload */ + uint32_t size = sizeof(itti_dump_message_t) + message->data_size; + + DevCheck(sd > 0, sd, 0, 0); + DevAssert(message != NULL); + + new_message = calloc(1, size); + DevAssert(new_message != NULL); + + /* Preparing the header */ + new_message->header.message_size = size; + new_message->header.message_type = ITTI_DUMP_MESSAGE_TYPE; + + new_message->message_number = message->message_number; + /* Copy the name, but leaves last byte set to 0 in case name is too long */ + memcpy(new_message->signal_name, message->message_name, SIGNAL_NAME_LENGTH - 1); + /* Appends message payload */ + memcpy(&new_message[1], message->data, message->data_size); + + if (write(sd, new_message, size) == -1) { + ITTI_ERROR("[%d] Failed to write message of size %u to socket (%d:%s)\n", + sd, size, errno, strerror(errno)); + result = -1; + } + + free(new_message); + return result; +} + +static int itti_dump_send_xml_definition(const int sd, const char *message_definition_xml, + const uint32_t message_definition_xml_length) +{ + itti_socket_header_t xml_definition_header; + + DevCheck(sd > 0, sd, 0, 0); + DevAssert(message_definition_xml != NULL); + + ITTI_DEBUG("[%d] Sending XML definition of size %u to observer peer\n", + sd, message_definition_xml_length); + + xml_definition_header.message_size = sizeof(xml_definition_header) + + message_definition_xml_length; + xml_definition_header.message_type = ITTI_DUMP_XML_DEFINITION; + + if (write(sd, &xml_definition_header, sizeof(xml_definition_header)) < 0) { + ITTI_ERROR("[%d] Failed to write header of size %zu to socket (%d:%s)\n", + sd, sizeof(xml_definition_header), errno, strerror(errno)); + return -1; + } + if (write(sd, message_definition_xml, message_definition_xml_length) < 0) { + ITTI_ERROR("[%d] Failed to write XML definition of size %u to socket (%d:%s)\n", + sd, message_definition_xml_length, errno, strerror(errno)); + return -1; + } + return 0; +} + +int itti_dump_queue_message(message_number_t message_number, + MessageDef *message_p, + const char *message_name, + const uint32_t message_size) +{ + itti_queue_item_t *new; + itti_queue_item_t *head = NULL; + size_t message_name_length; + int i; + + DevAssert(message_name != NULL); + DevAssert(message_p != NULL); + + new = calloc(1, sizeof(itti_queue_item_t)); + + if (new == NULL) { + ITTI_ERROR("Failed to allocate memory (%s:%d)\n", + __FILE__, __LINE__); + return -1; + } + + new->data = malloc(message_size); + + if (new->data == NULL) { + ITTI_ERROR("Failed to allocate memory (%s:%d)\n", + __FILE__, __LINE__); + return -1; + } + memcpy(new->data, message_p, message_size); + new->data_size = message_size; + new->message_number = message_number; + + message_name_length = strlen(message_name) + 1; + DevCheck(message_name_length <= SIGNAL_NAME_LENGTH, message_name_length, + SIGNAL_NAME_LENGTH, 0); + memcpy(new->message_name, message_name, message_name_length); + + /* Lock the queue mutex for writing to insert the new element */ + pthread_mutex_lock(&itti_queue.queue_mutex); + + /* We reached the maximum size for the queue of messages -> remove the head */ + if (itti_queue.queue_size + message_size > ITTI_QUEUE_SIZE_MAX) { + head = STAILQ_FIRST(&itti_queue.itti_message_queue); + /* Remove the head */ + STAILQ_REMOVE_HEAD(&itti_queue.itti_message_queue, entry); + } else { + itti_queue.queue_size += message_size; + } + /* Insert the packet at tail */ + STAILQ_INSERT_TAIL(&itti_queue.itti_message_queue, new, entry); + itti_queue.itti_queue_last = new; + + /* Release the mutex */ + pthread_mutex_unlock(&itti_queue.queue_mutex); + + for (i = 0; i < ITTI_DUMP_MAX_CON; i++) { + if (itti_queue.itti_clients[i].sd == -1) + continue; + itti_dump_send_message(itti_queue.itti_clients[i].sd, new); + } + + /* No need to have the mutex locked to free data as at this point the message + * is no more in the list. + */ + if (head) { + free(head->data); + free(head); + head = NULL; + } + + return 0; +} + +static void *itti_dump_socket(void *arg_p) +{ + uint32_t message_definition_xml_length; + char *message_definition_xml; + int rc; + int itti_listen_socket, max_sd; + int on = 1; + fd_set master_set, working_set; + struct sockaddr_in servaddr; /* socket address structure */ + + ITTI_DEBUG("Creating TCP dump socket on port %u\n", ITTI_PORT); + + message_definition_xml = (char *)arg_p; + DevAssert(message_definition_xml != NULL); + + message_definition_xml_length = strlen(message_definition_xml) + 1; + + if ((itti_listen_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + ITTI_ERROR("Socket creation failed (%d:%s)\n", errno, strerror(errno)); + pthread_exit(NULL); + } + + /* Allow socket reuse */ + rc = setsockopt(itti_listen_socket, SOL_SOCKET, SO_REUSEADDR, + (char *)&on, sizeof(on)); + if (rc < 0) { + ITTI_ERROR("setsockopt SO_REUSEADDR failed (%d:%s)\n", errno, strerror(errno)); + close(itti_listen_socket); + pthread_exit(NULL); + } + + /* Set socket to be non-blocking. + * NOTE: sockets accepted will inherit this option. + */ + rc = ioctl(itti_listen_socket, FIONBIO, (char *)&on); + if (rc < 0) { + ITTI_ERROR("ioctl FIONBIO (non-blocking) failed (%d:%s)\n", errno, strerror(errno)); + close(itti_listen_socket); + pthread_exit(NULL); + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(ITTI_PORT); + + if (bind(itti_listen_socket, (struct sockaddr *) &servaddr, + sizeof(servaddr)) < 0 ) { + ITTI_ERROR("Bind failed (%d:%s)\n", errno, strerror(errno)); + pthread_exit(NULL); + } + if (listen(itti_listen_socket, 5) < 0 ) { + ITTI_ERROR("Listen failed (%d:%s)\n", errno, strerror(errno)); + pthread_exit(NULL); + } + + FD_ZERO(&master_set); + max_sd = itti_listen_socket; + FD_SET(itti_listen_socket, &master_set); + + /* Loop waiting for incoming connects or for incoming data + * on any of the connected sockets. + */ + while (1) { + int desc_ready; + int client_socket = -1; + int i; + + memcpy(&working_set, &master_set, sizeof(master_set)); + + ITTI_DEBUG("Stuck on select\n"); + + /* No timeout: select blocks till a new event has to be handled + * on sd's. + */ + rc = select(max_sd + 1, &working_set, NULL, NULL, NULL); + + if (rc < 0) { + ITTI_ERROR("select failed (%d:%s)\n", errno, strerror(errno)); + pthread_exit(NULL); + } + + desc_ready = rc; + for (i = 0; i <= max_sd && desc_ready > 0; i++) { + if (FD_ISSET(i, &working_set)) { + ITTI_DEBUG("Handling socket %d\n", i); + desc_ready -= 1; + /* Check if the socket where data available is the listening + * socket. + */ + if (i == itti_listen_socket) { + do { + client_socket = accept(itti_listen_socket, NULL, NULL); + if (client_socket < 0) { + if (errno == EWOULDBLOCK || errno == EAGAIN) { + /* No more new connection */ + ITTI_DEBUG("No more new connection\n"); + continue; + } else { + ITTI_ERROR("accept failed (%d:%s)\n", errno, strerror(errno)); + pthread_exit(NULL); + } + } + if (itti_dump_handle_new_connection(client_socket, message_definition_xml, + message_definition_xml_length) == 0) { + /* The socket has been accepted. + * We have to update the set to include this new sd. + */ + FD_SET(client_socket, &master_set); + if (client_socket > max_sd) + max_sd = client_socket; + } + } while(client_socket != -1); + } else { + /* For now the MME itti dumper should not receive data + * other than connection oriented (CLOSE). + */ + uint8_t j; + + ITTI_DEBUG("Socket %d disconnected\n", i); + + /* Close the socket and update info related to this connection */ + close(i); + + for (j = 0; j < ITTI_DUMP_MAX_CON; j++) { + if (itti_queue.itti_clients[j].sd == i) + break; + } + + /* In case we don't find the matching sd in list of known + * connections -> assert. + */ + DevCheck(j < ITTI_DUMP_MAX_CON, j, ITTI_DUMP_MAX_CON, i); + + /* Re-initialize the socket to -1 so we can accept new + * incoming connections. + */ + itti_queue.itti_clients[j].sd = -1; + itti_queue.itti_clients[j].last_message_number = 0; + itti_queue.nb_connected--; + + /* Remove the socket from the FD set and update the max sd */ + FD_CLR(i, &master_set); + if (i == max_sd) + { + if (itti_queue.nb_connected == 0) { + /* No more new connection max_sd = itti_listen_socket */ + max_sd = itti_listen_socket; + } else { + while (FD_ISSET(max_sd, &master_set) == FALSE) { + max_sd -= 1; + } + } + } + } + } + } + } + return NULL; +} + +static +int itti_dump_handle_new_connection(int sd, const char *xml_definition, uint32_t xml_definition_length) +{ + if (itti_queue.nb_connected < ITTI_DUMP_MAX_CON) { + itti_queue_item_t *item; + uint8_t i; + + for (i = 0; i < ITTI_DUMP_MAX_CON; i++) { + /* Let's find a place to store the new client */ + if (itti_queue.itti_clients[i].sd == -1) { + break; + } + } + + ITTI_DEBUG("Found place to store new connection: %d\n", i); + + DevCheck(i < ITTI_DUMP_MAX_CON, i, ITTI_DUMP_MAX_CON, sd); + itti_queue.itti_clients[i].sd = sd; + itti_queue.nb_connected++; + + ITTI_DEBUG("Socket %d accepted\n", sd); + + /* Send the XML message definition */ + if (itti_dump_send_xml_definition(sd, xml_definition, xml_definition_length) < 0) { + ITTI_ERROR("Failed to send XML definition\n"); + close (sd); + return -1; + } + + /* At this point we have to dump the complete list */ + pthread_mutex_lock(&itti_queue.queue_mutex); + STAILQ_FOREACH(item, &itti_queue.itti_message_queue, entry) { + itti_dump_send_message(sd, item); + } + pthread_mutex_unlock(&itti_queue.queue_mutex); + } else { + ITTI_DEBUG("Socket %d rejected\n", sd); + /* We have reached max number of users connected... + * Reject the connection. + */ + close (sd); + return -1; + } + + return 0; +} + +int itti_dump_init(const char * const messages_definition_xml) +{ + int i; + + memset(&itti_queue, 0, sizeof(itti_desc_t)); + + pthread_mutex_init(&itti_queue.queue_mutex, NULL); + STAILQ_INIT(&itti_queue.itti_message_queue); + itti_queue.queue_size = 0; + itti_queue.nb_connected = 0; + + for(i = 0; i < ITTI_DUMP_MAX_CON; i++) { + itti_queue.itti_clients[i].sd = -1; + itti_queue.itti_clients[i].last_message_number = 0; + } + if (pthread_create(&itti_queue.itti_acceptor_thread, NULL, &itti_dump_socket, + (void *)messages_definition_xml) < 0) { + ITTI_ERROR("pthread_create failed (%d:%s)\n", errno, strerror(errno)); + return -1; + } + return 0; +} diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.h b/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.h new file mode 100644 index 0000000000..071e811cf6 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface_dump.h @@ -0,0 +1,41 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef INTERTASK_INTERFACE_DUMP_H_ +#define INTERTASK_INTERFACE_DUMP_H_ + +int itti_dump_queue_message(message_number_t message_number, + MessageDef *message_p, + const char *message_name, + const uint32_t message_size); + +int itti_dump_init(const char * const messages_definition_xml); + +#endif /* INTERTASK_INTERFACE_DUMP_H_ */ diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface_init.h b/openair-cn/INTERTASK_INTERFACE/intertask_interface_init.h new file mode 100644 index 0000000000..9d8d51fab6 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface_init.h @@ -0,0 +1,87 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms + * Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +/******************************************************************************** + * + * !!! This header should only be included by the file that initialize + * the intertask interface module for the process !!! + * + * Other files should include "intertask_interface.h" + * + *******************************************************************************/ + +#ifndef INTERTASK_INTERFACE_INIT_H_ +#define INTERTASK_INTERFACE_INIT_H_ + +#include "intertask_interface.h" + +#ifndef CHECK_PROTOTYPE_ONLY + +const char * const messages_definition_xml = { +#include "../messages_xml.h" +}; + +/* Map thread id to printable name. */ +const char * const threads_name[] = { + "unused", +#define TASK_DEF(tHREADiD, pRIO) #tHREADiD, +#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) +#include <tasks_def.h> +#undef SUB_TASK_DEF +#undef TASK_DEF +}; + +/* Map message id to message information */ +const message_info_t messages_info[] = { +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) { iD, pRIO, sizeof(sTRUCT), #iD }, +#include <messages_def.h> +#undef MESSAGE_DEF +}; + +#endif + +/** \brief Init function for the intertask interface. Init queues, Mutexes and Cond vars. + * \param thread_max Maximum number of threads + * \param messages_id_max Maximum message id + * \param threads_name Pointer on the threads name information as created by this include file + * \param messages_info Pointer on messages information as created by this include file + **/ +int intertask_interface_init(thread_id_t thread_max, MessagesIds messages_id_max, + const char * const *threads_name, const message_info_t *messages_info, + const char * const messages_definition_xml); + +#endif /* INTERTASK_INTERFACE_INIT_H_ */ +/* @} */ diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_interface_types.h b/openair-cn/INTERTASK_INTERFACE/intertask_interface_types.h new file mode 100644 index 0000000000..2f914daa97 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_interface_types.h @@ -0,0 +1,145 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + + *******************************************************************************/ + +/** @defgroup _intertask_interface_impl_ Intertask Interface Mechanisms + * Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef INTERTASK_INTERFACE_TYPES_H_ +#define INTERTASK_INTERFACE_TYPES_H_ + +/* Defines to handle bit fields on unsigned long values */ +#define UL_BIT_MASK(lENGTH) ((1UL << (lENGTH)) - 1UL) +#define UL_BIT_SHIFT(vALUE, oFFSET) ((vALUE) << (oFFSET)) +#define UL_BIT_UNSHIFT(vALUE, oFFSET) ((vALUE) >> (oFFSET)) + +#define UL_FIELD_MASK(oFFSET, lENGTH) UL_BIT_SHIFT(UL_BIT_MASK(lENGTH), (oFFSET)) +#define UL_FIELD_INSERT(vALUE, fIELD, oFFSET, lENGTH) (((vALUE) & (~UL_FIELD_MASK(oFFSET, lENGTH))) | UL_BIT_SHIFT(((fIELD) & UL_BIT_MASK(lENGTH)), oFFSET)) +#define UL_FIELD_EXTRACT(vALUE, oFFSET, lENGTH) (UL_BIT_UNSHIFT((vALUE), (oFFSET)) & UL_BIT_MASK(lENGTH)) + +/* Definitions of task ID fields */ +#define TASK_THREAD_ID_OFFSET 8 +#define TASK_THREAD_ID_LENGTH 8 + +#define TASK_SUB_TASK_ID_OFFSET 0 +#define TASK_SUB_TASK_ID_LENGTH 8 + +/* Defines to extract task ID fields */ +#define TASK_GET_THREAD_ID(tASKiD) UL_FIELD_EXTRACT(tASKiD, TASK_THREAD_ID_OFFSET, TASK_THREAD_ID_LENGTH) +#define TASK_GET_SUB_TASK_ID(tASKiD) UL_FIELD_EXTRACT(tASKiD, TASK_SUB_TASK_ID_OFFSET, TASK_SUB_TASK_ID_LENGTH) + +#include <messages_types.h> + +/* This enum defines messages ids. Each one is unique. */ +typedef enum +{ +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) iD, +#include <messages_def.h> +#undef MESSAGE_DEF + + MESSAGES_ID_MAX, MESSAGES_ID_END = MESSAGES_ID_MAX +} MessagesIds; + +//! Thread id of each task +typedef enum +{ + THREAD_FIRST = 1, THREAD_NULL = 0, + +#define TASK_DEF(tHREADiD, pRIO) THREAD_##tHREADiD, +#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) +#include <tasks_def.h> +#undef SUB_TASK_DEF +#undef TASK_DEF + + THREAD_MAX, THREAD_END = THREAD_MAX, +} thread_id_t; + +//! Sub-tasks id, to defined offset form thread id +typedef enum +{ +#define TASK_DEF(tHREADiD, pRIO) SUB_TASK_INIT_##tHREADiD = 0, +#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) SUB_TASK_OFFSET_##sUBtASKiD, +#include <tasks_def.h> +#undef SUB_TASK_DEF +#undef TASK_DEF +} sub_task_id_t; + +//! Tasks id of each task +typedef enum +{ +#define TASK_DEF(tHREADiD, pRIO) tHREADiD = UL_BIT_SHIFT(THREAD_##tHREADiD, TASK_THREAD_ID_OFFSET), +#define SUB_TASK_DEF(tHREADiD, sUBtASKiD) sUBtASKiD = (UL_BIT_SHIFT(THREAD_##tHREADiD, TASK_THREAD_ID_OFFSET) | UL_BIT_SHIFT(SUB_TASK_OFFSET_##sUBtASKiD, TASK_SUB_TASK_ID_OFFSET)), +#include <tasks_def.h> +#undef SUB_TASK_DEF +#undef TASK_DEF + + TASK_UNKNOWN = 0xFFFF, +} task_id_t; + +typedef union msg_s +{ +#define MESSAGE_DEF(iD, pRIO, sTRUCT, fIELDnAME) sTRUCT fIELDnAME; +#include <messages_def.h> +#undef MESSAGE_DEF +} msg_t; + +#define INSTANCE_DEFAULT 0 +#define INSTANCE_ALL -1 + +typedef int16_t instance_t; +typedef uint16_t MessageHeaderSize; + +/** @struct MessageHeader + * @brief Message Header structure for inter-task communication. + */ +typedef struct MessageHeader_s +{ + MessagesIds messageId; /**< Unique message id as referenced in enum MessagesIds */ + + task_id_t originTaskId; /**< ID of the sender task */ + task_id_t destinationTaskId; /**< ID of the destination task */ + instance_t instance; /* Task instance for virtualization */ + + MessageHeaderSize size; /**< Message size (not including header size) */ +} MessageHeader; + +/** @struct MessageDef + * @brief Message structure for inter-task communication. + */ +typedef struct MessageDef_s +{ + MessageHeader header; /**< Message header */ + msg_t msg; /**< Union of payloads as defined in x_messages_def.h headers */ +} MessageDef; + +#endif /* INTERTASK_INTERFACE_TYPES_H_ */ +/* @} */ diff --git a/openair-cn/INTERTASK_INTERFACE/intertask_messages_def.h b/openair-cn/INTERTASK_INTERFACE/intertask_messages_def.h new file mode 100644 index 0000000000..cf36d06e3e --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/intertask_messages_def.h @@ -0,0 +1,5 @@ +/* This message asks for task termination */ +MESSAGE_DEF(TERMINATE_MESSAGE, MESSAGE_PRIORITY_MAX, struct {}, terminate_message) +/* Test message used for debug */ +MESSAGE_DEF(MESSAGE_TEST, MESSAGE_PRIORITY_MAX, struct {}, message_test) + diff --git a/openair-cn/INTERTASK_INTERFACE/messages_def.h b/openair-cn/INTERTASK_INTERFACE/messages_def.h new file mode 100644 index 0000000000..384a404993 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/messages_def.h @@ -0,0 +1,5 @@ +// These messages files are mandatory and must always be placed in first position +#include "intertask_messages_def.h" +#include "timer_messages_def.h" + +// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory. diff --git a/openair-cn/INTERTASK_INTERFACE/messages_types.h b/openair-cn/INTERTASK_INTERFACE/messages_types.h new file mode 100644 index 0000000000..b6a45fe62a --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/messages_types.h @@ -0,0 +1,15 @@ +/* + * messages_types.h + * + * Created on: Oct 14, 2013 + * Author: winckel + */ + +#ifndef MESSAGES_TYPES_H_ +#define MESSAGES_TYPES_H_ + +#include "timer_messages_types.h" + +// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory. + +#endif /* MESSAGES_TYPES_H_ */ diff --git a/openair-cn/INTERTASK_INTERFACE/tasks_def.h b/openair-cn/INTERTASK_INTERFACE/tasks_def.h new file mode 100644 index 0000000000..09de9ca470 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/tasks_def.h @@ -0,0 +1,4 @@ +// This task is mandatory and must always be placed in first position +TASK_DEF(TASK_TIMER, TASK_PRIORITY_MED) + +// Dummy file for the generic intertask interface definition. Actual definition should be in top level build directory. diff --git a/openair-cn/INTERTASK_INTERFACE/timer.c b/openair-cn/INTERTASK_INTERFACE/timer.c new file mode 100644 index 0000000000..b1314696b3 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/timer.c @@ -0,0 +1,251 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <signal.h> +#include <time.h> +#include <errno.h> + +#include "assertions.h" +#include "intertask_interface.h" +#include "timer.h" + +#include "queue.h" + +#ifndef TMR_DEBUG +# define TMR_DEBUG(x, args...) do { fprintf(stdout, "[TMR] [D]"x, ##args); } while(0) +#endif +#ifndef TMR_ERROR +# define TMR_ERROR(x, args...) do { fprintf(stdout, "[TMR] [E]"x, ##args); } while(0) +#endif + +int timer_handle_signal(siginfo_t *info); + +struct timer_elm_s { + task_id_t task_id; ///< Task ID which has requested the timer + int32_t instance; ///< Instance of the task which has requested the timer + timer_t timer; ///< Unique timer id + timer_type_t type; ///< Timer type + void *timer_arg; ///< Optional argument that will be passed when timer expires + STAILQ_ENTRY(timer_elm_s) entries; ///< Pointer to next element +}; + +typedef struct timer_desc_s { + STAILQ_HEAD(timer_list_head, timer_elm_s) timer_queue; + pthread_mutex_t timer_list_mutex; + struct timespec timeout; +} timer_desc_t; + +static timer_desc_t timer_desc; + +#define TIMER_SEARCH(vAR, tIMERfIELD, tIMERvALUE, tIMERqUEUE) \ +do { \ + STAILQ_FOREACH(vAR, tIMERqUEUE, entries) { \ + if (((vAR)->tIMERfIELD == tIMERvALUE)) \ + break; \ + } \ +} while(0) + +int timer_handle_signal(siginfo_t *info) +{ + struct timer_elm_s *timer_p; + MessageDef *message_p; + timer_has_expired_t *timer_expired_p; + task_id_t task_id; + int32_t instance; + + /* Get back pointer to timer list element */ + timer_p = (struct timer_elm_s *)info->si_ptr; + + TMR_DEBUG("Timer with id 0x%lx has expired\n", (long)timer_p->timer); + + task_id = timer_p->task_id; + instance = timer_p->instance; + message_p = alloc_new_message(TASK_TIMER, TIMER_HAS_EXPIRED); + + timer_expired_p = &message_p->msg.timer_has_expired; + + timer_expired_p->timer_id = (long)timer_p->timer; + timer_expired_p->arg = timer_p->timer_arg; + + /* Timer is a one shot timer, remove it */ + if (timer_p->type == TIMER_ONE_SHOT) { +// if (timer_delete(timer_p->timer) < 0) { +// TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer); +// } +// TMR_DEBUG("Removed timer 0x%lx\n", (long)timer_p->timer); +// pthread_mutex_lock(&timer_desc.timer_list_mutex); +// STAILQ_REMOVE(&timer_desc.timer_queue, timer_p, timer_elm_s, entries); +// pthread_mutex_unlock(&timer_desc.timer_list_mutex); +// free(timer_p); +// timer_p = NULL; + if (timer_remove((long)timer_p->timer) != 0) { + TMR_DEBUG("Failed to delete timer 0x%lx\n", (long)timer_p->timer); + } + } + /* Notify task of timer expiry */ + if (send_msg_to_task(task_id, instance, message_p) < 0) { + TMR_DEBUG("Failed to send msg TIMER_HAS_EXPIRED to task %u\n", task_id); + free(message_p); + return -1; + } + + return 0; +} + +int timer_setup( + uint32_t interval_sec, + uint32_t interval_us, + task_id_t task_id, + int32_t instance, + timer_type_t type, + void *timer_arg, + long *timer_id) +{ + struct sigevent se; + struct itimerspec its; + struct timer_elm_s *timer_p; + timer_t timer; + + if (timer_id == NULL) { + return -1; + } + DevAssert(type < TIMER_TYPE_MAX); + + /* Allocate new timer list element */ + timer_p = malloc(sizeof(struct timer_elm_s)); + if (timer_p == NULL) { + TMR_ERROR("Failed to create new timer element\n"); + return -1; + } + + memset(&timer, 0, sizeof(timer_t)); + memset(&se, 0, sizeof(struct sigevent)); + + timer_p->task_id = task_id; + timer_p->instance = instance; + timer_p->type = type; + timer_p->timer_arg = timer_arg; + + /* Setting up alarm */ + /* Set and enable alarm */ + se.sigev_notify = SIGEV_SIGNAL; + se.sigev_signo = SIGTIMER; + se.sigev_value.sival_ptr = timer_p; + /* At the timer creation, the timer structure will be filled in with timer_id, + * which is unique for this process. This id is allocated by kernel and the + * value might be used to distinguish timers. + */ + if (timer_create(CLOCK_REALTIME, &se, &timer) < 0) { + TMR_ERROR("Failed to create timer: (%s:%d)\n", strerror(errno), errno); + free(timer_p); + return -1; + } + + /* Fill in the first expiration value. */ + its.it_value.tv_sec = interval_sec; + its.it_value.tv_nsec = interval_us * 1000; + + if (type == TIMER_PERIODIC) { + /* Asked for periodic timer. We set the interval time */ + its.it_interval.tv_sec = interval_sec; + its.it_interval.tv_nsec = interval_us * 1000; + } else { + /* Asked for one-shot timer. Do not set the interval field */ + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + } + timer_settime(timer, 0, &its, NULL); + /* Simply set the timer_id argument. so it can be used by caller */ + *timer_id = (long)timer; + TMR_DEBUG("Requesting new %s timer with id 0x%lx that expires within " + "%d sec and %d usec\n", + type == TIMER_PERIODIC ? "periodic" : "single shot", + *timer_id, interval_sec, interval_us); + + timer_p->timer = timer; + + /* Lock the queue and insert the timer at the tail */ + pthread_mutex_lock(&timer_desc.timer_list_mutex); + STAILQ_INSERT_TAIL(&timer_desc.timer_queue, timer_p, entries); + pthread_mutex_unlock(&timer_desc.timer_list_mutex); + + return 0; +} + +int timer_remove(long timer_id) +{ + struct timer_elm_s *timer_p; + int rc = 0; + + TMR_DEBUG("Removing timer 0x%lx\n", timer_id); + + pthread_mutex_lock(&timer_desc.timer_list_mutex); + TIMER_SEARCH(timer_p, timer, ((timer_t)timer_id), &timer_desc.timer_queue); + + /* We didn't find the timer in list */ + if (timer_p == NULL) { + pthread_mutex_unlock(&timer_desc.timer_list_mutex); + TMR_ERROR("Didn't find timer 0x%lx in list\n", (long)timer_p->timer); + return -1; + } + + STAILQ_REMOVE(&timer_desc.timer_queue, timer_p, timer_elm_s, entries); + pthread_mutex_unlock(&timer_desc.timer_list_mutex); + + if (timer_delete(timer_p->timer) < 0) { + TMR_ERROR("Failed to delete timer 0x%lx\n", (long)timer_p->timer); + rc = -1; + } + free(timer_p); + timer_p = NULL; + return rc; +} + +int timer_init(void) +{ + TMR_DEBUG("Initializing TIMER task interface\n"); + + memset(&timer_desc, 0, sizeof(timer_desc_t)); + + STAILQ_INIT(&timer_desc.timer_queue); + pthread_mutex_init(&timer_desc.timer_list_mutex, NULL); + + timer_desc.timeout.tv_sec = MME_TIMER_TIMEOUT_S; + timer_desc.timeout.tv_nsec = MME_TIMER_TIMEOUT_NS; + + TMR_DEBUG("Initializing TIMER task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/INTERTASK_INTERFACE/timer.h b/openair-cn/INTERTASK_INTERFACE/timer.h new file mode 100644 index 0000000000..4acff6b809 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/timer.h @@ -0,0 +1,76 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "mme_config.h" + +#ifndef TIMER_H_ +#define TIMER_H_ + +#define SIGTIMER SIGRTMIN + +typedef enum timer_type_s { + TIMER_PERIODIC, + TIMER_ONE_SHOT, + TIMER_TYPE_MAX, +} timer_type_t; + +/** \brief Request a new timer + * \param interval_sec timer interval in seconds + * \param interval_us timer interval in micro seconds + * \param task_id task id of the task requesting the timer + * \param instance instance of the task requesting the timer + * \param type timer type + * \param timer_id unique timer identifier + * @returns -1 on failure, 0 otherwise + **/ +int timer_setup( + uint32_t interval_sec, + uint32_t interval_us, + task_id_t task_id, + int32_t instance, + timer_type_t type, + void *timer_arg, + long *timer_id); + +/** \brief Remove the timer from list + * \param timer_id unique timer id + * @returns -1 on failure, 0 otherwise + **/ + +int timer_remove(long timer_id); +#define timer_stop timer_remove + +/** \brief Initialize timer task and its API + * \param mme_config MME common configuration + * @returns -1 on failure, 0 otherwise + **/ +int timer_init(); + +#endif diff --git a/openair-cn/INTERTASK_INTERFACE/timer_messages_def.h b/openair-cn/INTERTASK_INTERFACE/timer_messages_def.h new file mode 100644 index 0000000000..47955de591 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/timer_messages_def.h @@ -0,0 +1 @@ +MESSAGE_DEF(TIMER_HAS_EXPIRED, MESSAGE_PRIORITY_MED_PLUS, timer_has_expired_t, timer_has_expired) diff --git a/openair-cn/INTERTASK_INTERFACE/timer_messages_types.h b/openair-cn/INTERTASK_INTERFACE/timer_messages_types.h new file mode 100644 index 0000000000..968e319424 --- /dev/null +++ b/openair-cn/INTERTASK_INTERFACE/timer_messages_types.h @@ -0,0 +1,9 @@ +#ifndef TIMER_MESSAGES_TYPES_H_ +#define TIMER_MESSAGES_TYPES_H_ + +typedef struct { + void *arg; + long timer_id; +} timer_has_expired_t; + +#endif /* TIMER_MESSAGES_TYPES_H_ */ diff --git a/openair-cn/MME_APP/Makefile.am b/openair-cn/MME_APP/Makefile.am new file mode 100644 index 0000000000..396860d4c0 --- /dev/null +++ b/openair-cn/MME_APP/Makefile.am @@ -0,0 +1,21 @@ +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/S1AP \ + -I$(top_srcdir)/S6A \ + -I$(top_srcdir)/SCTP \ + -I$(top_srcdir)/SECU \ + -I$(top_srcdir)/UTILS + +noinst_LTLIBRARIES = libmmeapp.la +libmmeapp_la_LDFLAGS = -all-static + +libmmeapp_la_SOURCES = \ + mme_app_context.c \ + mme_app_main.c mme_app_defs.h \ + mme_app_bearer.c \ + mme_app_authentication.c \ + mme_app_statistics.c mme_app_statistics.h \ + mme_app_defs.h mme_app_extern.h \ + s6a_2_nas_cause.c diff --git a/openair-cn/MME_APP/mme_app_authentication.c b/openair-cn/MME_APP/mme_app_authentication.c new file mode 100644 index 0000000000..edba681e2d --- /dev/null +++ b/openair-cn/MME_APP/mme_app_authentication.c @@ -0,0 +1,285 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "intertask_interface.h" + +#include "mme_config.h" + +#include "mme_app_ue_context.h" +#include "mme_app_defs.h" + +#include "assertions.h" + +int mme_app_request_authentication_info(const mme_app_imsi_t imsi, + const uint8_t nb_of_vectors, + const plmn_t *plmn); + +int mme_app_request_authentication_info(const mme_app_imsi_t imsi, + const uint8_t nb_of_vectors, + const plmn_t *plmn) +{ + s6a_auth_info_req_t *auth_info_req; + MessageDef *message_p; + + DevAssert(plmn != NULL); + + message_p = alloc_new_message(TASK_MME_APP, S6A_AUTH_INFO_REQ); + + if (message_p == NULL) return -1; + + auth_info_req = &message_p->msg.s6a_auth_info_req; + MME_APP_IMSI_TO_STRING(imsi, auth_info_req->imsi); + memcpy(&auth_info_req->visited_plmn, plmn, sizeof(plmn_t)); + auth_info_req->nb_of_vectors = nb_of_vectors; + + return send_msg_to_task(TASK_S6A, INSTANCE_DEFAULT, message_p); +} + +int mme_app_handle_nas_auth_resp(nas_auth_resp_t *nas_auth_resp_p) +{ + struct ue_context_s *ue_context; + uint64_t imsi; + + DevAssert(nas_auth_resp_p != NULL); + + MME_APP_STRING_TO_IMSI((char *)nas_auth_resp_p->imsi, &imsi); + + MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", imsi); + + if ((ue_context = mme_ue_context_exists_imsi(&mme_app_desc.mme_ue_contexts, imsi)) == NULL) { + MME_APP_ERROR("That's embarrassing as we don't know this IMSI\n"); + return -1; + } + + /* Consider the UE authenticated */ + ue_context->imsi_auth = IMSI_AUTHENTICATED; + + /* TODO: Get keys... */ + + /* Now generate S6A ULR */ + { + MessageDef *message_p; + s6a_update_location_req_t *s6a_ulr; + + message_p = alloc_new_message(TASK_MME_APP, S6A_UPDATE_LOCATION_REQ); + + if (message_p == NULL) { + return -1; + } + + s6a_ulr = &message_p->msg.s6a_update_location_req; + + memcpy(s6a_ulr->imsi, nas_auth_resp_p->imsi, 16); + s6a_ulr->initial_attach = INITIAL_ATTACH; + s6a_ulr->rat_type = RAT_EUTRAN; + /* Check if we already have UE data */ + s6a_ulr->skip_subsriber_data = 0; + + return send_msg_to_task(TASK_S6A, INSTANCE_DEFAULT, message_p); + } + return -1; +} + +int mme_app_handle_authentication_info_answer(s6a_auth_info_ans_t *s6a_auth_info_ans_p) +{ + struct ue_context_s *ue_context; + uint64_t imsi; + + nas_auth_req_t *nas_auth_req_p; + MessageDef *message_p = NULL; + + DevAssert(s6a_auth_info_ans_p != NULL); + + message_p = alloc_new_message(TASK_MME_APP, NAS_AUTHENTICATION_REQ); + + if (message_p == NULL) { + return -1; + } + + nas_auth_req_p = &message_p->msg.nas_auth_req; + + MME_APP_STRING_TO_IMSI((char *)s6a_auth_info_ans_p->imsi, &imsi); + + MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", imsi); + + memcpy(nas_auth_req_p->imsi, s6a_auth_info_ans_p->imsi, 16); + + if ((ue_context = mme_ue_context_exists_imsi(&mme_app_desc.mme_ue_contexts, imsi)) == NULL) { + MME_APP_ERROR("That's embarrassing as we don't know this IMSI\n"); + free(message_p); + return -1; + } + + if ((s6a_auth_info_ans_p->result.present == S6A_RESULT_BASE) && + (s6a_auth_info_ans_p->result.choice.base == DIAMETER_SUCCESS)) + { + /* S6A procedure has succeeded. + * We have to request UE authentication. + */ + + /* Check that list is not empty and contain only one element */ + DevCheck(s6a_auth_info_ans_p->auth_info.nb_of_vectors == 1, + s6a_auth_info_ans_p->auth_info.nb_of_vectors, 1, 0); + DevAssert(!STAILQ_EMPTY(&s6a_auth_info_ans_p->auth_info.e_utran_vectors)); + + /* Concat both lists */ + STAILQ_CONCAT(&ue_context->vector_list, + &s6a_auth_info_ans_p->auth_info.e_utran_vectors); + + ue_context->nb_of_vectors += s6a_auth_info_ans_p->auth_info.nb_of_vectors; + + nas_auth_req_p->failure = NAS_FAILURE_OK; + + ue_context->vector_in_use = STAILQ_FIRST(&ue_context->vector_list); + +// mme_app_dump_ue_contexts(); + } else { + // nas_auth_req_p->failure = NAS_FAILURE_IND; + // nas_auth_req_p->cause = s6a_error_2_nas_cause( +// s6a_auth_info_ans_p->result.choice.base, 0); + DevMessage("TODO: Handle s6a_auth_info_ans_p->result.present " + "!= S6A_RESULT_BASE"); + } + + return send_msg_to_task(TASK_NAS, INSTANCE_DEFAULT, message_p); +} + +int mme_app_handle_attach_req(nas_attach_req_t *attach_req_p) +{ + /* An attach request has been received from NAS layer. + * If the UE authentication vectors for the UE are known within MME then the + * authentication procedure should be triggered only if the request is an + * initial attach, otherwise an update location should be sent to the HSS + * and default bearer should be established for the provided APN. + * In case of initial attach procedure, the default APN retrieved from the + * HSS will be used to establish the default bearer within EPC. + * The default APN is the one that matches the context-identifier + */ + struct ue_context_s *ue_context; + uint64_t imsi = 0; + + DevAssert(attach_req_p != NULL); + + MME_APP_STRING_TO_IMSI((char *)attach_req_p->imsi, &imsi); + + MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", imsi); + + ue_context = mme_ue_context_exists_imsi(&mme_app_desc.mme_ue_contexts, imsi); + if (ue_context == NULL) { + /* The MME doesn't know this IMSI. + * Insert the UE to the list of known equipements and + * Retrieve the authentication vector from HSS. + */ + MME_APP_DEBUG("UE context doesn't exist -> create one\n"); + if ((ue_context = mme_create_new_ue_context()) == NULL) { + /* Error during ue context malloc */ + /* TODO */ + DevMessage("mme_create_new_ue_context"); + return -1; + } + ue_context->imsi = imsi; + + ue_context->eNB_ue_s1ap_id = attach_req_p->transparent.eNB_ue_s1ap_id; + ue_context->mme_ue_s1ap_id = attach_req_p->transparent.mme_ue_s1ap_id; + + STAILQ_INIT(&ue_context->vector_list); + DevAssert(mme_insert_ue_context(&mme_app_desc.mme_ue_contexts, ue_context) == 0); + goto request_auth; + } else { + /* MME knows this IMSI, check if UE is authenticated and authentication + * vectors are known. + */ + MME_APP_DEBUG("UE context already exists, use it\n"); + + /* Update mme ue s1ap id */ + ue_context->mme_ue_s1ap_id = attach_req_p->transparent.mme_ue_s1ap_id; + + if ((ue_context->imsi_auth == IMSI_AUTHENTICATED) && + (attach_req_p->initial != INITIAL_REQUEST)) + { + /* We have to send an update location request to the HSS */ + MME_APP_DEBUG("UE is authenticated\n"); + } else { + MME_APP_DEBUG("UE is not authenticated\n"); + /* UE is not authenticated or an initial request */ + if (STAILQ_EMPTY(&ue_context->vector_list)) +request_auth: + { + /* We have no vector for this UE, send an authentication request + * to the HSS. + */ + plmn_t plmn = { + .MCCdigit2 = 0, + .MCCdigit1 = 8, + .MCCdigit3 = 2, + .MNCdigit1 = 0, + .MNCdigit2 = 4, + .MNCdigit3 = 3, + }; + + memcpy(&ue_context->e_utran_cgi, &attach_req_p->transparent.e_utran_cgi, + sizeof(cgi_t)); + + /* Acquire the current time */ + time(&ue_context->cell_age); + + /* Some random values for GUTI */ + ue_context->guti.m_tmsi = 0x24568956; + ue_context->guti.gummei.MMEcode = 0x01; + ue_context->guti.gummei.MMEgid = 0x5691; + + memcpy(&ue_context->guti.gummei.plmn, &plmn, sizeof(plmn_t)); + MME_APP_DEBUG("and we have no auth. vector for it, request" + " authentication information\n"); +// mme_app_dump_ue_contexts(); + mme_app_request_authentication_info(imsi, 1, &plmn); + } else { + nas_auth_req_t *nas_auth_req_p; + MessageDef *message_p; + /* We have a vector... USE it */ + MME_APP_DEBUG("but we have an auth. vector for it, request" + " authentication from NAS\n"); + message_p = alloc_new_message(TASK_MME_APP, NAS_AUTHENTICATION_REQ); + + nas_auth_req_p = &message_p->msg.nas_auth_req; + + MME_APP_IMSI_TO_STRING(imsi, nas_auth_req_p->imsi); + nas_auth_req_p->failure = NAS_FAILURE_OK; + + return send_msg_to_task(TASK_NAS, INSTANCE_DEFAULT, message_p); + } + } + } + return 0; +} diff --git a/openair-cn/MME_APP/mme_app_bearer.c b/openair-cn/MME_APP/mme_app_bearer.c new file mode 100644 index 0000000000..7eff8c9cda --- /dev/null +++ b/openair-cn/MME_APP/mme_app_bearer.c @@ -0,0 +1,351 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "intertask_interface.h" + +#include "mme_app_extern.h" +#include "mme_app_ue_context.h" +#include "mme_app_defs.h" + +#include "secu_defs.h" + +#include "assertions.h" + +int mme_app_create_bearer(s6a_update_location_ans_t *ula_p) +{ + uint64_t imsi; + uint8_t i; + task_id_t to_task; + + struct ue_context_s *ue_context; + + MessageDef *message_p; + SgwCreateSessionRequest *session_request_p; + /* Keep the identifier to the default APN */ + context_identifier_t context_identifier; + struct apn_configuration_s *default_apn; + + DevAssert(ula_p != NULL); + +#if defined(DISABLE_STANDALONE_EPC) + to_task = TASK_S11; +#else + to_task = TASK_SPGW_APP; +#endif + + if (ula_p->result.present == S6A_RESULT_BASE) { + if (ula_p->result.choice.base != DIAMETER_SUCCESS) { + /* The update location procedure has failed. Notify the NAS layer + * and don't initiate the bearer creation on S-GW side. + */ + DevMessage("ULR/ULA procedure returned non success\n"); + } + } else { + /* The update location procedure has failed. Notify the NAS layer + * and don't initiate the bearer creation on S-GW side. + */ + DevMessage("ULR/ULA procedure returned non success\n"); + } + + MME_APP_STRING_TO_IMSI((char *)ula_p->imsi, &imsi); + + MME_APP_DEBUG("Handling imsi %"IMSI_FORMAT"\n", imsi); + + if ((ue_context = mme_ue_context_exists_imsi(&mme_app_desc.mme_ue_contexts, imsi)) == NULL) { + MME_APP_ERROR("That's embarrassing as we don't know this IMSI\n"); + return -1; + } + + ue_context->subscription_known = SUBSCRIPTION_KNOWN; + + ue_context->sub_status = ula_p->subscription_data.subscriber_status; + ue_context->access_restriction_data = ula_p->subscription_data.access_restriction; + + /* Copy the subscribed ambr to the sgw create session request message */ + memcpy(&ue_context->subscribed_ambr, &ula_p->subscription_data.subscribed_ambr, + sizeof(ambr_t)); + memcpy(ue_context->msisdn, ula_p->subscription_data.msisdn, + MSISDN_LENGTH); + + ue_context->rau_tau_timer = ula_p->subscription_data.rau_tau_timer; + ue_context->access_mode = ula_p->subscription_data.access_mode; + ue_context->rau_tau_timer = ula_p->subscription_data.rau_tau_timer; + + memcpy(&ue_context->apn_profile, &ula_p->subscription_data.apn_config_profile, + sizeof(apn_config_profile_t)); + +// mme_app_dump_ue_contexts(); + + if (ula_p->subscription_data.subscriber_status != SS_SERVICE_GRANTED) { + /* HSS rejected the bearer creation or roaming is not allowed for this + * UE. This result will trigger an ESM Failure message sent to UE. + */ + DevMessage("Not implemented: ACCESS NOT GRANTED, send ESM Failure to NAS\n"); + } + + message_p = alloc_new_message(TASK_MME_APP, SGW_CREATE_SESSION_REQUEST); + + /* WARNING: + * Some parameters should be provided by NAS Layer: + * - ue_time_zone + * - mei + * - uli + * - uci + * Some parameters should be provided by HSS: + * - PGW address for CP + * - paa + * - ambr + * and by MME Application layer: + * - selection_mode + * Set these parameters with random values for now. + */ + + session_request_p = &message_p->msg.sgwCreateSessionRequest; + memset(session_request_p, 0, sizeof(SgwCreateSessionRequest)); + + /* As the create session request is the first exchanged message and as + * no tunnel had been previously setup, the distant teid is set to 0. + * The remote teid will be provided in the response message. + */ + session_request_p->teid = 0; + + memcpy(session_request_p->imsi.digit, ula_p->imsi, + ula_p->imsi_length); + session_request_p->imsi.length = ula_p->imsi_length; + + /* Copy the MSISDN */ + memcpy(session_request_p->msisdn.digit, ula_p->subscription_data.msisdn, + ula_p->subscription_data.msisdn_length); + session_request_p->msisdn.length = ula_p->subscription_data.msisdn_length; + + session_request_p->rat_type = RAT_EUTRAN; + + /* Copy the subscribed ambr to the sgw create session request message */ + memcpy(&session_request_p->ambr, &ula_p->subscription_data.subscribed_ambr, + sizeof(ambr_t)); + + if (ula_p->subscription_data.apn_config_profile.nb_apns == 0) { + DevMessage("No APN returned by the HSS"); + } + + context_identifier = ula_p->subscription_data.apn_config_profile.context_identifier; + for (i = 0; i < ula_p->subscription_data.apn_config_profile.nb_apns; i++) { + default_apn = &ula_p->subscription_data.apn_config_profile.apn_configuration[i]; + /* OK we got our default APN */ + if (default_apn->context_identifier == context_identifier) + break; + } + + if (!default_apn) { + /* Unfortunately we didn't find our default APN... */ + DevMessage("No default APN found"); + } + + memcpy(&session_request_p->bearer_to_create.bearer_level_qos.gbr, + &default_apn->ambr, sizeof(ambr_t)); + memcpy(&session_request_p->bearer_to_create.bearer_level_qos.mbr, + &default_apn->ambr, sizeof(ambr_t)); + + session_request_p->bearer_to_create.bearer_level_qos.qci = + default_apn->subscribed_qos.qci; + + session_request_p->bearer_to_create.bearer_level_qos.pvi = + default_apn->subscribed_qos.allocation_retention_priority.pre_emp_vulnerability; + session_request_p->bearer_to_create.bearer_level_qos.pci = + default_apn->subscribed_qos.allocation_retention_priority.pre_emp_capability; + session_request_p->bearer_to_create.bearer_level_qos.pl = + default_apn->subscribed_qos.allocation_retention_priority.priority_level; + + /* Asking for default bearer in initial UE message. + * Use the address of ue_context as unique TEID: Need to find better here + * and will generate unique id only for 32 bits platforms. + */ + session_request_p->sender_fteid_for_cp.teid = (uint32_t)ue_context; + session_request_p->sender_fteid_for_cp.interface_type = S11_MME_GTP_C; + session_request_p->bearer_to_create.eps_bearer_id = 5; + + ue_context->mme_s11_teid = session_request_p->sender_fteid_for_cp.teid; + ue_context->sgw_s11_teid = 0; + + memcpy(session_request_p->apn, default_apn->service_selection, + default_apn->service_selection_length); + + /* Set PDN type for pdn_type and PAA even if this IE is redundant */ + session_request_p->pdn_type = default_apn->pdn_type; + session_request_p->paa.pdn_type = default_apn->pdn_type; + if (default_apn->nb_ip_address == 0) { + /* UE DHCPv4 allocated ip address */ + memset(session_request_p->paa.ipv4_address, 0, 4); + memset(session_request_p->paa.ipv6_address, 0, 16); + } else { + uint8_t j; + + for (j = 0; j < default_apn->nb_ip_address; j++) { + ip_address_t *ip_address; + ip_address = &default_apn->ip_address[j]; + if (ip_address->pdn_type == IPv4) { + memcpy(session_request_p->paa.ipv4_address, ip_address->address.ipv4_address, 4); + } else if (ip_address->pdn_type == IPv6) { + memcpy(session_request_p->paa.ipv6_address, ip_address->address.ipv6_address, 16); + } +// free(ip_address); + } + } + + config_read_lock(&mme_config); + session_request_p->peer_ip = mme_config.ipv4.sgw_ip_address_for_S11; + config_unlock(&mme_config); + + session_request_p->serving_network.mcc[0] = ue_context->e_utran_cgi.plmn.MCCdigit1; + session_request_p->serving_network.mcc[1] = ue_context->e_utran_cgi.plmn.MCCdigit2; + session_request_p->serving_network.mcc[2] = ue_context->e_utran_cgi.plmn.MCCdigit3; + + session_request_p->serving_network.mnc[0] = ue_context->e_utran_cgi.plmn.MNCdigit1; + session_request_p->serving_network.mnc[1] = ue_context->e_utran_cgi.plmn.MNCdigit2; + session_request_p->serving_network.mnc[2] = ue_context->e_utran_cgi.plmn.MNCdigit3; + + session_request_p->selection_mode = MS_O_N_P_APN_S_V; + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); +} + +int mme_app_handle_create_sess_resp(SgwCreateSessionResponse *create_sess_resp_p) +{ + struct ue_context_s *ue_context_p; + bearer_context_t *current_bearer_p; + + int16_t bearer_id; + + DevAssert(create_sess_resp_p != NULL); + + MME_APP_DEBUG("Received create session response from S+P-GW\n"); + + ue_context_p = mme_ue_context_exists_s11_teid(&mme_app_desc.mme_ue_contexts, + create_sess_resp_p->teid); + if (ue_context_p == NULL) { + MME_APP_DEBUG("We didn't find this teid in list of UE: %08x\n", + create_sess_resp_p->teid); + return -1; + } + + /* Store the S-GW teid */ + ue_context_p->sgw_s11_teid = create_sess_resp_p->s11_sgw_teid.teid; + + bearer_id = create_sess_resp_p->bearer_context_created.eps_bearer_id/* - 5*/; + + /* Depending on s11 result we have to send reject or accept for bearers */ + DevCheck((bearer_id < BEARERS_PER_UE) && (bearer_id >= 0), bearer_id, + BEARERS_PER_UE, 0); + + if (create_sess_resp_p->bearer_context_created.cause != REQUEST_ACCEPTED) { + DevMessage("Cases where bearer cause != REQUEST_ACCEPTED are not handled\n"); + } + DevAssert(create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.interface_type == S1_U_SGW_GTP_U); + + /* Updating statistics */ + mme_app_desc.mme_ue_contexts.nb_bearers_managed++; + mme_app_desc.mme_ue_contexts.nb_bearers_since_last_stat++; + + current_bearer_p = &ue_context_p->eps_bearers[bearer_id]; + + current_bearer_p->s_gw_teid = create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.teid; + switch (create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv4 + + (create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv6 << 1)) + { + default: + case 0: { + /* No address provided: impossible case */ + DevMessage("No ip address for user-plane provided...\n"); + } break; + case 1: { + /* Only IPv4 address */ + current_bearer_p->s_gw_address.pdn_type = IPv4; + memcpy(current_bearer_p->s_gw_address.address.ipv4_address, + &create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv4_address, 4); + } break; + case 2: { + /* Only IPv6 address */ + current_bearer_p->s_gw_address.pdn_type = IPv6; + memcpy(current_bearer_p->s_gw_address.address.ipv6_address, + create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv6_address, 16); + } break; + case 3: { + /* Both IPv4 and Ipv6 */ + current_bearer_p->s_gw_address.pdn_type = IPv4_AND_v6; + memcpy(current_bearer_p->s_gw_address.address.ipv4_address, + &create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv4_address, 4); + memcpy(current_bearer_p->s_gw_address.address.ipv6_address, + create_sess_resp_p->bearer_context_created.s1u_sgw_fteid.ipv6_address, 16); + } break; + } + + mme_app_dump_ue_contexts(&mme_app_desc.mme_ue_contexts); + + /* Generate attach accepted */ + { + uint8_t *keNB; + MessageDef *message_p; + nas_attach_accept_t *attach_accept_p; + + message_p = alloc_new_message(TASK_MME_APP, NAS_ATTACH_ACCEPT); + + attach_accept_p = &message_p->msg.nas_attach_accept; + + derive_keNB(ue_context_p->vector_in_use->kasme, 156, &keNB); + memcpy(attach_accept_p->transparent.keNB, keNB, 16); + + free(keNB); + + attach_accept_p->transparent.eNB_ue_s1ap_id = ue_context_p->eNB_ue_s1ap_id; + attach_accept_p->transparent.mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + + attach_accept_p->transparent.ebi = bearer_id - 5; + + attach_accept_p->transparent.qci = current_bearer_p->qci; + attach_accept_p->transparent.prio_level = current_bearer_p->prio_level; + attach_accept_p->transparent.pre_emp_vulnerability = current_bearer_p->pre_emp_vulnerability; + attach_accept_p->transparent.pre_emp_capability = current_bearer_p->pre_emp_capability; + + attach_accept_p->transparent.teid = current_bearer_p->s_gw_teid; + memcpy(&attach_accept_p->transparent.s_gw_address, + ¤t_bearer_p->s_gw_address, sizeof(ip_address_t)); + + memcpy(&attach_accept_p->transparent.ambr, &ue_context_p->subscribed_ambr, + sizeof(ambr_t)); + + return send_msg_to_task(TASK_NAS, INSTANCE_DEFAULT, message_p); + } + + return 0; +} + diff --git a/openair-cn/MME_APP/mme_app_context.c b/openair-cn/MME_APP/mme_app_context.c new file mode 100644 index 0000000000..5b2408b9a0 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_context.c @@ -0,0 +1,348 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <stdint.h> +#include <inttypes.h> + +#include <arpa/inet.h> + +#include "intertask_interface.h" + +#include "assertions.h" +#include "conversions.h" +#include "tree.h" +#include "enum_string.h" +#include "common_types.h" + +#include "mme_app_extern.h" +#include "mme_app_ue_context.h" +#include "mme_app_defs.h" + +static inline int ue_context_compare_identifiers(struct ue_context_s *p1, + struct ue_context_s *p2); + +RB_PROTOTYPE(ue_context_map, ue_context_s, rb_entry, + ue_context_compare_identifiers); + +RB_GENERATE(ue_context_map, ue_context_s, rb_entry, + ue_context_compare_identifiers); + +static inline int ue_context_compare_identifiers( + struct ue_context_s *p1, struct ue_context_s *p2) +{ + if (p1->imsi > 0) { + /* if IMSI provided */ + if (p1->imsi > p2->imsi) { + return 1; + } + if (p1->imsi < p2->imsi) { + return -1; + } + } else if (p1->mme_s11_teid > 0) { + /* if s11 teid provided */ + if (p1->mme_s11_teid > p2->mme_s11_teid) { + return 1; + } + if (p1->mme_s11_teid < p2->mme_s11_teid) { + return -1; + } + } else { + uint16_t mcc1; + uint16_t mnc1; + uint16_t mcc2; + uint16_t mnc2; + + PLMN_T_TO_MCC_MNC(p1->guti.gummei.plmn, mcc1, mnc1); + PLMN_T_TO_MCC_MNC(p1->guti.gummei.plmn, mcc2, mnc2); + + /* else compare by GUTI */ + if ((p1->guti.m_tmsi < p2->guti.m_tmsi) && + (p1->guti.gummei.MMEcode < p2->guti.gummei.MMEcode) && + (p1->guti.gummei.MMEgid < p2->guti.gummei.MMEgid) && + (mcc1 < mcc2) && + (mnc1 < mnc2)) + return 1; + if ((p1->guti.m_tmsi > p2->guti.m_tmsi) && + (p1->guti.gummei.MMEcode > p2->guti.gummei.MMEcode) && + (p1->guti.gummei.MMEgid > p2->guti.gummei.MMEgid) && + (mcc1 > mcc2) && + (mnc1 > mnc2)) + return -1; + } + /* Match -> return 0 */ + return 0; +} + +ue_context_t *mme_create_new_ue_context(void) +{ + ue_context_t *new_p; + + new_p = malloc(sizeof(ue_context_t)); + if (new_p == NULL) { + return NULL; + } + memset(new_p, 0, sizeof(ue_context_t)); + return new_p; +} + +inline +struct ue_context_s *mme_ue_context_exists_imsi(mme_ue_context_t *mme_ue_context, + mme_app_imsi_t imsi) +{ + struct ue_context_s reference; + + DevAssert(mme_ue_context != NULL); + + memset(&reference, 0, sizeof(struct ue_context_s)); + reference.imsi = imsi; + return RB_FIND(ue_context_map, &mme_ue_context->ue_context_tree, + &reference); +} + +inline +struct ue_context_s *mme_ue_context_exists_s11_teid(mme_ue_context_t *mme_ue_context, + uint32_t teid) +{ + struct ue_context_s reference; + + DevAssert(mme_ue_context != NULL); + + memset(&reference, 0, sizeof(struct ue_context_s)); + reference.imsi = 0; + reference.mme_s11_teid = teid; + return RB_FIND(ue_context_map, &mme_ue_context->ue_context_tree, + &reference); +} + +inline +struct ue_context_s *mme_ue_context_exists_guti(mme_ue_context_t *mme_ue_context, + GUTI_t guti) +{ + struct ue_context_s reference; + + DevAssert(mme_ue_context != NULL); + + memset(&reference, 0, sizeof(struct ue_context_s)); + + memcpy(&reference.guti, &guti, sizeof(GUTI_t)); + + return RB_FIND(ue_context_map, &mme_ue_context->ue_context_tree, + &reference); +} + +int mme_insert_ue_context(mme_ue_context_t *mme_ue_context, struct ue_context_s *ue_context_p) +{ + struct ue_context_s *collision_p = NULL; + + DevAssert(mme_ue_context != NULL); + DevAssert(ue_context_p != NULL); + + /* Updating statistics */ + mme_ue_context->nb_ue_managed++; + mme_ue_context->nb_ue_since_last_stat++; + + collision_p = RB_INSERT(ue_context_map, &mme_ue_context->ue_context_tree, + ue_context_p); + if (collision_p != NULL) { + fprintf(stderr, "This ue context already exists...\n"); + return -1; + } + + return 0; +} + +void mme_app_dump_ue_contexts(mme_ue_context_t *mme_ue_context) +{ + struct ue_context_s *context_p; + + MME_APP_DEBUG("-----------------------UE contexts-----------------------\n"); + RB_FOREACH(context_p, ue_context_map, &mme_ue_context->ue_context_tree) + { + struct eutran_vector_s *vector_p; + uint8_t j; + + MME_APP_DEBUG(" - IMSI ...........: %"SCNu64"\n", context_p->imsi); + MME_APP_DEBUG(" | m_tmsi | mmec | mmegid | mcc | mnc |\n"); + MME_APP_DEBUG(" - GUTI............: | %08x | %02x | %04x | %03u | %03u |\n", + context_p->guti.m_tmsi, context_p->guti.gummei.MMEcode, + context_p->guti.gummei.MMEgid, + /* TODO check if two or three digits MNC... */ + context_p->guti.gummei.plmn.MCCdigit3 * 100 + + context_p->guti.gummei.plmn.MCCdigit2 * 10 + + context_p->guti.gummei.plmn.MCCdigit1, + context_p->guti.gummei.plmn.MNCdigit3 * 100 + + context_p->guti.gummei.plmn.MNCdigit2 * 10 + + context_p->guti.gummei.plmn.MNCdigit1); + MME_APP_DEBUG(" - Authenticated ..: %s\n", + (context_p->imsi_auth == IMSI_UNAUTHENTICATED) ? "FALSE": "TRUE"); + MME_APP_DEBUG(" - eNB UE s1ap ID .: %08x\n", context_p->eNB_ue_s1ap_id); + MME_APP_DEBUG(" - MME UE s1ap ID .: %08x\n", context_p->mme_ue_s1ap_id); + MME_APP_DEBUG(" - MME S11 TEID ...: %08x\n", context_p->mme_s11_teid); + MME_APP_DEBUG(" - SGW S11 TEID ...: %08x\n", context_p->sgw_s11_teid); + MME_APP_DEBUG(" | mcc | mnc | cell id |\n"); + MME_APP_DEBUG(" - E-UTRAN CGI ....: | %03u | %03u | %08x |\n", + context_p->e_utran_cgi.plmn.MCCdigit3 * 100 + + context_p->e_utran_cgi.plmn.MCCdigit2 * 10 + + context_p->e_utran_cgi.plmn.MCCdigit1, + context_p->e_utran_cgi.plmn.MNCdigit3 * 100 + + context_p->e_utran_cgi.plmn.MNCdigit2 * 10 + + context_p->e_utran_cgi.plmn.MNCdigit1, + context_p->e_utran_cgi.cell_identity); + /* Ctime return a \n in the string */ + MME_APP_DEBUG(" - Last acquired ..: %s", ctime(&context_p->cell_age)); + + /* Display UE info only if we know them */ + if (context_p->subscription_known == SUBSCRIPTION_KNOWN) + { + MME_APP_DEBUG(" - Status .........: %s\n", + (context_p->sub_status == SS_SERVICE_GRANTED) ? "Granted" : "Barred"); +#define DISPLAY_BIT_MASK_PRESENT(mASK) \ + ((context_p->access_restriction_data & mASK) ? 'X' : 'O') + MME_APP_DEBUG(" (O = allowed, X = !O) |UTRAN|GERAN|GAN|HSDPA EVO|E_UTRAN|HO TO NO 3GPP|\n"); + MME_APP_DEBUG(" - Access restriction | %c | %c | %c | %c | %c | %c |\n", + DISPLAY_BIT_MASK_PRESENT(ARD_UTRAN_NOT_ALLOWED), + DISPLAY_BIT_MASK_PRESENT(ARD_GERAN_NOT_ALLOWED), + DISPLAY_BIT_MASK_PRESENT(ARD_GAN_NOT_ALLOWED), + DISPLAY_BIT_MASK_PRESENT(ARD_I_HSDPA_EVO_NOT_ALLOWED), + DISPLAY_BIT_MASK_PRESENT(ARD_E_UTRAN_NOT_ALLOWED), + DISPLAY_BIT_MASK_PRESENT(ARD_HO_TO_NON_3GPP_NOT_ALLOWED)); + MME_APP_DEBUG(" - Access Mode ....: %s\n", + ACCESS_MODE_TO_STRING(context_p->access_mode)); + MME_APP_DEBUG(" - MSISDN .........: %-*s\n", + MSISDN_LENGTH, context_p->msisdn); + MME_APP_DEBUG(" - RAU/TAU timer ..: %u\n", context_p->rau_tau_timer); + MME_APP_DEBUG(" - IMEISV .........: %*s\n", 15, + context_p->me_identity.imeisv); + MME_APP_DEBUG(" - AMBR (bits/s) ( Downlink | Uplink )\n"); + MME_APP_DEBUG(" Subscribed ...: (%010u|%010u)\n", + context_p->subscribed_ambr.br_dl, + context_p->subscribed_ambr.br_ul); + MME_APP_DEBUG(" Allocated ....: (%010u|%010u)\n", + context_p->used_ambr.br_dl, context_p->used_ambr.br_ul); + MME_APP_DEBUG(" - Known vectors ..: %u\n", context_p->nb_of_vectors); + STAILQ_FOREACH(vector_p, &context_p->vector_list, entries) + { + int k; + char xres_string[3 * XRES_LENGTH_MAX + 1]; + + MME_APP_DEBUG(" - RAND ..: "RAND_FORMAT"\n", + RAND_DISPLAY(vector_p->rand)); + MME_APP_DEBUG(" - AUTN ..: "AUTN_FORMAT"\n", + AUTN_DISPLAY(vector_p->autn)); + MME_APP_DEBUG(" - KASME .: "KASME_FORMAT"\n", + KASME_DISPLAY_1(vector_p->kasme)); + MME_APP_DEBUG(" "KASME_FORMAT"\n", + KASME_DISPLAY_2(vector_p->kasme)); + + for (k = 0; k < vector_p->xres.size; k++) + { + sprintf(&xres_string[k * 3], "%02x,", vector_p->xres.data[k]); + } + xres_string[k * 3 - 1] = '\0'; + MME_APP_DEBUG(" - XRES ..: %s\n", xres_string); + } + MME_APP_DEBUG(" - PDN List:\n"); + for (j = 0; j < context_p->apn_profile.nb_apns; j++) + { + struct apn_configuration_s *apn_config_p; + + apn_config_p = &context_p->apn_profile.apn_configuration[j]; + + /* Default APN ? */ + MME_APP_DEBUG(" - Default APN ...: %s\n", + (apn_config_p->context_identifier == context_p->apn_profile.context_identifier) + ? "TRUE" : "FALSE"); + MME_APP_DEBUG(" - APN ...........: %s\n", apn_config_p->service_selection); + MME_APP_DEBUG(" - AMBR (bits/s) ( Downlink | Uplink )\n"); + MME_APP_DEBUG(" (%010u|%010u)\n", + apn_config_p->ambr.br_dl, apn_config_p->ambr.br_ul); + MME_APP_DEBUG(" - PDN type ......: %s\n", + PDN_TYPE_TO_STRING(apn_config_p->pdn_type)); + MME_APP_DEBUG(" - QOS\n"); + MME_APP_DEBUG(" QCI .........: %u\n", + apn_config_p->subscribed_qos.qci); + MME_APP_DEBUG(" Prio level ..: %u\n", + apn_config_p->subscribed_qos.allocation_retention_priority.priority_level); + MME_APP_DEBUG(" Pre-emp vul .: %s\n", + (apn_config_p->subscribed_qos.allocation_retention_priority.pre_emp_vulnerability + == PRE_EMPTION_VULNERABILITY_ENABLED) ? "ENABLED" : "DISABLED"); + MME_APP_DEBUG(" Pre-emp cap .: %s\n", + (apn_config_p->subscribed_qos.allocation_retention_priority.pre_emp_capability + == PRE_EMPTION_CAPABILITY_ENABLED) ? "ENABLED" : "DISABLED"); + if (apn_config_p->nb_ip_address == 0) { + MME_APP_DEBUG(" IP addr .....: Dynamic allocation\n"); + } else { + int i; + MME_APP_DEBUG(" IP addresses :\n"); + for (i = 0; i < apn_config_p->nb_ip_address; i++) + { + if (apn_config_p->ip_address[i].pdn_type == IPv4) { + MME_APP_DEBUG(" ["IPV4_ADDR"]\n", + IPV4_ADDR_DISPLAY_8(apn_config_p->ip_address[i].address.ipv4_address)); + } else { + char ipv6[40]; + inet_ntop(AF_INET6, apn_config_p->ip_address[i].address.ipv6_address,ipv6, 40); + MME_APP_DEBUG(" [%s]\n", ipv6); + } + } + } + MME_APP_DEBUG("\n"); + } + MME_APP_DEBUG(" - Bearer List:\n"); + for (j = 0; j < BEARERS_PER_UE; j++) + { + bearer_context_t *bearer_context_p; + + bearer_context_p = &context_p->eps_bearers[j]; + + if (bearer_context_p->s_gw_teid != 0) { + MME_APP_DEBUG(" Bearer id .......: %02u\n", j); + MME_APP_DEBUG(" S-GW TEID (UP)...: %08x\n", bearer_context_p->s_gw_teid); + MME_APP_DEBUG(" P-GW TEID (UP)...: %08x\n", bearer_context_p->p_gw_teid); + MME_APP_DEBUG(" QCI .............: %u\n", + bearer_context_p->qci); + MME_APP_DEBUG(" Priority level ..: %u\n", + bearer_context_p->prio_level); + MME_APP_DEBUG(" Pre-emp vul .....: %s\n", + (bearer_context_p->pre_emp_vulnerability + == PRE_EMPTION_VULNERABILITY_ENABLED) ? "ENABLED" : "DISABLED"); + MME_APP_DEBUG(" Pre-emp cap .....: %s\n", + (bearer_context_p->pre_emp_capability + == PRE_EMPTION_CAPABILITY_ENABLED) ? "ENABLED" : "DISABLED"); + } + } + } + } + MME_APP_DEBUG("---------------------------------------------------------\n"); +} diff --git a/openair-cn/MME_APP/mme_app_defs.h b/openair-cn/MME_APP/mme_app_defs.h new file mode 100644 index 0000000000..7b84a15915 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_defs.h @@ -0,0 +1,72 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/* This file contains definitions related to mme applicative layer and should + * not be included within other layers. + * Use mme_app_extern.h to expose mme applicative layer procedures/data. + */ + +#include "mme_app_ue_context.h" + +#ifndef MME_APP_DEFS_H_ +#define MME_APP_DEFS_H_ + +#ifndef MME_APP_DEBUG +# define MME_APP_DEBUG(x, args...) do { fprintf(stdout, "[MMEA][D]"x, ##args); } while(0) +#endif +#ifndef MME_APP_ERROR +# define MME_APP_ERROR(x, args...) do { fprintf(stdout, "[MMEA][E]"x, ##args); } while(0) +#endif + +typedef struct { + /* UE contexts + some statistics variables */ + mme_ue_context_t mme_ue_contexts; + + long statistic_timer_id; + uint32_t statistic_timer_period; +} mme_app_desc_t; + +extern mme_app_desc_t mme_app_desc; + +int mme_app_create_bearer(s6a_update_location_ans_t *ula_p); + +int mme_app_handle_attach_req(nas_attach_req_t *attach_req_p); + +int mme_app_handle_create_sess_resp(SgwCreateSessionResponse *create_sess_resp_p); + +int mme_app_handle_establish_ind(nas_establish_ind_t *nas_establish_ind_p); + +int mme_app_handle_authentication_info_answer(s6a_auth_info_ans_t *s6a_auth_info_ans_p); + +int mme_app_handle_nas_auth_resp(nas_auth_resp_t *nas_auth_resp_p); + +int s6a_error_2_nas_cause(uint32_t s6a_error, int experimental); + +#endif /* MME_APP_DEFS_H_ */ diff --git a/openair-cn/MME_APP/mme_app_extern.h b/openair-cn/MME_APP/mme_app_extern.h new file mode 100644 index 0000000000..6907199584 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_extern.h @@ -0,0 +1,36 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef MME_APP_EXTERN_H_ +#define MME_APP_EXTERN_H_ + +int mme_app_init(const mme_config_t *mme_config); + +#endif /* MME_APP_EXTERN_H_ */ diff --git a/openair-cn/MME_APP/mme_app_main.c b/openair-cn/MME_APP/mme_app_main.c new file mode 100644 index 0000000000..bde2776667 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_main.c @@ -0,0 +1,129 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "intertask_interface.h" +#include "timer.h" + +#include "mme_app_extern.h" +#include "mme_app_ue_context.h" +#include "mme_app_defs.h" +#include "mme_app_statistics.h" + +#include "assertions.h" + +mme_app_desc_t mme_app_desc; + +void *mme_app_thread(void *args); + +void *mme_app_thread(void *args) +{ + intertask_interface_mark_task_ready(TASK_MME_APP); + + while(1) { + MessageDef *received_message_p = NULL; + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + receive_msg(TASK_MME_APP, &received_message_p); + DevAssert(received_message_p != NULL); + switch(received_message_p->header.messageId) { + case S6A_AUTH_INFO_ANS: { + /* We received the authentication vectors from HSS, trigger a ULR + * for now. Normaly should trigger an authentication procedure with UE. + */ + mme_app_handle_authentication_info_answer(&received_message_p->msg.s6a_auth_info_ans); + } break; + case S6A_UPDATE_LOCATION_ANS: { + /* We received the update location answer message from HSS -> Handle it */ + mme_app_create_bearer(&received_message_p->msg.s6a_update_location_ans); + } break; + case SGW_CREATE_SESSION_RESPONSE: { + mme_app_handle_create_sess_resp(&received_message_p->msg.sgwCreateSessionResponse); + } break; + case NAS_AUTHENTICATION_RESP: { + mme_app_handle_nas_auth_resp(&received_message_p->msg.nas_auth_resp); + } break; + case NAS_ATTACH_REQ: { + mme_app_handle_attach_req(&received_message_p->msg.nas_attach_req); + } break; + case TIMER_HAS_EXPIRED: { + /* Check if it is the statistic timer */ + if (received_message_p->msg.timer_has_expired.timer_id == + mme_app_desc.statistic_timer_id) { + mme_app_statistics_display(); + } + } break; + case TERMINATE_MESSAGE: { + /* Termination message received -> release any data allocated */ + + } break; + default: { + MME_APP_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int mme_app_init(const mme_config_t *mme_config_p) +{ + MME_APP_DEBUG("Initializing MME applicative layer\n"); + + memset(&mme_app_desc, 0, sizeof(mme_app_desc)); + + /* Create the thread associated with MME applicative layer */ + if (intertask_interface_create_task(TASK_MME_APP, &mme_app_thread, NULL) < 0) { + MME_APP_ERROR("MME APP create task failed\n"); + return -1; + } + + mme_app_desc.statistic_timer_period = mme_config_p->mme_statistic_timer; + + /* Request for periodic timer */ + if (timer_setup(mme_config_p->mme_statistic_timer, 0, TASK_MME_APP, INSTANCE_DEFAULT, + TIMER_PERIODIC, NULL, &mme_app_desc.statistic_timer_id) < 0) + { + MME_APP_ERROR("Failed to request new timer for statistics with %ds " + "of periocidity\n", mme_config_p->mme_statistic_timer); + mme_app_desc.statistic_timer_id = 0; + } + + MME_APP_DEBUG("Initializing MME applicative layer: DONE\n"); + return 0; +} diff --git a/openair-cn/MME_APP/mme_app_statistics.c b/openair-cn/MME_APP/mme_app_statistics.c new file mode 100644 index 0000000000..5bf5f4e11b --- /dev/null +++ b/openair-cn/MME_APP/mme_app_statistics.c @@ -0,0 +1,25 @@ +#include <stdlib.h> +#include <stdio.h> + +#include "intertask_interface.h" + +#include "mme_app_ue_context.h" +#include "mme_app_defs.h" +#include "mme_app_statistics.h" + +int mme_app_statistics_display(void) +{ + fprintf(stdout, "================== Statistics ==================\n"); + fprintf(stdout, " | Global | Since last display |\n"); + fprintf(stdout, "UE | %10u | %10u |\n", + mme_app_desc.mme_ue_contexts.nb_ue_managed, + mme_app_desc.mme_ue_contexts.nb_ue_since_last_stat); + fprintf(stdout, "Bearers | %10u | %10u |\n", + mme_app_desc.mme_ue_contexts.nb_bearers_managed, + mme_app_desc.mme_ue_contexts.nb_bearers_since_last_stat); + + mme_app_desc.mme_ue_contexts.nb_ue_since_last_stat = 0; + mme_app_desc.mme_ue_contexts.nb_bearers_since_last_stat = 0; + + return 0; +} diff --git a/openair-cn/MME_APP/mme_app_statistics.h b/openair-cn/MME_APP/mme_app_statistics.h new file mode 100644 index 0000000000..e5d63f2048 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_statistics.h @@ -0,0 +1,6 @@ +#ifndef MME_APP_STATISTICS_H_ +#define MME_APP_STATISTICS_H_ + +int mme_app_statistics_display(void); + +#endif /* MME_APP_STATISTICS_H_ */ diff --git a/openair-cn/MME_APP/mme_app_ue_context.h b/openair-cn/MME_APP/mme_app_ue_context.h new file mode 100644 index 0000000000..45173eeca4 --- /dev/null +++ b/openair-cn/MME_APP/mme_app_ue_context.h @@ -0,0 +1,225 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file mme_app_ue_context.h + * \brief MME applicative layer + * \author Sebastien ROUX + * \date 2013 + * \version 1.0 + * @defgroup _mme_app_impl_ MME applicative layer + * @ingroup _ref_implementation_ + * @{ + */ + +#include <stdint.h> +#include <inttypes.h> /* For sscanf formats */ +#include <time.h> /* to provide time_t */ + +#include "security_types.h" +#include "tree.h" + +#ifndef MME_APP_UE_CONTEXT_H_ +#define MME_APP_UE_CONTEXT_H_ + +typedef enum { + ECM_IDLE, + ECM_CONNECTED, + EMM_DEREGISTERED, +} mm_state_t; + +typedef uint64_t mme_app_imsi_t; + +#define IMSI_FORMAT SCNu64 + +/* Convert the IMSI contained by a char string NULL terminated to uint64_t */ +#define MME_APP_STRING_TO_IMSI(sTRING, iMSI) sscanf(sTRING, "%"IMSI_FORMAT, iMSI) +#define MME_APP_IMSI_TO_STRING(iMSI, sTRING) sprintf(sTRING, "%"IMSI_FORMAT, iMSI) + +/** @struct bearer_context_t + * @brief Parameters that should be kept for an eps bearer. + */ +typedef struct bearer_context_s { + /* S-GW Tunnel Endpoint for User-Plane */ + uint32_t s_gw_teid; + + /* S-GW IP address for User-Plane */ + ip_address_t s_gw_address; + + /* P-GW Tunnel Endpoint for User-Plane */ + uint32_t p_gw_teid; + + /* P-GW IP address for User-Plane */ + ip_address_t p_gw_address; + + /* QoS for this bearer */ + qci_t qci; + priority_level_t prio_level; + pre_emp_vulnerability_t pre_emp_vulnerability; + pre_emp_capability_t pre_emp_capability; + + /* TODO: add TFT */ +} bearer_context_t; + +/** @struct ue_context_t + * @brief Useful parameters to know in MME application layer. They are set + * according to 3GPP TS.23.401 #5.7.2 + */ +typedef struct ue_context_s { + /* Basic identifier for ue. IMSI is encoded on maximum of 15 digits of 4 bits, + * so usage of an unsigned integer on 64 bits is necessary. + */ + mme_app_imsi_t imsi; +#define IMSI_UNAUTHENTICATED (0x0) +#define IMSI_AUTHENTICATED (0x1) + /* Indicator to show the IMSI authentication state */ + unsigned imsi_auth:1; + + unsigned eNB_ue_s1ap_id:24; + uint32_t mme_ue_s1ap_id; + + uint8_t nb_of_vectors; + + struct eutran_vector_s *vector_in_use; + /* List of authentication vectors for E-UTRAN */ + STAILQ_HEAD(auth_vectors, eutran_vector_s) vector_list; + +#define SUBSCRIPTION_UNKNOWN 0x0 +#define SUBSCRIPTION_KNOWN 0x1 + unsigned subscription_known:1; + + uint8_t msisdn[MSISDN_LENGTH]; + mm_state_t mm_state; + /* Globally Unique Temporary Identity */ + GUTI_t guti; + me_identity_t me_identity; + + /* TODO: Add TAI list */ + + /* Last known cell identity */ + cgi_t e_utran_cgi; + /* Time when the cell identity was acquired */ + time_t cell_age; + + /* TODO: add csg_id */ + /* TODO: add csg_membership */ + + network_access_mode_t access_mode; + + /* TODO: add ue radio cap, ms classmarks, cupported codecs */ + + /* TODO: add ue network capability, ms network capability */ + /* TODO: add selected NAS algorithm */ + + /* TODO: add DRX parameter */ + + apn_config_profile_t apn_profile; + + ard_t access_restriction_data; + + subscriber_status_t sub_status; + + ambr_t subscribed_ambr; + ambr_t used_ambr; + + rau_tau_timer_t rau_tau_timer; + + /* Store the radio capabilities as received in S1AP UE capability indication + * message. + */ + char *ue_radio_capabilities; + int ue_radio_cap_length; + + uint32_t mme_s11_teid; + uint32_t sgw_s11_teid; + + bearer_context_t eps_bearers[BEARERS_PER_UE]; + + /* Tree entry */ + RB_ENTRY(ue_context_s) rb_entry; + +} ue_context_t; + +typedef struct { + uint32_t nb_ue_managed; + uint32_t nb_ue_idle; + + uint32_t nb_bearers_managed; + + uint32_t nb_ue_since_last_stat; + uint32_t nb_bearers_since_last_stat; + + /* Entry to the root */ + RB_HEAD(ue_context_map, ue_context_s) ue_context_tree; +} mme_ue_context_t; + +/** \brief Retrieve an UE context by selecting the provided IMSI + * \param imsi Imsi to find in UE map + * @returns an UE context matching the IMSI or NULL if the context doesn't exists + **/ +inline +ue_context_t *mme_ue_context_exists_imsi(mme_ue_context_t *mme_ue_context, + mme_app_imsi_t imsi); + +/** \brief Retrieve an UE context by selecting the provided S11 teid + * \param teid The tunnel endpoint identifier used between MME and S-GW + * @returns an UE context matching the teid or NULL if the context doesn't exists + **/ +inline +ue_context_t *mme_ue_context_exists_s11_teid(mme_ue_context_t *mme_ue_context, + uint32_t teid); + +/** \brief Retrieve an UE context by selecting the provided guti + * \param guti The GUTI used by the UE + * @returns an UE context matching the guti or NULL if the context doesn't exists + **/ +inline +struct ue_context_s *mme_ue_context_exists_guti(mme_ue_context_t *mme_ue_context, + GUTI_t guti); + +/** \brief Insert a new UE context in the tree of known UEs. + * At least the IMSI should be known to insert the context in the tree. + * \param ue_context_p The UE context to insert + * @returns 0 in case of success, -1 otherwise + **/ +int mme_insert_ue_context(mme_ue_context_t *mme_ue_context, + struct ue_context_s *ue_context_p); + +/** \brief Allocate memory for a new UE context + * @returns Pointer to the new structure, NULL if allocation failed + **/ +ue_context_t *mme_create_new_ue_context(void); + +/** \brief Dump the UE contexts present in the tree + **/ +void mme_app_dump_ue_contexts(mme_ue_context_t *mme_ue_context); + +#endif /* MME_APP_UE_CONTEXT_H_ */ + +/* @} */ diff --git a/openair-cn/MME_APP/s6a_2_nas_cause.c b/openair-cn/MME_APP/s6a_2_nas_cause.c new file mode 100644 index 0000000000..38050c11c6 --- /dev/null +++ b/openair-cn/MME_APP/s6a_2_nas_cause.c @@ -0,0 +1,95 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "as_message.h" +#include "common_types.h" +#include "s6a_defs.h" + +// int send_nas_failure(uint32_t nas_cause) +// { +// MessageDef *message_p; +// +// message_p = alloc_new_message(TASK_MME_APP, TASK_NAS, +// SGW_CREATE_SESSION_REQUEST); +// +// return send_msg_to_task(TASK_NAS, message_p); +// } + +int s6a_error_2_nas_cause(uint32_t s6a_error, int experimental) +{ + if (experimental == 0) { + /* Base protocol errors */ + switch (s6a_error) { + /* 3002 */ + case ER_DIAMETER_UNABLE_TO_DELIVER: /* Fall through */ + /* 3003 */ + case ER_DIAMETER_REALM_NOT_SERVED: /* Fall through */ + /* 5003 */ + case ER_DIAMETER_AUTHORIZATION_REJECTED: + return NO_SUITABLE_CELLS_IN_TRACKING_AREA; + /* 5012 */ + case ER_DIAMETER_UNABLE_TO_COMPLY: /* Fall through */ + /* 5004 */ + case ER_DIAMETER_INVALID_AVP_VALUE: /* Fall through */ + /* Any other permanent errors from the diameter base protocol */ + default: + break; + } + } else { + switch (s6a_error) { + /* 5001 */ + case DIAMETER_ERROR_USER_UNKNOWN: + return EPS_SERVICES_AND_NON_EPS_SERVICES_NOT_ALLOWED; + /* TODO: distinguish GPRS_DATA_SUBSCRIPTION */ + /* 5420 */ + case DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION: + return NO_SUITABLE_CELLS_IN_TRACKING_AREA; + /* 5421 */ + case DIAMETER_ERROR_RAT_NOT_ALLOWED: + /* One of the following parameter can be sent depending on + * operator preference: + * ROAMING_NOT_ALLOWED_IN_THIS_TRACKING_AREA + * TRACKING_AREA_NOT_ALLOWED + * NO_SUITABLE_CELLS_IN_TRACKING_AREA + */ + return TRACKING_AREA_NOT_ALLOWED; + /* 5004 without error diagnostic */ + case DIAMETER_ERROR_ROAMING_NOT_ALLOWED: + return PLMN_NOT_ALLOWED; + /* TODO: 5004 with error diagnostic of ODB_HPLMN_APN or + * ODB_VPLMN_APN + */ + /* TODO: 5004 with error diagnostic of ODB_ALL_APN */ + default: + break; + } + } + return NETWORK_FAILURE; +} diff --git a/openair-cn/Makefile.am b/openair-cn/Makefile.am new file mode 100644 index 0000000000..56f389af8a --- /dev/null +++ b/openair-cn/Makefile.am @@ -0,0 +1,63 @@ +ACLOCAL_AMFLAGS = -I m4 + +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/INTERTASK_INTERFACE + +if HAVE_GCCXML +BUILT_SOURCES = \ + messages.xml \ + messages_xml.h + +messages_hdr = \ + $(top_srcdir)/INTERTASK_INTERFACE/intertask_messages_def.h \ + $(top_srcdir)/INTERTASK_INTERFACE/timer_messages_def.h \ + $(top_srcdir)/INTERTASK_INTERFACE/timer_messages_types.h \ + $(top_srcdir)/COMMON/tasks_def.h \ + $(top_srcdir)/COMMON/messages_def.h \ + $(top_srcdir)/COMMON/messages_types.h \ + $(top_srcdir)/COMMON/gtpv1_u_messages_def.h \ + $(top_srcdir)/COMMON/gtpv1_u_messages_types.h \ + $(top_srcdir)/COMMON/nas_messages_def.h \ + $(top_srcdir)/COMMON/nas_messages_types.h \ + $(top_srcdir)/COMMON/s11_messages_def.h \ + $(top_srcdir)/COMMON/s11_messages_types.h \ + $(top_srcdir)/COMMON/s1ap_messages_def.h \ + $(top_srcdir)/COMMON/s1ap_messages_types.h \ + $(top_srcdir)/COMMON/s6a_messages_def.h \ + $(top_srcdir)/COMMON/s6a_messages_types.h \ + $(top_srcdir)/COMMON/sgw_lite_def.h \ + $(top_srcdir)/COMMON/sgw_lite_messages_types.h \ + $(top_srcdir)/COMMON/sctp_messages_def.h \ + $(top_srcdir)/COMMON/sctp_messages_types.h \ + $(top_srcdir)/COMMON/udp_messages_def.h \ + $(top_srcdir)/COMMON/udp_messages_types.h + +messages.xml: $(top_srcdir)/INTERTASK_INTERFACE/intertask_interface_types.h $(messages_hdr) + gccxml $(AM_CFLAGS) $< -fxml=$(top_builddir)/$@ + +messages_xml.h: messages.xml + sed -e 's/[ ]*//' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/"/' messages.xml > messages_xml.h +endif + +SUBDIRS = \ + . \ + GTPV1-U \ + GTPV2-C \ + INTERTASK_INTERFACE \ + SGI \ + NAS \ + SCTP \ + S11 \ + S1AP \ + S6A \ + SECU \ + SGW-LITE \ + UTILS \ + UDP \ + MME_APP \ + TEST \ + OAISIM_MME \ + OAI_EPC \ + OAI_SGW \ No newline at end of file diff --git a/openair-cn/NAS/EURECOM-NAS/Makefile b/openair-cn/NAS/EURECOM-NAS/Makefile new file mode 100644 index 0000000000..81fbba90f1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/Makefile @@ -0,0 +1,65 @@ +# To be run as: make or make PROCESS=UE or make PROCESS=MME +# make and make PROCESS=UE build ./bin/UEprocess +# make PROCESS=MME builds ./bin/MMEprocess + +include Makerules +include Makefile.inc + +export PROJDIR = $(CURDIR) + +all: + @$(CD) $(UTILDIR) && $(MAKE) + @$(CD) $(APIDIR) && $(MAKE) + @$(CD) $(IESDIR) && $(MAKE) + @$(CD) $(EMMDIR) && $(MAKE) + @$(CD) $(ESMDIR) && $(MAKE) + @$(CD) $(SRCDIR) && $(MAKE) +ifeq ($(PROCESS), UE) + @$(CD) $(TOOLSDIR) && $(MAKE) + @$(CD) $(USRTSTDIR) && $(MAKE) +endif +ifeq ($(PROCESS), MME) + @$(CD) $(NETTSTDIR) && $(MAKE) + @$(CD) $(ASSIMUDIR) && $(MAKE) +endif +# SR include all objects in a single archive + $(AR) rcs libUE/libNasUE.a `find . -name *.o` + +clean: + @$(CD) $(SRCDIR) && $(MAKE) $@ + @$(CD) $(APIDIR) && $(MAKE) $@ + @$(CD) $(EMMDIR) && $(MAKE) $@ + @$(CD) $(ESMDIR) && $(MAKE) $@ + +veryclean: clean + @$(CD) $(SRCDIR) && $(MAKE) $@ + @$(CD) $(APIDIR) && $(MAKE) $@ + @$(CD) $(EMMDIR) && $(MAKE) $@ + @$(CD) $(ESMDIR) && $(MAKE) $@ + @$(CD) $(UTILDIR) && $(MAKE) $@ + @$(CD) $(IESDIR) && $(MAKE) $@ + @$(CD) $(TOOLSDIR) && $(MAKE) $@ + @$(CD) $(USRTSTDIR) && $(MAKE) $@ + @$(CD) $(NETTSTDIR) && $(MAKE) $@ + @$(CD) $(ASSIMUDIR) && $(MAKE) $@ + @$(RM) libUE/libNasUE.a + +veryveryclean: veryclean + @$(CD) $(BINDIR) && $(RM) * .*.nvram + @$(CD) $(LIBDIR) && $(RM) * + @$(CD) $(LIBDIR)UE && $(RM) * + @$(CD) $(LIBDIR)MME && $(RM) * + +depend: + @$(CD) $(SRCDIR) && $(MAKE) depend + @$(CD) $(APIDIR) && $(MAKE) depend + @$(CD) $(EMMDIR) && $(MAKE) depend + @$(CD) $(ESMDIR) && $(MAKE) depend + @$(CD) $(UTILDIR) && $(MAKE) depend + @$(CD) $(IESDIR) && $(MAKE) depend + @$(CD) $(TOOLSDIR) && $(MAKE) depend + @$(CD) $(USRTSTDIR) && $(MAKE) depend + @$(CD) $(NETTSTDIR) && $(MAKE) depend + @$(CD) $(ASSIMUDIR) && $(MAKE) depend + +# DO NOT DELETE diff --git a/openair-cn/NAS/EURECOM-NAS/Makefile.inc b/openair-cn/NAS/EURECOM-NAS/Makefile.inc new file mode 100644 index 0000000000..1efed2d9da --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/Makefile.inc @@ -0,0 +1,39 @@ +# list of generated libraries +LIBUTIL = libutil +LIBAPI = libapi +LIBIES = libies +LIBEMMMSG = libEMMmsg +LIBEMMSAP = libEMMsap +LIBESMMSG = libESMmsg +LIBESMSAP = libESMsap + +# Binary directories +BINDIR = $(PROJDIR)/bin +LIBDIR = $(PROJDIR)/lib +LIBPROCESS = $(LIBDIR)$(PROCESS) + +# Source directories +SRCDIR = $(PROJDIR)/src +INCDIR = $(SRCDIR)/include +UTILDIR = $(SRCDIR)/util +APIDIR = $(SRCDIR)/api +USERAPIDIR = $(APIDIR)/user +NETAPIDIR = $(APIDIR)/network +USIMAPIDIR = $(APIDIR)/usim +MMEAPIDIR = $(APIDIR)/mme +IESDIR = $(SRCDIR)/ies +EMMDIR = $(SRCDIR)/emm +ESMDIR = $(SRCDIR)/esm +EMMMSGDIR = $(EMMDIR)/msg +EMMSAPDIR = $(EMMDIR)/sap +ESMMSGDIR = $(ESMDIR)/msg +ESMSAPDIR = $(ESMDIR)/sap + +# Tools directory +TOOLSDIR = $(PROJDIR)/tools + +# Test directories +TSTDIR = $(PROJDIR)/tst +USRTSTDIR = $(TSTDIR)/user +NETTSTDIR = $(TSTDIR)/network +ASSIMUDIR = $(TSTDIR)/as_simulator diff --git a/openair-cn/NAS/EURECOM-NAS/Makerules b/openair-cn/NAS/EURECOM-NAS/Makerules new file mode 100644 index 0000000000..2ed86e58fa --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/Makerules @@ -0,0 +1,26 @@ +CC = gcc +RM = rm -f +CP = cp -p +LD = /usr/bin/ld +AR = /usr/bin/ar +CD = cd +MAKE = make + +CFLAGS = $(INCLUDES) $(DEFINES) -g -pthread +DEFINES = -DLINUX -D_REENTRANT -Wall -O -std=gnu99 + +SVN_REV = $(shell svnversion -n .) +DATE_REV = $(shell date '+%F %T') + +# Default builds UEprocess +ifeq ($(PROCESS), MME) + DEFINES += -DNAS_MME +else + DEFINES += -DNAS_UE +endif + +LDFLAGS = -pthread -L$(LIBDIR) -L$(LIBPROCESS) -lrt + +SRCS = $(wildcard *.c) +OBJS = $(SRCS:.c=.o) + diff --git a/openair-cn/NAS/EURECOM-NAS/src/MMEprocess.c b/openair-cn/NAS/EURECOM-NAS/src/MMEprocess.c new file mode 100644 index 0000000000..4550bf5827 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/MMEprocess.c @@ -0,0 +1,319 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + + Source MMEprocess.c + + Version 0.1 + + Date 2013/02/26 + + Product NAS stack + + Subsystem MME NAS main process + + Author Frederic Maurel + + Description Implements the Non-Access Stratum protocol for Evolved Packet + system (EPS) running at the Network side. + + *****************************************************************************/ + +#include "commonDef.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "network_api.h" +#include "nas_network.h" +#include "nas_parser.h" + +#include <stdlib.h> // exit +#include <poll.h> // poll +#include <string.h> // memset +#include <signal.h> // sigaction +#include <pthread.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#define NAS_SLEEP_TIMEOUT 1000 /* 1 second */ + +static void* _nas_network_mngr(void*); + +static int _nas_set_signal_handler(int signal, void (handler)(int)); +static void _nas_signal_handler(int signal); + +static void _nas_clean(int net_fd); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +int main(int argc, const char* argv[]) +{ + /* + * Get the command line options + */ + if (nas_parser_get_options (argc, argv) != RETURNok) + { + nas_parser_print_usage (FIRMWARE_VERSION); + exit (EXIT_FAILURE); + } + + /* + * Initialize logging trace utility + */ + nas_log_init (nas_parser_get_trace_level ()); + + const char* nhost = nas_parser_get_network_host (); + const char* nport = nas_parser_get_network_port (); + + LOG_TRACE (INFO, "MME-MAIN - %s -nhost %s -nport %s -trace 0x%x", argv[0], nhost, nport, + nas_parser_get_trace_level ()); + + /* + * Initialize the Network interface + */ + if (network_api_initialize (nhost, nport) != RETURNok) + { + LOG_TRACE (ERROR, "MME-MAIN - network_api_initialize() failed"); + exit (EXIT_FAILURE); + } + int network_fd = network_api_get_fd (); + + /* + * Initialize the NAS contexts + */ + nas_network_initialize (); + + /* + * Initialize NAS timer handlers + */ + nas_timer_init (); + + /* + * Set up signal handlers + */ + (void) _nas_set_signal_handler (SIGINT, _nas_signal_handler); + (void) _nas_set_signal_handler (SIGTERM, _nas_signal_handler); + + pthread_attr_t attr; + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + /* + * Start thread use to manage the network connection endpoint + */ + pthread_t network_mngr; + if (pthread_create (&network_mngr, &attr, _nas_network_mngr, &network_fd) != 0) + { + LOG_TRACE (ERROR, "MME-MAIN - " + "Failed to create the network management thread"); + network_api_close (network_fd); + exit (EXIT_FAILURE); + } + pthread_attr_destroy (&attr); + + /* + * Suspend execution of the main process until the network connection + * endpoint is still active + */ + while (network_fd != -1) + { + poll (NULL, 0, NAS_SLEEP_TIMEOUT); + network_fd = network_api_get_fd (); + } + + /* Termination cleanup */ + _nas_clean (network_fd); + + LOG_TRACE + (WARNING, "MME-MAIN - NAS main process exited"); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _nas_network_mngr() ** + ** ** + ** Description: Manages the connection endpoint use to communicate with ** + ** the network sublayer ** + ** ** + ** Inputs: fd: The descriptor of the network connection ** + ** endpoint ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _nas_network_mngr(void* args) +{ + LOG_FUNC_IN; + + int ret_code; + int network_message_id; + int bytes; + + int *fd = (int*) args; + + LOG_TRACE (INFO, "MME-MAIN - Network connection manager started (%d)", *fd); + + /* Network receiving loop */ + while (TRUE) + { + /* Read the network data message */ + bytes = network_api_read_data (*fd); + if (bytes == RETURNerror) + { + /* Failed to read data from the network sublayer; + * exit from the receiving loop */ + LOG_TRACE (ERROR, "MME-MAIN - " + "Failed to read data from the network sublayer"); + break; + } + + if (bytes == 0) + { + /* A signal was caught before any data were available */ + continue; + } + + /* Decode the network data message */ + network_message_id = network_api_decode_data (bytes); + if (network_message_id == RETURNerror) + { + /* Failed to decode data read from the network sublayer */ + continue; + } + + /* Process the network data message */ + ret_code = nas_network_process_data (network_message_id, network_api_get_data ()); + if (ret_code != RETURNok) + { + /* The network data message has not been successfully + * processed */ + LOG_TRACE + (WARNING, "MME-MAIN - " + "The network procedure call 0x%x failed", + network_message_id); + } + } + + /* Close the connection to the network sublayer */LOG_TRACE (WARNING, "MME-MAIN - " + "The network connection endpoint manager exited"); + + LOG_FUNC_RETURN(NULL); +} + +/**************************************************************************** + ** ** + ** Name: _nas_set_signal_handler() ** + ** ** + ** Description: Set up a signal handler ** + ** ** + ** Inputs: signal: Signal number ** + ** handler: Signal handler ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_set_signal_handler(int signal, void (handler)(int)) +{ + LOG_FUNC_IN; + + struct sigaction act; + + /* Initialize signal set */ + (void) memset (&act, 0, sizeof(act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + /* Initialize signal handler */ + act.sa_handler = handler; + if (sigaction (signal, &act, 0) < 0) + { + return RETURNerror; + } + + LOG_TRACE (INFO, "MME-MAIN - Handler successfully set for signal %d", signal); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _nas_signal_handler() ** + ** ** + ** Description: Signal handler ** + ** ** + ** Inputs: signal: Signal number ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _nas_signal_handler(int signal) +{ + LOG_FUNC_IN; + + LOG_TRACE (WARNING, "MME-MAIN - Signal %d received", signal); + _nas_clean (network_api_get_fd ()); + exit (EXIT_SUCCESS); + + LOG_FUNC_OUT + ; +} + +/**************************************************************************** + ** ** + ** Name: _nas_clean() ** + ** ** + ** Description: Performs termination cleanup ** + ** ** + ** Inputs: net_fd: Network's connection file descriptor ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _nas_clean(int net_fd) +{ + LOG_FUNC_IN; + + LOG_TRACE (INFO, "MME-MAIN - Perform EMM and ESM cleanup"); + nas_network_cleanup (); + + LOG_TRACE (INFO, "MME-MAIN - Closing network connection %d", net_fd); + network_api_close (net_fd); + + LOG_FUNC_OUT + ; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/Makefile b/openair-cn/NAS/EURECOM-NAS/src/Makefile new file mode 100644 index 0000000000..de1d50bea2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/Makefile @@ -0,0 +1,118 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +export LD_RUN_PATH = $(LIBDIR):$(LIBPROCESS) + +TARGET = $(PROCESS)process + +# Define the version number +DEFINES += -D'FIRMWARE_VERSION="$(SVN_REV) - $(DATE_REV)"' + +ifeq ($(TARGET), MMEprocess) + SRCS = MMEprocess.c nas_network.c nas_parser.c nas_proc.c +endif +ifeq ($(TARGET), UEprocess) + SRCS = UEprocess.c nas_network.c nas_parser.c nas_proc.c nas_user.c +endif + +LIBS = -lutil -lapi -lEMMmsg -lESMmsg -lEMMsap -lESMsap -lies -lrt +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(USERAPIDIR) -I$(NETAPIDIR) \ + -I$(EMMDIR) -I$(EMMMSGDIR) -I$(EMMSAPDIR) \ + -I$(ESMDIR) -I$(ESMMSGDIR) -I$(ESMSAPDIR) \ + -I$(IESDIR) + +.PHONY: $(TARGET) + +%.o: %.c Makefile $(PROJDIR)/Makerules $(PROJDIR)/Makefile.inc + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(EMMDIR)/*.o $(ESMDIR)/*.o $(LIBS) + @echo Replacing $@ to $(BINDIR) + @$(RM) $(BINDIR)/$@ + @$(CP) $@ $(BINDIR) + +# Always build the main object file which contains the version number +$(TARGET).o: .FORCE +.FORCE: + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) UE$(TARGET) MME$(TARGET) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +MMEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +MMEprocess.o: /usr/include/stdint.h /usr/include/features.h +MMEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MMEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +MMEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/network_api.h +MMEprocess.o: nas_network.h nas_parser.h /usr/include/stdlib.h +MMEprocess.o: /usr/include/alloca.h /usr/include/poll.h /usr/include/string.h +MMEprocess.o: /usr/include/xlocale.h /usr/include/signal.h +MMEprocess.o: /usr/include/time.h /usr/include/pthread.h +MMEprocess.o: /usr/include/endian.h /usr/include/sched.h +nas_network.o: nas_network.h +nas_network.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_network.o: /usr/include/stdint.h /usr/include/features.h +nas_network.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +nas_network.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/as_message.h +nas_network.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +nas_network.o: nas_proc.h +nas_parser.o: nas_parser.h +nas_parser.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/parser.h +nas_parser.o: /usr/include/stdio.h /usr/include/features.h +nas_parser.o: /usr/include/libio.h /usr/include/_G_config.h +nas_parser.o: /usr/include/wchar.h /usr/include/stdlib.h +nas_parser.o: /usr/include/alloca.h +nas_proc.o: nas_proc.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_proc.o: /usr/include/stdint.h /usr/include/features.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/emm_main.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/esm_main.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +nas_proc.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +nas_proc.o: /usr/include/stdio.h /usr/include/libio.h +nas_proc.o: /usr/include/_G_config.h /usr/include/wchar.h +nas_user.o: nas_user.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_user.o: /usr/include/stdint.h /usr/include/features.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/userDef.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/memory.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/user/at_command.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/user/at_response.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/user/at_error.h +nas_user.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/user/user_indication.h +nas_user.o: nas_proc.h /usr/include/string.h /usr/include/xlocale.h +nas_user.o: /usr/include/stdlib.h /usr/include/alloca.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +UEprocess.o: /usr/include/stdint.h /usr/include/features.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/user/user_api.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +UEprocess.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/network_api.h +UEprocess.o: nas_user.h nas_network.h nas_parser.h /usr/include/stdlib.h +UEprocess.o: /usr/include/alloca.h /usr/include/poll.h /usr/include/string.h +UEprocess.o: /usr/include/xlocale.h /usr/include/signal.h /usr/include/time.h +UEprocess.o: /usr/include/pthread.h /usr/include/endian.h +UEprocess.o: /usr/include/sched.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/UEprocess.c b/openair-cn/NAS/EURECOM-NAS/src/UEprocess.c new file mode 100644 index 0000000000..a042c66d97 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/UEprocess.c @@ -0,0 +1,467 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + + Source UEprocess.c + + Version 0.1 + + Date 2012/02/27 + + Product NAS stack + + Subsystem UE NAS main process + + Author Frederic Maurel + + Description Implements the Non-Access Stratum protocol for Evolved Packet + system (EPS) running at the User Equipment side. + + *****************************************************************************/ + +#include "commonDef.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "user_api.h" +#include "network_api.h" +#include "nas_user.h" +#include "nas_network.h" +#include "nas_parser.h" + +#include <stdlib.h> // exit +#include <poll.h> // poll +#include <string.h> // memset +#include <signal.h> // sigaction +#include <pthread.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#define NAS_SLEEP_TIMEOUT 1000 /* 1 second */ + +static void* _nas_user_mngr(void*); +static void* _nas_network_mngr(void*); + +static int _nas_set_signal_handler(int signal, void (handler)(int)); +static void _nas_signal_handler(int signal); + +static void _nas_clean(int usr_fd, int net_fd); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +int main(int argc, const char* argv[]) +{ + /* + * Get the command line options + */ + if (nas_parser_get_options (argc, argv) != RETURNok) + { + nas_parser_print_usage (FIRMWARE_VERSION); + exit (EXIT_FAILURE); + } + + /* + * Initialize logging trace utility + */ + nas_log_init (nas_parser_get_trace_level ()); + + const char* uhost = nas_parser_get_user_host (); + const char* uport = nas_parser_get_user_port (); + const char* devpath = nas_parser_get_device_path (); + const char* devparams = nas_parser_get_device_params (); + const char* nhost = nas_parser_get_network_host (); + const char* nport = nas_parser_get_network_port (); + + LOG_TRACE (INFO, "UE-MAIN - %s -ueid %d -uhost %s -uport %s -nhost %s -nport %s -dev %s -params %s -trace 0x%x", + argv[0], nas_parser_get_ueid (), uhost, uport, nhost, nport, devpath, devparams, + nas_parser_get_trace_level ()); + + /* + * Initialize the User interface + */ + if (user_api_initialize (uhost, uport, devpath, devparams) != RETURNok) + { + LOG_TRACE (ERROR, "UE-MAIN - user_api_initialize() failed"); + exit (EXIT_FAILURE); + } + int user_fd = user_api_get_fd (); + + /* + * Initialize the Network interface + */ + if (network_api_initialize (nhost, nport) != RETURNok) + { + LOG_TRACE (ERROR, "UE-MAIN - network_api_initialize() failed"); + user_api_close (user_fd); + exit (EXIT_FAILURE); + } + int network_fd = network_api_get_fd (); + + /* + * Initialize the NAS contexts + */ + nas_user_initialize (&user_api_emm_callback, &user_api_esm_callback, FIRMWARE_VERSION); + nas_network_initialize (); + + /* + * Initialize NAS timer handlers + */ + nas_timer_init (); + + /* + * Set up signal handlers + */ + (void) _nas_set_signal_handler (SIGINT, _nas_signal_handler); + (void) _nas_set_signal_handler (SIGTERM, _nas_signal_handler); + + pthread_attr_t attr; + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + + /* + * Start thread use to manage the user connection endpoint + */ + pthread_t user_mngr; + if (pthread_create (&user_mngr, &attr, _nas_user_mngr, &user_fd) != 0) + { + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to create the user management thread"); + user_api_close (user_fd); + network_api_close (network_fd); + exit (EXIT_FAILURE); + } + + /* + * Start thread use to manage the network connection endpoint + */ + pthread_t network_mngr; + if (pthread_create (&network_mngr, &attr, _nas_network_mngr, &network_fd) != 0) + { + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to create the network management thread"); + user_api_close (user_fd); + network_api_close (network_fd); + exit (EXIT_FAILURE); + } + pthread_attr_destroy (&attr); + + /* + * Suspend execution of the main process until all connection + * endpoints are still active + */ + while ((user_fd != -1) && (network_fd != -1)) + { + poll (NULL, 0, NAS_SLEEP_TIMEOUT); + user_fd = user_api_get_fd (); + network_fd = network_api_get_fd (); + } + + /* Termination cleanup */ + _nas_clean (user_fd, network_fd); + + LOG_TRACE + (WARNING, "UE-MAIN - NAS main process exited"); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _nas_user_mngr() ** + ** ** + ** Description: Manages the connection endpoint use to communicate with ** + ** the user application layer ** + ** ** + ** Inputs: fd: The descriptor of the user connection end- ** + ** point ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _nas_user_mngr(void* args) +{ + LOG_FUNC_IN; + + int ret_code; + int exit_loop = FALSE; + int nb_command; + int bytes; + + int *fd = (int*) args; + + LOG_TRACE (INFO, "UE-MAIN - User connection manager started (%d)", *fd); + + /* User receiving loop */ + while (!exit_loop) + { + /* Read the user data message */ + bytes = user_api_read_data (*fd); + if (bytes == RETURNerror) + { + /* Failed to read data from the user application layer; + * exit from the receiving loop */ + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to read data from the user application layer"); + break; + } + + if (bytes == 0) + { + /* A signal was caught before any data were available */ + continue; + } + + /* Decode the user data message */ + nb_command = user_api_decode_data (bytes); + for (int i = 0; i < nb_command; i++) + { + /* Get the user data to be processed */ + const void* data = user_api_get_data (i); + if (data == NULL) + { + /* Failed to get user data at the given index; + * go ahead and process the next user data */ + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to get user data at index %d", + i); + continue; + } + + /* Process the user data message */ + ret_code = nas_user_process_data (data); + if (ret_code != RETURNok) + { + /* The user data message has not been successfully + * processed; cause code will be encoded and sent back + * to the user */ + LOG_TRACE + (WARNING, "UE-MAIN - " + "The user procedure call failed"); + } + + /* Encode the user data message */ + bytes = user_api_encode_data (nas_user_get_data (), i == nb_command - 1); + if (bytes == RETURNerror) + { + /* Failed to encode the user data message; + * go ahead and process the next user data */ + continue; + } + + /* Send the data message to the user */ + bytes = user_api_send_data (*fd, bytes); + if (bytes == RETURNerror) + { + /* Failed to send data to the user application layer; + * exit from the receiving loop */ + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to send data to the user application layer"); + exit_loop = TRUE; + break; + } + } + } + + /* Close the connection to the user application layer */ + user_api_close (*fd); + LOG_TRACE (WARNING, "UE-MAIN - " + "The user connection endpoint manager exited"); + + LOG_FUNC_RETURN(NULL); +} + +/**************************************************************************** + ** ** + ** Name: _nas_network_mngr() ** + ** ** + ** Description: Manages the connection endpoint use to communicate with ** + ** the network sublayer ** + ** ** + ** Inputs: fd: The descriptor of the network connection ** + ** endpoint ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _nas_network_mngr(void* args) +{ + LOG_FUNC_IN; + + int ret_code; + int network_message_id; + int bytes; + + int *fd = (int*) args; + + LOG_TRACE (INFO, "UE-MAIN - Network connection manager started (%d)", *fd); + + /* Network receiving loop */ + while (TRUE) + { + /* Read the network data message */ + bytes = network_api_read_data (*fd); + if (bytes == RETURNerror) + { + /* Failed to read data from the network sublayer; + * exit from the receiving loop */ + LOG_TRACE (ERROR, "UE-MAIN - " + "Failed to read data from the network sublayer"); + break; + } + + if (bytes == 0) + { + /* A signal was caught before any data were available */ + continue; + } + + /* Decode the network data message */ + network_message_id = network_api_decode_data (bytes); + if (network_message_id == RETURNerror) + { + /* Failed to decode data read from the network sublayer */ + continue; + } + + /* Process the network data message */ + ret_code = nas_network_process_data (network_message_id, network_api_get_data ()); + if (ret_code != RETURNok) + { + /* The network data message has not been successfully + * processed */ + LOG_TRACE + (WARNING, "UE-MAIN - " + "The network procedure call 0x%x failed", + network_message_id); + } + } + + /* Close the connection to the network sublayer */ + network_api_close (*fd); + LOG_TRACE (WARNING, "UE-MAIN - " + "The network connection endpoint manager exited"); + + LOG_FUNC_RETURN(NULL); +} + +/**************************************************************************** + ** ** + ** Name: _nas_set_signal_handler() ** + ** ** + ** Description: Set up a signal handler ** + ** ** + ** Inputs: signal: Signal number ** + ** handler: Signal handler ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_set_signal_handler(int signal, void (handler)(int)) +{ + LOG_FUNC_IN; + + struct sigaction act; + + /* Initialize signal set */ + (void) memset (&act, 0, sizeof(act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + /* Initialize signal handler */ + act.sa_handler = handler; + if (sigaction (signal, &act, 0) < 0) + { + return RETURNerror; + } + + LOG_TRACE (INFO, "UE-MAIN - Handler successfully set for signal %d", signal); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _nas_signal_handler() ** + ** ** + ** Description: Signal handler ** + ** ** + ** Inputs: signal: Signal number ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _nas_signal_handler(int signal) +{ + LOG_FUNC_IN; + + LOG_TRACE (WARNING, "UE-MAIN - Signal %d received", signal); + _nas_clean (user_api_get_fd (), network_api_get_fd ()); + exit (EXIT_SUCCESS); + + LOG_FUNC_OUT + ; +} + +/**************************************************************************** + ** ** + ** Name: _nas_clean() ** + ** ** + ** Description: Performs termination cleanup ** + ** ** + ** Inputs: usr_fd: User's connection file descriptor ** + ** net_fd: Network's connection file descriptor ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _nas_clean(int usr_fd, int net_fd) +{ + LOG_FUNC_IN; + + LOG_TRACE (INFO, "UE-MAIN - Perform EMM and ESM cleanup"); + nas_network_cleanup (); + + LOG_TRACE (INFO, "UE-MAIN - " + "Closing user connection %d and network connection %d", + usr_fd, net_fd); + user_api_close (usr_fd); + network_api_close (net_fd); + + LOG_FUNC_OUT + ; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/Makefile new file mode 100644 index 0000000000..764dae8f30 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/Makefile @@ -0,0 +1,47 @@ +ifndef PROJDIR +export PROJDIR = $(PWD)/../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +export INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(EMMMSGDIR) -I$(ESMMSGDIR) + +TARGET = $(LIBAPI) +TARGETS = $(TARGET).a $(TARGET).so +OBJS = $(USERAPIDIR)/*.o $(NETAPIDIR)/*.o $(USIMAPIDIR)/*.o $(MMEAPIDIR)/*.o + +all: + @$(CD) $(NETAPIDIR) && $(MAKE) + @$(CD) $(USERAPIDIR) && $(MAKE) + @$(CD) $(USIMAPIDIR) && $(MAKE) + @$(CD) $(MMEAPIDIR) && $(MAKE) + @$(MAKE) $(TARGETS) + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $^ + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $^ + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +clean: + $(RM) *.bak *~ + @$(CD) $(USERAPIDIR) && $(MAKE) $@ + @$(CD) $(NETAPIDIR) && $(MAKE) $@ + @$(CD) $(USIMAPIDIR) && $(MAKE) $@ + @$(CD) $(MMEAPIDIR) && $(MAKE) $@ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/mme/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/mme/Makefile new file mode 100644 index 0000000000..881aefdcd9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/mme/Makefile @@ -0,0 +1,21 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +all: $(OBJS) + +%.o: %.c Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) $(OBJS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.c b/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.c new file mode 100644 index 0000000000..cfb0163e9b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.c @@ -0,0 +1,501 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source mme_api.c + +Version 0.1 + +Date 2013/02/28 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer running in the MME + to interact with a Mobility Management Entity + +*****************************************************************************/ + +#ifdef NAS_MME + +#include "mme_api.h" +#include "nas_log.h" + +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Maximum number of PDN connections the MME may simultaneously support */ +#define MME_API_PDN_MAX 10 + +/* MME group identifier */ +#define MME_API_MME_GID 0x0102 + +/* MME code */ +#define MME_API_MME_CODE 0x12 + +/* Default APN */ +static const OctetString mme_api_default_apn = { + 14, (uint8_t*)("www.eurecom.fr")}; + +/* APN configured for emergency bearer services */ +static const OctetString mme_api_emergency_apn = { + 18, (uint8_t*)("www.eurecom_sos.fr")}; + +/* Public Land Mobile Network identifier */ +static const plmn_t mme_api_plmn = {0, 2, 0xf, 8, 0, 1}; // 20810 + +/* Number of concecutive tracking areas */ +#define MME_API_NB_TACS 4 +/* Code of the first tracking area belonging to the PLMN */ +#define MME_API_FIRST_TAC 0x0001 + +/* NAS security key */ +#define MME_API_KASME "CAFECAFECAFECAFECAFECAFECAFECAFE" + +/* Authentication parameter RAND */ +static const UInt8_t _mme_api_rand[AUTH_RAND_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x03, 0x04 +}; + +/* Authentication parameter AUTN */ +static const UInt8_t _mme_api_autn[AUTH_AUTN_SIZE] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x05, 0x04, 0x03, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +/* Authentication response parameter */ +static const UInt8_t _mme_api_xres[AUTH_XRES_SIZE] = { + 0x67, 0x70, 0x3a, 0x31, 0xf2, 0x2a, 0x2d, 0x51, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 +}; + +/* Network IP version capability */ +enum { + MME_API_IPV4_ADDR, + MME_API_IPV6_ADDR, + MME_API_IPV4V6_ADDR, + MME_API_ADDR_MAX +} _mme_api_ip_capability = MME_API_IPV4V6_ADDR; + +/* Pool of IPv4 addresses */ +static uint8_t _mme_api_ipv4_addr[MME_API_PDN_MAX][4] = { + {0xC0, 0xA8, 0x02, 0x3C}, /* 192.168.02.60 */ + {0xC0, 0xA8, 0x0C, 0xBB}, /* 192.168.12.187 */ + {0xC0, 0xA8, 0x0C, 0xBC}, /* 192.168.12.188 */ + {0xC0, 0xA8, 0x0C, 0xBD}, /* 192.168.12.189 */ + {0xC0, 0xA8, 0x0C, 0xBE}, /* 192.168.12.190 */ + {0xC0, 0xA8, 0x0C, 0xBF}, /* 192.168.12.191 */ + {0xC0, 0xA8, 0x0C, 0xC0}, /* 192.168.12.192 */ + {0xC0, 0xA8, 0x0C, 0xC1}, /* 192.168.12.193 */ + {0xC0, 0xA8, 0x0C, 0xC2}, /* 192.168.12.194 */ + {0xC0, 0xA8, 0x0C, 0xC3}, /* 192.168.12.195 */ +}; +/* Pool of IPv6 addresses */ +static uint8_t _mme_api_ipv6_addr[MME_API_PDN_MAX][8] = { + /* FE80::221:70FF:C0A8:023C/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}, + /* FE80::221:70FF:C0A8:0CBB/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}, + /* FE80::221:70FF:C0A8:0CBC/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBC}, + /* FE80::221:70FF:C0A8:0CBD/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBD}, + /* FE80::221:70FF:C0A8:0CBE/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBE}, + /* FE80::221:70FF:C0A8:0CBF/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBF}, + /* FE80::221:70FF:C0A8:0CC0/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC0}, + /* FE80::221:70FF:C0A8:0CC1/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC1}, + /* FE80::221:70FF:C0A8:0CC2/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC2}, + /* FE80::221:70FF:C0A8:0CC3/64 */ + {0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC3}, +}; +/* Pool of IPv4v6 addresses */ +static uint8_t _mme_api_ipv4v6_addr[MME_API_PDN_MAX][12] = { + /* 192.168.02.60, FE80::221:70FF:C0A8:023C/64 */ + {0xC0, 0xA8, 0x02, 0x3C, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}, + /* 192.168.12.187, FE80::221:70FF:C0A8:0CBB/64 */ + {0xC0, 0xA8, 0x0C, 0xBB, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}, + /* 192.168.12.188, FE80::221:70FF:C0A8:0CBC/64 */ + {0xC0, 0xA8, 0x0C, 0xBC, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBC}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CBD/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBD}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CBE/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBE}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CBF/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBF}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CC0/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC0}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CC1/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC1}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CC2/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC2}, + /* 192.168.12.189, FE80::221:70FF:C0A8:0CC3/64 */ + {0xC0, 0xA8, 0x0C, 0xBD, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xC3}, +}; +static const OctetString _mme_api_pdn_addr[MME_API_ADDR_MAX][MME_API_PDN_MAX] = +{ + { /* IPv4 network capability */ + {4, _mme_api_ipv4_addr[0]}, + {4, _mme_api_ipv4_addr[1]}, + {4, _mme_api_ipv4_addr[2]}, + {4, _mme_api_ipv4_addr[3]}, + {4, _mme_api_ipv4_addr[4]}, + {4, _mme_api_ipv4_addr[5]}, + {4, _mme_api_ipv4_addr[6]}, + {4, _mme_api_ipv4_addr[7]}, + {4, _mme_api_ipv4_addr[8]}, + {4, _mme_api_ipv4_addr[9]}, + }, + { /* IPv6 network capability */ + {8, _mme_api_ipv6_addr[0]}, + {8, _mme_api_ipv6_addr[1]}, + {8, _mme_api_ipv6_addr[2]}, + {8, _mme_api_ipv6_addr[3]}, + {8, _mme_api_ipv6_addr[4]}, + {8, _mme_api_ipv6_addr[5]}, + {8, _mme_api_ipv6_addr[6]}, + {8, _mme_api_ipv6_addr[7]}, + {8, _mme_api_ipv6_addr[8]}, + {8, _mme_api_ipv6_addr[9]}, + }, + { /* IPv4v6 network capability */ + {12, _mme_api_ipv4v6_addr[0]}, + {12, _mme_api_ipv4v6_addr[1]}, + {12, _mme_api_ipv4v6_addr[2]}, + {12, _mme_api_ipv4v6_addr[3]}, + {12, _mme_api_ipv4v6_addr[4]}, + {12, _mme_api_ipv4v6_addr[5]}, + {12, _mme_api_ipv4v6_addr[6]}, + {12, _mme_api_ipv4v6_addr[7]}, + {12, _mme_api_ipv4v6_addr[8]}, + {12, _mme_api_ipv4v6_addr[9]}, + }, +}; + +/* Subscribed QCI */ +#define MME_API_QCI 3 + +/* Data bit rates */ +#define MME_API_BIT_RATE_64K 0x40 +#define MME_API_BIT_RATE_128K 0x48 +#define MME_API_BIT_RATE_512K 0x78 +#define MME_API_BIT_RATE_1024K 0x87 + +/* Total number of PDN connections (should not exceed MME_API_PDN_MAX) */ +static int _mme_api_pdn_id = 0; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: mme_api_get_emm_config() ** + ** ** + ** Description: Retreives MME configuration data related to EPS mobility ** + ** management ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_get_emm_config(mme_api_emm_config_t* config) +{ + LOG_FUNC_IN; + + config->gummei.plmn.MCCdigit1 = 2; + config->gummei.plmn.MCCdigit2 = 0; + config->gummei.plmn.MCCdigit3 = 8; + config->gummei.plmn.MNCdigit1 = 1; + config->gummei.plmn.MNCdigit2 = 0; + config->gummei.plmn.MNCdigit3 = 0xf; + config->gummei.MMEgid = MME_API_MME_GID; + config->gummei.MMEcode = MME_API_MME_CODE; + config->features = MME_API_EMERGENCY_ATTACH | MME_API_UNAUTHENTICATED_IMSI; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_get_config() ** + ** ** + ** Description: Retreives MME configuration data related to EPS session ** + ** management ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_get_esm_config(mme_api_esm_config_t* config) +{ + LOG_FUNC_IN; + + if (_mme_api_ip_capability == MME_API_IPV4_ADDR) { + config->features = MME_API_IPV4; + } else if (_mme_api_ip_capability == MME_API_IPV6_ADDR) { + config->features = MME_API_IPV6; + } else if (_mme_api_ip_capability == MME_API_IPV4V6_ADDR) { + config->features = MME_API_IPV4 | MME_API_IPV6; + } else { + config->features = 0; + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_identify_guti() ** + ** ** + ** Description: Requests the MME to identify the UE using the specified ** + ** GUTI. If the UE is known by the MME (a Mobility Manage- ** + ** ment context exists for this UE in the MME), its se- ** + ** curity context is returned. ** + ** ** + ** Inputs: guti: EPS Globally Unique Temporary UE Identity ** + ** Others: None ** + ** ** + ** Outputs: vector: The EPS authentication vector of the UE if ** + ** known by the network; NULL otherwise. ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_identify_guti(const GUTI_t* guti, auth_vector_t* vector) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_identify_imsi() ** + ** ** + ** Description: Requests the MME to identify the UE using the specified ** + ** IMSI. If the UE is known by the MME (a Mobility Manage- ** + ** ment context exists for this UE in the MME), its se- ** + ** curity context is returned. ** + ** ** + ** Inputs: imsi: International Mobile Subscriber Identity ** + ** Others: None ** + ** ** + ** Outputs: vector: The EPS authentication vector of the UE if ** + ** known by the network; NULL otherwise. ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_identify_imsi(const imsi_t* imsi, auth_vector_t* vector) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + memcpy(vector->rand, _mme_api_rand, AUTH_RAND_SIZE); + memcpy(vector->autn, _mme_api_autn, AUTH_AUTN_SIZE); + memcpy(vector->xres, _mme_api_xres, AUTH_XRES_SIZE); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_identify_imei() ** + ** ** + ** Description: Requests the MME to identify the UE using the specified ** + ** IMEI. If the UE is known by the MME (a Mobility Manage- ** + ** ment context exists for this UE in the MME), its se- ** + ** curity context is returned. ** + ** ** + ** Inputs: imei: International Mobile Equipment Identity ** + ** Others: None ** + ** ** + ** Outputs: vector: The EPS authentication vector of the UE if ** + ** known by the network; NULL otherwise. ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_identify_imei(const imei_t* imei, auth_vector_t* vector) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_new_guti() ** + ** ** + ** Description: Requests the MME to assign a new GUTI to the UE identi- ** + ** fied by the given IMSI. ** + ** ** + ** Description: Requests the MME to assign a new GUTI to the UE identi- ** + ** fied by the given IMSI and returns the list of consecu- ** + ** tive tracking areas the UE is registered to. ** + ** ** + ** Inputs: imsi: International Mobile Subscriber Identity ** + ** Others: None ** + ** ** + ** Outputs: guti: The new assigned GUTI ** + ** tac: Code of the first tracking area belonging ** + ** to the PLMN ** + ** n_tacs: Number of concecutive tracking areas ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_new_guti(const imsi_t* imsi, GUTI_t* guti, tac_t* tac, int* n_tacs) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + static unsigned int tmsi = 1; + + guti->gummei.plmn = mme_api_plmn; + guti->gummei.MMEgid = MME_API_MME_GID; + guti->gummei.MMEcode = MME_API_MME_CODE; + guti->m_tmsi = tmsi++; + + *tac = MME_API_FIRST_TAC; + *n_tacs = MME_API_NB_TACS; + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_subscribe() ** + ** ** + ** Description: Requests the MME to check whether connectivity with the ** + ** requested PDN can be established using the specified APN. ** + ** If accepted the MME returns PDN subscription context con- ** + ** taining EPS subscribed QoS profile, the default APN if ** + ** required and UE's IPv4 address and/or the IPv6 prefix. ** + ** ** + ** Inputs: apn: If not NULL, Access Point Name of the PDN ** + ** to connect to ** + ** is_emergency: TRUE if the PDN connectivity is requested ** + ** for emergency bearer services ** + ** Others: None ** + ** ** + ** Outputs: apn: If NULL, default APN or APN configured for ** + ** emergency bearer services ** + ** pdn_addr: PDN connection IPv4 address or IPv6 inter- ** + ** face identifier to be used to build the ** + ** IPv6 link local address ** + ** qos: EPS subscribed QoS profile ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_subscribe(OctetString* apn, OctetString* pdn_addr, + int is_emergency, mme_api_qos_t* qos) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if ( apn && (apn->length == 0) ) { + /* PDN connectivity to default APN */ + if (is_emergency) { + apn->length = mme_api_emergency_apn.length; + apn->value = mme_api_emergency_apn.value; + } else { + apn->length = mme_api_default_apn.length; + apn->value = mme_api_default_apn.value; + } + } + + /* Assign PDN address */ + if ( pdn_addr && (_mme_api_pdn_id < MME_API_PDN_MAX) ) { + pdn_addr->length = + _mme_api_pdn_addr[_mme_api_ip_capability][_mme_api_pdn_id].length; + pdn_addr->value = + _mme_api_pdn_addr[_mme_api_ip_capability][_mme_api_pdn_id].value; + /* Increment the total number of PDN connections */ + _mme_api_pdn_id += 1; + } else { + /* Maximum number of PDN connections exceeded */ + rc = RETURNerror; + } + + /* Setup EPS subscribed QoS profile */ + if (qos) { + qos->qci = MME_API_QCI; + /* Uplink bit rate */ + qos->gbr[MME_API_UPLINK] = MME_API_BIT_RATE_64K; + qos->mbr[MME_API_UPLINK] = MME_API_BIT_RATE_128K; + /* Downlink bit rate */ + qos->gbr[MME_API_DOWNLINK] = MME_API_BIT_RATE_512K; + qos->mbr[MME_API_DOWNLINK] = MME_API_BIT_RATE_1024K; + } else { + rc = RETURNerror; + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: mme_api_unsubscribe() ** + ** ** + ** Description: Requests the MME to release connectivity with the reques- ** + ** ted PDN using the specified APN. ** + ** ** + ** Inputs: apn: Access Point Name of the PDN to disconnect ** + ** from ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int mme_api_unsubscribe(OctetString* apn) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + /* Decrement the total number of PDN connections */ + _mme_api_pdn_id -= 1; + + LOG_FUNC_RETURN(rc); +} + +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.h b/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.h new file mode 100644 index 0000000000..ee6d0e540d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/mme/mme_api.h @@ -0,0 +1,105 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source mme_api.h + +Version 0.1 + +Date 2013/02/28 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer running in the MME + to interact with a Mobility Management Entity + +*****************************************************************************/ +#ifndef __MME_API_H__ +#define __MME_API_H__ + +#ifdef NAS_MME +#include "commonDef.h" +#include "securityDef.h" +#include "OctetString.h" +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Maximum number of UEs the MME may simultaneously support */ +#define MME_API_NB_UE_MAX 1 + +#ifdef NAS_MME + +/* Features supported by the MME */ +typedef enum { + MME_API_NO_FEATURE_SUPPORTED = 0, + MME_API_EMERGENCY_ATTACH = (1<<0), + MME_API_UNAUTHENTICATED_IMSI = (1<<1), + MME_API_IPV4 = (1<<2), + MME_API_IPV6 = (1<<3), + MME_API_SINGLE_ADDR_BEARERS = (1<<4), +} mme_api_feature_t; + +/* + * EPS Mobility Management configuration data + * ------------------------------------------ + */ +typedef struct { + mme_api_feature_t features; /* Supported features */ + gummei_t gummei; /* EPS Globally Unique MME Identity */ +} mme_api_emm_config_t; + +/* + * EPS Session Management configuration data + * ----------------------------------------- + */ +typedef struct { + mme_api_feature_t features; /* Supported features */ +} mme_api_esm_config_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* EPS subscribed QoS profile */ +typedef struct { +#define MME_API_UPLINK 0 +#define MME_API_DOWNLINK 1 +#define MME_API_DIRECTION 2 + int gbr[MME_API_DIRECTION]; /* Guaranteed Bit Rate */ + int mbr[MME_API_DIRECTION]; /* Maximum Bit Rate */ + int qci; /* QoS Class Identifier */ +} mme_api_qos_t; + +/* Traffic Flow Template */ +typedef struct { +} mme_api_tft_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int mme_api_get_emm_config(mme_api_emm_config_t* config); +int mme_api_get_esm_config(mme_api_esm_config_t* config); + +int mme_api_identify_guti(const GUTI_t* guti, auth_vector_t* vector); +int mme_api_identify_imsi(const imsi_t* imsi, auth_vector_t* vector); +int mme_api_identify_imei(const imei_t* imei, auth_vector_t* vector); +int mme_api_new_guti(const imsi_t* imsi, GUTI_t* guti, tac_t* tac, int* n_tacs); + +int mme_api_subscribe(OctetString* apn, OctetString* pdn_addr, int is_emergency, mme_api_qos_t* qos); +int mme_api_unsubscribe(OctetString* apn); + +#endif // NAS_MME + +#endif /* __MME_API_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/network/Makefile new file mode 100644 index 0000000000..216db33a18 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/Makefile @@ -0,0 +1,185 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(EMMMSGDIR) -I$(ESMMSGDIR) +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +all: $(OBJS) + +%.o: %.c Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) $(OBJS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +as_message.o: as_message.h +as_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +as_message.o: /usr/include/stdint.h /usr/include/features.h +as_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +as_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +as_message.o: /usr/include/string.h /usr/include/xlocale.h +as_message.o: /usr/include/stdlib.h /usr/include/alloca.h +nas_message.o: nas_message.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_message.o: /usr/include/stdint.h /usr/include/features.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h +nas_message.o: /usr/include/stdio.h /usr/include/libio.h +nas_message.o: /usr/include/_G_config.h /usr/include/wchar.h +nas_message.o: /usr/include/stdlib.h /usr/include/alloca.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MessageType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DrxParameter.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TmsiStatus.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GutiType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GprsTimer.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmmCause.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PlmnList.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DetachType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Nonce.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ServiceType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CsfbResponse.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ShortMac.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/IdentityType2.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NetworkName.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZone.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PagingIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Cli.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SsCode.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsIndicator.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/QualityOfService.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RadioPriority.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmCause.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AccessPointName.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnAddress.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RequestType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnType.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +nas_message.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +nas_message.o: /usr/include/endian.h +nas_message.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +nas_message.o: /usr/include/string.h /usr/include/xlocale.h +network_api.o: network_api.h +network_api.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +network_api.o: /usr/include/stdint.h /usr/include/features.h +network_api.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +network_api.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/socket.h +network_api.o: as_message.h +network_api.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +network_api.o: /usr/include/string.h /usr/include/xlocale.h +network_api.o: /usr/include/netdb.h /usr/include/netinet/in.h +network_api.o: /usr/include/endian.h /usr/include/rpc/netdb.h +network_api.o: /usr/include/errno.h /usr/include/unistd.h +network_api.o: /usr/include/getopt.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.c b/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.c new file mode 100644 index 0000000000..9b85fde5f3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.c @@ -0,0 +1,347 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_message.c + +Version 0.1 + +Date 2012/11/06 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the messages supported by the Access Stratum sublayer + protocol (usually RRC and S1AP for E-UTRAN) and functions used + to encode and decode + +*****************************************************************************/ + +#include "as_message.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <string.h> // memcpy +#include <stdlib.h> // free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: as_message_decode() ** + ** ** + ** Description: Decode AS message and accordingly fills data structure ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the ** + ** message ** + ** length: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: AS message structure to be filled ** + ** Return: The AS message identifier when the buffer ** + ** has been successfully decoded; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int as_message_decode(const char* buffer, as_message_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes; + Byte_t** data = NULL; + + /* Get the message type */ + msg->msgID = *(UInt16_t*)(buffer); + bytes = sizeof(UInt16_t); + + switch (msg->msgID) + { + case AS_NAS_ESTABLISH_REQ: + /* NAS signalling connection establish request */ + bytes += sizeof(nas_establish_req_t) - sizeof(Byte_t*); + data = &msg->msg.nas_establish_req.initialNasMsg.data; + break; + + case AS_NAS_ESTABLISH_IND: + /* NAS signalling connection establishment indication */ + bytes += sizeof(nas_establish_ind_t) - sizeof(Byte_t*); + data = &msg->msg.nas_establish_ind.initialNasMsg.data; + break; + + case AS_NAS_ESTABLISH_RSP: + /* NAS signalling connection establishment response */ + bytes += sizeof(nas_establish_rsp_t) - sizeof(Byte_t*); + data = &msg->msg.nas_establish_rsp.nasMsg.data; + break; + + case AS_NAS_ESTABLISH_CNF: + /* NAS signalling connection establishment confirm */ + bytes += sizeof(nas_establish_cnf_t) - sizeof(Byte_t*); + data = &msg->msg.nas_establish_cnf.nasMsg.data; + break; + + case AS_UL_INFO_TRANSFER_REQ: + /* Uplink L3 data transfer request */ + bytes += sizeof(ul_info_transfer_req_t) - sizeof(Byte_t*); + data = &msg->msg.ul_info_transfer_req.nasMsg.data; + break; + + case AS_UL_INFO_TRANSFER_IND: + /* Uplink L3 data transfer indication */ + bytes += sizeof(ul_info_transfer_ind_t) - sizeof(Byte_t*); + data = &msg->msg.ul_info_transfer_ind.nasMsg.data; + break; + + case AS_DL_INFO_TRANSFER_REQ: + /* Downlink L3 data transfer request */ + bytes += sizeof(dl_info_transfer_req_t) - sizeof(Byte_t*); + data = &msg->msg.dl_info_transfer_req.nasMsg.data; + break; + + case AS_DL_INFO_TRANSFER_IND: + /* Downlink L3 data transfer indication */ + bytes += sizeof(dl_info_transfer_ind_t) - sizeof(Byte_t*); + data = &msg->msg.dl_info_transfer_ind.nasMsg.data; + break; + + case AS_BROADCAST_INFO_IND: + case AS_CELL_INFO_REQ: + case AS_CELL_INFO_CNF: + case AS_CELL_INFO_IND: + case AS_PAGING_REQ: + case AS_PAGING_IND: + case AS_NAS_RELEASE_REQ: + case AS_UL_INFO_TRANSFER_CNF: + case AS_DL_INFO_TRANSFER_CNF: + case AS_NAS_RELEASE_IND: + case AS_RAB_ESTABLISH_REQ: + case AS_RAB_ESTABLISH_IND: + case AS_RAB_ESTABLISH_RSP: + case AS_RAB_ESTABLISH_CNF: + case AS_RAB_RELEASE_REQ: + case AS_RAB_RELEASE_IND: + /* Messages without dedicated NAS information */ + bytes = length; + break; + + default: + bytes = 0; + LOG_TRACE(WARNING, "NET-API - AS message 0x%x is not valid", + msg->msgID); + break; + } + + if (bytes > 0) { + if (data) { + /* Set the pointer to dedicated NAS information */ + *data = (Byte_t*)(buffer + bytes); + } + /* Decode the message */ + memcpy(msg, (as_message_t*)buffer, bytes); + LOG_FUNC_RETURN (msg->msgID); + } + + LOG_TRACE(WARNING, "NET-API - Failed to decode AS message 0x%x", + msg->msgID); + LOG_FUNC_RETURN (RETURNerror); + } + +/**************************************************************************** + ** ** + ** Name: as_message_encode() ** + ** ** + ** Description: Encode AS message ** + ** ** + ** Inputs: msg: AS message structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters in the buffer ** + ** when data have been successfully encoded; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int as_message_encode(char* buffer, as_message_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = sizeof(msg->msgID); + as_nas_info_t* nas_msg = NULL; + + switch (msg->msgID) + { + case AS_BROADCAST_INFO_IND: + /* Broadcast information */ + bytes += sizeof(broadcast_info_ind_t); + break; + + case AS_CELL_INFO_REQ: + /* Cell information request */ + bytes += sizeof(cell_info_req_t); + break; + + case AS_CELL_INFO_CNF: + /* Cell information response */ + bytes += sizeof(cell_info_cnf_t); + break; + + case AS_CELL_INFO_IND: + /* Cell information indication */ + bytes += sizeof(cell_info_ind_t); + break; + + case AS_PAGING_REQ: + /* Paging information request */ + bytes += sizeof(paging_req_t); + break; + + case AS_PAGING_IND: + /* Paging information indication */ + bytes += sizeof(paging_ind_t); + break; + + case AS_NAS_ESTABLISH_REQ: + /* NAS signalling connection establish request */ + bytes += sizeof(nas_establish_req_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.nas_establish_req.initialNasMsg; + break; + + case AS_NAS_ESTABLISH_IND: + /* NAS signalling connection establish indication */ + bytes += sizeof(nas_establish_ind_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.nas_establish_ind.initialNasMsg; + break; + + case AS_NAS_ESTABLISH_RSP: + /* NAS signalling connection establish response */ + bytes += sizeof(nas_establish_rsp_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.nas_establish_rsp.nasMsg; + break; + + case AS_NAS_ESTABLISH_CNF: + /* NAS signalling connection establish confirm */ + bytes += sizeof(nas_establish_cnf_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.nas_establish_cnf.nasMsg; + break; + + case AS_NAS_RELEASE_REQ: + /* NAS signalling connection release request */ + bytes += sizeof(nas_release_req_t); + break; + + case AS_NAS_RELEASE_IND: + /* NAS signalling connection release indication */ + bytes += sizeof(nas_release_ind_t); + break; + + case AS_UL_INFO_TRANSFER_REQ: + /* Uplink L3 data transfer request */ + bytes += sizeof(ul_info_transfer_req_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.ul_info_transfer_req.nasMsg; + break; + + case AS_UL_INFO_TRANSFER_CNF: + /* Uplink L3 data transfer confirm */ + bytes += sizeof(ul_info_transfer_cnf_t); + break; + + case AS_UL_INFO_TRANSFER_IND: + /* Uplink L3 data transfer indication */ + bytes += sizeof(ul_info_transfer_ind_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.ul_info_transfer_ind.nasMsg; + break; + + case AS_DL_INFO_TRANSFER_REQ: + /* Downlink L3 data transfer */ + bytes += sizeof(dl_info_transfer_req_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.dl_info_transfer_req.nasMsg; + break; + + case AS_DL_INFO_TRANSFER_CNF: + /* Downlink L3 data transfer confirm */ + bytes += sizeof(dl_info_transfer_cnf_t); + break; + + case AS_DL_INFO_TRANSFER_IND: + /* Downlink L3 data transfer indication */ + bytes += sizeof(dl_info_transfer_ind_t) - sizeof(Byte_t*); + nas_msg = &msg->msg.dl_info_transfer_ind.nasMsg; + break; + + case AS_RAB_ESTABLISH_REQ: + /* Radio Access Bearer establishment request */ + bytes += sizeof(rab_establish_req_t); + break; + + case AS_RAB_ESTABLISH_IND: + /* Radio Access Bearer establishment indication */ + bytes += sizeof(rab_establish_ind_t); + break; + + case AS_RAB_ESTABLISH_RSP: + /* Radio Access Bearer establishment response */ + bytes += sizeof(rab_establish_rsp_t); + break; + + case AS_RAB_ESTABLISH_CNF: + /* Radio Access Bearer establishment confirm */ + bytes += sizeof(rab_establish_cnf_t); + break; + + case AS_RAB_RELEASE_REQ: + /* Radio Access Bearer release request */ + bytes += sizeof(rab_release_req_t); + break; + + case AS_RAB_RELEASE_IND: + /* Radio Access Bearer release indication */ + bytes += sizeof(rab_release_ind_t); + break; + + default: + LOG_TRACE(WARNING, "NET-API - AS message 0x%x is not valid", + msg->msgID); + bytes = length; + break; + } + + if (length > bytes) { + /* Encode the AS message */ + memcpy(buffer, (unsigned char*)msg, bytes); + if ( nas_msg && (nas_msg->length > 0) ) { + /* Copy the NAS message */ + memcpy(buffer + bytes, nas_msg->data, nas_msg->length); + bytes += nas_msg->length; + /* Release NAS message memory */ + free(nas_msg->data); + nas_msg->length = 0; + nas_msg->data = NULL; + } + LOG_FUNC_RETURN (bytes); + } + + LOG_TRACE(WARNING, "NET-API - Failed to encode AS message 0x%x", + msg->msgID); + LOG_FUNC_RETURN (RETURNerror); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.h b/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.h new file mode 100644 index 0000000000..ff5bd8f747 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/as_message.h @@ -0,0 +1,515 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_message.h + +Version 0.1 + +Date 2012/10/18 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the messages supported by the Access Stratum sublayer + protocol (usually RRC and S1AP for E-UTRAN) and functions used + to encode and decode + +*****************************************************************************/ +#ifndef __AS_MESSAGE_H__ +#define __AS_MESSAGE_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Access Stratum message types + * -------------------------------------------------------------------------- + */ +#define AS_REQUEST 0x0100 +#define AS_RESPONSE 0x0200 +#define AS_INDICATION 0x0400 +#define AS_CONFIRM 0x0800 + +/* + * -------------------------------------------------------------------------- + * Access Stratum message identifiers + * -------------------------------------------------------------------------- + */ + +/* Broadcast information */ +#define AS_BROADCAST_INFO 0x01 +#define AS_BROADCAST_INFO_IND (AS_BROADCAST_INFO | AS_INDICATION) + +/* Cell information relevant for cell selection processing */ +#define AS_CELL_INFO 0x02 +#define AS_CELL_INFO_REQ (AS_CELL_INFO | AS_REQUEST) +#define AS_CELL_INFO_CNF (AS_CELL_INFO | AS_CONFIRM) +#define AS_CELL_INFO_IND (AS_CELL_INFO | AS_INDICATION) + +/* Paging information */ +#define AS_PAGING 0x03 +#define AS_PAGING_REQ (AS_PAGING | AS_REQUEST) +#define AS_PAGING_IND (AS_PAGING | AS_INDICATION) + +/* NAS signalling connection establishment */ +#define AS_NAS_ESTABLISH 0x04 +#define AS_NAS_ESTABLISH_REQ (AS_NAS_ESTABLISH | AS_REQUEST) +#define AS_NAS_ESTABLISH_IND (AS_NAS_ESTABLISH | AS_INDICATION) +#define AS_NAS_ESTABLISH_RSP (AS_NAS_ESTABLISH | AS_RESPONSE) +#define AS_NAS_ESTABLISH_CNF (AS_NAS_ESTABLISH | AS_CONFIRM) + +/* NAS signalling connection release */ +#define AS_NAS_RELEASE 0x05 +#define AS_NAS_RELEASE_REQ (AS_NAS_RELEASE | AS_REQUEST) +#define AS_NAS_RELEASE_IND (AS_NAS_RELEASE | AS_INDICATION) + +/* Uplink information transfer */ +#define AS_UL_INFO_TRANSFER 0x06 +#define AS_UL_INFO_TRANSFER_REQ (AS_UL_INFO_TRANSFER | AS_REQUEST) +#define AS_UL_INFO_TRANSFER_CNF (AS_UL_INFO_TRANSFER | AS_CONFIRM) +#define AS_UL_INFO_TRANSFER_IND (AS_UL_INFO_TRANSFER | AS_INDICATION) + +/* Downlink information transfer */ +#define AS_DL_INFO_TRANSFER 0x07 +#define AS_DL_INFO_TRANSFER_REQ (AS_DL_INFO_TRANSFER | AS_REQUEST) +#define AS_DL_INFO_TRANSFER_CNF (AS_DL_INFO_TRANSFER | AS_CONFIRM) +#define AS_DL_INFO_TRANSFER_IND (AS_DL_INFO_TRANSFER | AS_INDICATION) + +/* Radio Access Bearer establishment */ +#define AS_RAB_ESTABLISH 0x08 +#define AS_RAB_ESTABLISH_REQ (AS_RAB_ESTABLISH | AS_REQUEST) +#define AS_RAB_ESTABLISH_IND (AS_RAB_ESTABLISH | AS_INDICATION) +#define AS_RAB_ESTABLISH_RSP (AS_RAB_ESTABLISH | AS_RESPONSE) +#define AS_RAB_ESTABLISH_CNF (AS_RAB_ESTABLISH | AS_CONFIRM) + +/* Radio Access Bearer release */ +#define AS_RAB_RELEASE 0x09 +#define AS_RAB_RELEASE_REQ (AS_RAB_RELEASE | AS_REQUEST) +#define AS_RAB_RELEASE_IND (AS_RAB_RELEASE | AS_INDICATION) + +/* + * -------------------------------------------------------------------------- + * Access Stratum message global parameters + * -------------------------------------------------------------------------- + */ + +/* Error code */ +enum { + AS_SUCCESS = 1, /* Success code, transaction is going on */ + AS_TERMINATED_NAS, /* Transaction terminated by NAS */ + AS_TERMINATED_AS, /* Transaction terminated by AS */ + AS_FAILURE /* Failure code */ +}; + +/* Core network domain */ +enum { + AS_PS = 1, /* Packet-Switched */ + AS_CS /* Circuit-Switched */ +}; + +/* SAE Temporary Mobile Subscriber Identity */ +typedef struct { + UInt8_t MMEcode; /* MME code that allocated the GUTI */ + UInt32_t m_tmsi; /* M-Temporary Mobile Subscriber Identity */ +} as_stmsi_t; + +/* Dedicated NAS information */ +typedef struct { + UInt32_t length; /* Length of the NAS information data */ + Byte_t* data; /* Dedicated NAS information data container */ +} as_nas_info_t; + +/* Radio Access Bearer identity */ +typedef UInt8_t as_rab_id_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Broadcast information + * -------------------------------------------------------------------------- + */ + +/* + * AS->NAS - Broadcast information indication + * AS may asynchronously report to NAS available PLMNs within specific + * location area + */ +typedef struct { +#define PLMN_LIST_MAX_SIZE 6 + PLMN_LIST_T(PLMN_LIST_MAX_SIZE) plmnIDs; /* List of PLMN identifiers */ + ci_t cellID; /* Identity of the cell serving the listed PLMNs */ + tac_t tac; /* Code of the tracking area the cell belongs to */ +} broadcast_info_ind_t; + +/* + * -------------------------------------------------------------------------- + * Cell information relevant for cell selection processing + * -------------------------------------------------------------------------- + */ + +/* Radio access technologies supported by the network */ +#define AS_GSM (1 << NET_ACCESS_GSM) +#define AS_COMPACT (1 << NET_ACCESS_COMPACT) +#define AS_UTRAN (1 << NET_ACCESS_UTRAN) +#define AS_EGPRS (1 << NET_ACCESS_EGPRS) +#define AS_HSDPA (1 << NET_ACCESS_HSDPA) +#define AS_HSUPA (1 << NET_ACCESS_HSUPA) +#define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) +#define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) + +/* + * NAS->AS - Cell Information request + * NAS request AS to search for a suitable cell belonging to the selected + * PLMN to camp on. + */ +typedef struct { + plmn_t plmnID; /* Selected PLMN identity */ + Byte_t rat; /* Bitmap - set of radio access technologies */ +} cell_info_req_t; + +/* + * AS->NAS - Cell Information confirm + * AS search for a suitable cell and respond to NAS. If found, the cell + * is selected to camp on. + */ +typedef struct { + UInt8_t errCode; /* Error code */ + ci_t cellID; /* Identity of the cell serving the selected PLMN */ + tac_t tac; /* Code of the tracking area the cell belongs to */ + AcT_t rat; /* Radio access technology supported by the cell */ + UInt8_t rsrq; /* Reference signal received quality */ + UInt8_t rsrp; /* Reference signal received power */ +} cell_info_cnf_t; + +/* + * AS->NAS - Cell Information indication + * AS may change cell selection if a more suitable cell is found. + */ +typedef struct { + ci_t cellID; /* Identity of the new serving cell */ + tac_t tac; /* Code of the tracking area the cell belongs to */ +} cell_info_ind_t; + +/* + * -------------------------------------------------------------------------- + * Paging information + * -------------------------------------------------------------------------- + */ + +/* Paging cause */ +enum { + AS_CONNECTION_ESTABLISH, /* Establish NAS signalling connection */ + AS_EPS_ATTACH, /* Perform local detach and initiate EPS + * attach procedure */ + AS_CS_FALLBACK /* Inititate CS fallback procedure */ +}; + +/* + * NAS->AS - Paging Information request + * NAS requests the AS that NAS signalling messages or user data is pending + * to be sent. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t CN_domain; /* Core network domain */ +} paging_req_t; + +/* + * AS->NAS - Paging Information indication + * AS reports to the NAS that appropriate procedure has to be initiated. + */ +typedef struct { + UInt8_t cause; /* Paging cause */ +} paging_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection establishment + * -------------------------------------------------------------------------- + */ + +/* Cause of RRC connection establishment */ +#define AS_CAUSE_EMERGENCY (NET_ESTABLISH_CAUSE_EMERGENCY) +#define AS_CAUSE_HIGH_PRIO (NET_ESTABLISH_CAUSE_HIGH_PRIO) +#define AS_CAUSE_MT_ACCESS (NET_ESTABLISH_CAUSE_MT_ACCESS) +#define AS_CAUSE_MO_SIGNAL (NET_ESTABLISH_CAUSE_MO_SIGNAL) +#define AS_CAUSE_MO_DATA (NET_ESTABLISH_CAUSE_MO_DATA) +#define AS_CAUSE_V1020 (NET_ESTABLISH_CAUSE_V1020) + +/* Type of the call associated to the RRC connection establishment */ +#define AS_TYPE_ORIGINATING_SIGNAL (NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL) +#define AS_TYPE_EMERGENCY_CALLS (NET_ESTABLISH_TYPE_EMERGENCY_CALLS) +#define AS_TYPE_ORIGINATING_CALLS (NET_ESTABLISH_TYPE_ORIGINATING_CALLS) +#define AS_TYPE_TERMINATING_CALLS (NET_ESTABLISH_TYPE_TERMINATING_CALLS) +#define AS_TYPE_MO_CS_FALLBACK (NET_ESTABLISH_TYPE_MO_CS_FALLBACK) + + +/* + * NAS->AS - NAS signalling connection establishment request + * NAS requests the AS to perform the RRC connection establishment procedure + * to transfer initial NAS message to the network while UE is in IDLE mode. + */ +typedef struct { + UInt8_t cause; /* RRC connection establishment cause */ + UInt8_t type; /* RRC associated call type */ + as_stmsi_t s_tmsi; /* UE identity */ + plmn_t plmnID; /* Selected PLMN identity */ + as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */ +} nas_establish_req_t; + +/* + * AS->NAS - NAS signalling connection establishment indication + * AS transfers the initial NAS message to the NAS. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + tac_t tac; /* Code of the tracking area the initiating + * UE belongs to */ + as_nas_info_t initialNasMsg; /* Initial NAS message to transfer */ +} nas_establish_ind_t; + +/* + * NAS->AS - NAS signalling connection establishment response + * NAS responds to the AS that initial answer message has to be provided to + * the UE. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t errCode; /* Transaction status */ + as_nas_info_t nasMsg; /* NAS message to transfer */ +} nas_establish_rsp_t; + +/* + * AS->NAS - NAS signalling connection establishment confirm + * AS transfers the initial answer message to the NAS. + */ +typedef struct { + UInt8_t errCode; /* Transaction status */ + as_nas_info_t nasMsg; /* NAS message to transfer */ +} nas_establish_cnf_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection release + * -------------------------------------------------------------------------- + */ + +/* Release cause */ +enum { + AS_AUTHENTICATION_FAILURE = 1, /* Authentication procedure failed */ + AS_DETACH /* Detach requested */ +}; + +/* + * NAS->AS - NAS signalling connection release request + * NAS requests the termination of the connection with the UE. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + UInt8_t cause; /* Release cause */ +} nas_release_req_t; + +/* + * AS->NAS - NAS signalling connection release indication + * AS reports that connection has been terminated by the network. + */ +typedef struct { + UInt8_t cause; /* Release cause */ +} nas_release_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS information transfer + * -------------------------------------------------------------------------- + */ + +/* + * NAS->AS - Uplink data transfer request + * NAS requests the AS to transfer uplink information to the NAS that + * operates at the network side. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_stmsi_t s_tmsi; /* UE identity */ + as_nas_info_t nasMsg; /* Uplink NAS message */ +} ul_info_transfer_req_t; + +/* + * AS->NAS - Uplink data transfer confirm + * AS immediately notifies the NAS whether uplink information has been + * successfully sent to the network or not. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + UInt8_t errCode; /* Transaction status */ +} ul_info_transfer_cnf_t; + +/* + * AS->NAS - Uplink data transfer indication + * AS delivers the uplink information message to the NAS that operates + * at the network side. + */ +typedef struct { + UInt32_t UEid; /* UE lower layer identifier */ + as_nas_info_t nasMsg; /* Uplink NAS message */ +} ul_info_transfer_ind_t; + +/* + * NAS->AS - Downlink data transfer request + * NAS requests the AS to transfer downlink information to the NAS that + * operates at the UE side. + */ +typedef ul_info_transfer_req_t dl_info_transfer_req_t; + +/* + * AS->NAS - Downlink data transfer confirm + * AS immediately notifies the NAS whether downlink information has been + * successfully sent to the network or not. + */ +typedef ul_info_transfer_cnf_t dl_info_transfer_cnf_t; + +/* + * AS->NAS - Downlink data transfer indication + * AS delivers the downlink information message to the NAS that operates + * at the UE side. + */ +typedef ul_info_transfer_ind_t dl_info_transfer_ind_t; + +/* + * -------------------------------------------------------------------------- + * Radio Access Bearer establishment + * -------------------------------------------------------------------------- + */ + +/* TODO: Quality of Service parameters */ +typedef struct {} as_qos_t; + +/* + * NAS->AS - Radio access bearer establishment request + * NAS requests the AS to allocate transmission resources to radio access + * bearer initialized at the network side. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ + as_qos_t QoS; /* Requested Quality of Service */ +} rab_establish_req_t; + +/* + * AS->NAS - Radio access bearer establishment indication + * AS notifies the NAS that specific radio access bearer has to be setup. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_establish_ind_t; + +/* + * NAS->AS - Radio access bearer establishment response + * NAS responds to AS whether the specified radio access bearer has been + * successfully setup or not. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ + UInt8_t errCode; /* Transaction status */ +} rab_establish_rsp_t; + +/* + * AS->NAS - Radio access bearer establishment confirm + * AS notifies NAS whether the specified radio access bearer has been + * successfully setup at the UE side or not. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ + UInt8_t errCode; /* Transaction status */ +} rab_establish_cnf_t; + +/* + * -------------------------------------------------------------------------- + * Radio Access Bearer release + * -------------------------------------------------------------------------- + */ + +/* + * NAS->AS - Radio access bearer release request + * NAS requests the AS to release transmission resources previously allocated + * to specific radio access bearer at the network side. + */ +typedef struct { + as_stmsi_t s_tmsi; /* UE identity */ + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_release_req_t; + +/* + * AS->NAS - Radio access bearer release indication + * AS notifies NAS that specific radio access bearer has been released. + */ +typedef struct { + as_rab_id_t rabID; /* Radio access bearer identity */ +} rab_release_ind_t; + +/* + * -------------------------------------------------------------------------- + * Structure of the AS messages handled by the network sublayer + * -------------------------------------------------------------------------- + */ +typedef struct { + UInt16_t msgID; + union { + broadcast_info_ind_t broadcast_info_ind; + cell_info_req_t cell_info_req; + cell_info_cnf_t cell_info_cnf; + cell_info_ind_t cell_info_ind; + paging_req_t paging_req; + paging_ind_t paging_ind; + nas_establish_req_t nas_establish_req; + nas_establish_ind_t nas_establish_ind; + nas_establish_rsp_t nas_establish_rsp; + nas_establish_cnf_t nas_establish_cnf; + nas_release_req_t nas_release_req; + nas_release_ind_t nas_release_ind; + ul_info_transfer_req_t ul_info_transfer_req; + ul_info_transfer_cnf_t ul_info_transfer_cnf; + ul_info_transfer_ind_t ul_info_transfer_ind; + dl_info_transfer_req_t dl_info_transfer_req; + dl_info_transfer_cnf_t dl_info_transfer_cnf; + dl_info_transfer_ind_t dl_info_transfer_ind; + rab_establish_req_t rab_establish_req; + rab_establish_ind_t rab_establish_ind; + rab_establish_rsp_t rab_establish_rsp; + rab_establish_cnf_t rab_establish_cnf; + rab_release_req_t rab_release_req; + rab_release_ind_t rab_release_ind; + } __attribute__((__packed__)) msg; +} as_message_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int as_message_decode(const char* buffer, as_message_t* msg, int length); + +int as_message_encode(char* buffer, as_message_t* msg, int length); + +/* Implemented in the network_api.c body file */ +int as_message_send(as_message_t* as_msg); + +#endif /* __AS_MESSAGE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/l2_message.h b/openair-cn/NAS/EURECOM-NAS/src/api/network/l2_message.h new file mode 100644 index 0000000000..9904d9bad6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/l2_message.h @@ -0,0 +1,283 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_message.h + +Version 0.1 + +Date 2012/10/18 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the messages supported by the Access Stratum sublayer + protocol (usually RRC and S1AP for E-UTRAN) and functions used + to encode and decode + +*****************************************************************************/ +#ifndef __AS_MESSAGE_H__ +#define __AS_MESSAGE_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Access Stratum Message types */ +#define AS_REQUEST 0x0100 +#define AS_RESPONSE 0x0200 +#define AS_INDICATION 0x0400 +#define AS_CONFIRM 0x0800 + +/* + * Access Stratum Message identifiers + * ---------------------------------- + */ + +/* Cell information relevant for cell selection processing */ +#define AS_CELL_INFO 0x01 +#define AS_CELL_INFO_REQ (AS_CELL_INFO | AS_REQUEST) +#define AS_CELL_INFO_RSP (AS_CELL_INFO | AS_RESPONSE) +#define AS_CELL_INFO_IND (AS_CELL_INFO | AS_INDICATION) + +/* Security mode control */ +#define AS_SECURITY 0x02 +#define AS_SECURITY_REQ (AS_SECURITY | AS_REQUEST) +#define AS_SECURITY_RSP (AS_SECURITY | AS_RESPONSE) + +/* Paging information */ +#define AS_PAGING 0x03 +#define AS_PAGING_IND (AS_PAGING | AS_INDICATION) + +/* NAS signalling connection establishment */ +#define AS_NAS_ESTABLISH 0x04 +#define AS_NAS_ESTABLISH_REQ (AS_NAS_ESTABLISH | AS_REQUEST) +#define AS_NAS_ESTABLISH_RSP (AS_NAS_ESTABLISH | AS_RESPONSE) + +/* NAS signalling connection release */ +#define AS_NAS_RELEASE 0x05 +#define AS_NAS_RELEASE_REQ (AS_NAS_RELEASE | AS_REQUEST) +#define AS_NAS_RELEASE_IND (AS_NAS_RELEASE | AS_INDICATION) + +/* NAS information transfer */ +#define AS_INFO_TRANSFER 0x10 +#define AS_UL_INFO_TRANSFER (AS_INFO_TRANSFER | AS_REQUEST) +#define AS_DL_INFO_TRANSFER (AS_INFO_TRANSFER | AS_INDICATION) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Available PLMNs and cell Information + * -------------------------------------------------------------------------- + */ + +/* Radio access technologies supported by the network */ +#define AS_GSM (1 << NET_ACCESS_GSM) +#define AS_COMPACT (1 << NET_ACCESS_COMPACT) +#define AS_UTRAN (1 << NET_ACCESS_UTRAN) +#define AS_EGPRS (1 << NET_ACCESS_EGPRS) +#define AS_HSDPA (1 << NET_ACCESS_HSDPA) +#define AS_HSUPA (1 << NET_ACCESS_HSUPA) +#define AS_HSDUPA (1 << NET_ACCESS_HSDUPA) +#define AS_EUTRAN (1 << NET_ACCESS_EUTRAN) + +/* + * NAS->AS - Cell Information request + * NAS request AS to search for a suitable cell belonging to the selected + * PLMN to camp on. + */ +typedef struct { + plmn_t plmnID; /* PLMN identifier */ + Byte_t rat; /* Bitmap - set of radio access technologies */ +} cell_info_req_t; + +/* + * AS->NAS - Cell Information response + * AS search for a suitable cell and respond to NAS. If found, the cell + * is selected to camp on. + */ +typedef struct { + plmn_t plmnID; /* PLMN identifier */ + TAC_t tac; /* identifies a tracking area the PLMN belongs to */ + CI_t cellID; /* identifies a cell within a PLMN */ + AcT_t rat; /* radio access technology supported by the cell */ +} cell_info_rsp_t; + +/* + * AS->NAS - Cell Information indication + * AS Reports available PLMNs with associated Radio Access Technologies + * to NAS on request from NAS or autonomously. + */ +typedef struct { +#define PLMN_LIST_MAX_SIZE 6 + PLMN_LIST_T(PLMN_LIST_MAX_SIZE) plmnIDs; /* List of PLMN identifiers */ + Byte_t rat[PLMN_LIST_MAX_SIZE]; /* Radio access technologies */ + TAC_t tac; /* identifies a tracking area within a scope of PLMNs */ + CI_t cellID; /* identifies a cell within a PLMN */ +} cell_info_ind_t; + +/* + * -------------------------------------------------------------------------- + * Security mode control + * -------------------------------------------------------------------------- + */ + +/* + * TODO: NAS->AS - Security command request + */ +typedef struct {} security_req_t; + + +/* + * TODO: AS->NAS - Security command response + */ +typedef struct {} security_rsp_t; + + +/* + * -------------------------------------------------------------------------- + * Paging information + * -------------------------------------------------------------------------- + */ + +/* + * TODO: AS->NAS - Paging Information indication + */ +typedef struct {} paging_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection establishment + * -------------------------------------------------------------------------- + */ + +/* Cause of RRC connection establishment */ +#define AS_CAUSE_EMERGENCY (NET_ESTABLISH_CAUSE_EMERGENCY) +#define AS_CAUSE_HIGH_PRIO (NET_ESTABLISH_CAUSE_HIGH_PRIO) +#define AS_CAUSE_MT_ACCESS (NET_ESTABLISH_CAUSE_MT_ACCESS) +#define AS_CAUSE_MO_SIGNAL (NET_ESTABLISH_CAUSE_MO_SIGNAL) +#define AS_CAUSE_MO_DATA (NET_ESTABLISH_CAUSE_MO_DATA) +#define AS_CAUSE_V1020 (NET_ESTABLISH_CAUSE_V1020) + +/* Type of the call associated to the RRC connection establishment */ +#define AS_TYPE_ORIGINATING_SIGNAL (NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL) +#define AS_TYPE_EMERGENCY_CALLS (NET_ESTABLISH_TYPE_EMERGENCY_CALLS) +#define AS_TYPE_ORIGINATING_CALLS (NET_ESTABLISH_TYPE_ORIGINATING_CALLS) +#define AS_TYPE_TERMINATING_CALLS (NET_ESTABLISH_TYPE_TERMINATING_CALLS) +#define AS_TYPE_MO_CS_FALLBACK (NET_ESTABLISH_TYPE_MO_CS_FALLBACK) + + +/* Structure of the SAE Temporary Mobile Subscriber Identity */ +typedef struct { + UInt8_t MMEcode; /* MME code that allocated the GUTI */ + UInt32_t m_tmsi; /* M-Temporary Mobile Subscriber Identity */ +} as_stmsi_t; + +/* Structure of the dedicated NAS information */ +typedef struct { + UInt32_t length; /* Length of the NAS information data */ + Byte_t* data; /* Dedicated NAS information data container */ +} as_nas_info_t; + +/* + * NAS->AS - NAS signalling connection establishment request + * NAS request AS to perform the RRC connection establishment procedure + * to transfer initial NAS message to the network while UE is in IDLE mode. + */ +typedef struct { + UInt8_t cause; /* Connection establishment cause */ + UInt8_t type; /* Associated call type */ + plmn_t plmnID; /* Identifier of the selected PLMN */ + as_stmsi_t s_tmsi; /* SAE Temporary Mobile Subscriber Identity */ + as_nas_info_t initialNasMsg;/* Initial NAS message to transfer */ +} nas_establish_req_t; + +/* + * TODO: AS->NAS - NAS signalling connection establishment response + */ +typedef struct {} nas_establish_rsp_t; + +/* + * -------------------------------------------------------------------------- + * NAS signalling connection release + * -------------------------------------------------------------------------- + */ + +/* + * TODO: NAS->AS - NAS signalling connection release request + */ +typedef struct {} nas_release_req_t; + +/* + * TODO: AS->NAS - NAS signalling connection release indication + */ +typedef struct {} nas_release_ind_t; + +/* + * -------------------------------------------------------------------------- + * NAS information transfer + * -------------------------------------------------------------------------- + */ + +/* + * AS->NAS - Downlink data transfer + * AS notifies upper layer that NAS or non-3GPP dedicated downlink information + * has to be transfered to NAS. +*/ +typedef as_nas_info_t dl_info_transfer_t; + +/* + * NAS->AS - Uplink data transfer request + * NAS requests under layer to transfer NAS or non-3GPP dedicated uplink + * information to AS. + */ +typedef as_nas_info_t ul_info_transfer_t; + +/* + * -------------------------------------------------------------------------- + * Structure of the AS messages handled by the network sublayer + * -------------------------------------------------------------------------- + */ +typedef struct { + UInt16_t msgID; + union { + cell_info_req_t cell_info_req; + cell_info_rsp_t cell_info_rsp; + cell_info_ind_t cell_info_ind; + security_req_t security_req; + security_rsp_t security_rsp; + paging_ind_t paging_ind; + nas_establish_req_t nas_establish_req; + nas_establish_rsp_t nas_establish_rsp; + nas_release_req_t nas_release_req; + nas_release_ind_t nas_release_ind; + ul_info_transfer_t ul_info_transfer; + dl_info_transfer_t dl_info_transfer; + } __attribute__((__packed__)) msg; +} as_message_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int as_message_decode(const char* buffer, int length, as_message_t* msg); + +int as_message_encode(char* buffer, int length, const as_message_t* msg); + +/* Implemented in the network_api.c body file */ +int as_message_send(as_message_t* as_msg, const void* nas_msg); + +#endif /* __AS_MESSAGE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.c b/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.c new file mode 100644 index 0000000000..b8b214b6b4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.c @@ -0,0 +1,725 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_message.h + +Version 0.1 + +Date 2012/26/09 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the layer 3 messages supported by the NAS sublayer + protocol and functions used to encode and decode + +*****************************************************************************/ + +#include "nas_message.h" +#include "nas_log.h" + +#include "TLVDecoder.h" +#include "TLVEncoder.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Functions used to decode layer 3 NAS messages */ +static int _nas_message_header_decode(const char* buffer, + nas_message_security_header_t* header, int length); +static int _nas_message_plain_decode(const char* buffer, + const nas_message_security_header_t* header, + nas_message_plain_t* msg, int length); +static int _nas_message_protected_decode(const char* buffer, + nas_message_security_header_t* header, + nas_message_plain_t* msg, int length); + +/* Functions used to encode layer 3 NAS messages */ +static int _nas_message_header_encode(char* buffer, + const nas_message_security_header_t* header, int length); +static int _nas_message_plain_encode(char* buffer, + const nas_message_security_header_t* header, + const nas_message_plain_t* msg, int length); +static int _nas_message_protected_encode(char* buffer, + const nas_message_security_protected_t* msg, int length); + +/* Functions used to decrypt and encrypt layer 3 NAS messages */ +static int _nas_message_decrypt(char* dest, const char* src, UInt8_t type, + UInt32_t code, UInt8_t seq, int length); +static int _nas_message_encrypt(char* dest, const char* src, UInt8_t type, + UInt32_t code, UInt8_t seq, int length); + +/* Functions used for integrity protection of layer 3 NAS messages */ +static UInt32_t _nas_message_get_mac(const char* buffer, UInt32_t count, + int length); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: nas_message_encrypt() ** + ** ** + ** Description: Encripts plain NAS message into security protected NAS ** + ** message ** + ** ** + ** Inputs: inbuf: Input buffer containing plain NAS message ** + ** header: Security protected header to be applied ** + ** length: Number of bytes that should be encrypted ** + ** Others: None ** + ** ** + ** Outputs: outbuf: Output buffer containing security protec- ** + ** ted message ** + ** Return: The number of bytes in the output buffer ** + ** if the input buffer has been successfully ** + ** encrypted; Negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_message_encrypt(const char* inbuf, char* outbuf, + const nas_message_security_header_t* header, int length) +{ + LOG_FUNC_IN; + + int bytes = length; + + /* Encode the header */ + int size = _nas_message_header_encode(outbuf, header, length); + + if (size < 0) { + LOG_FUNC_RETURN (TLV_ENCODE_BUFFER_TOO_SHORT); + } + else if (size > 1) { + /* Encrypt the plain NAS message */ + bytes = _nas_message_encrypt(outbuf + size, inbuf, + header->security_header_type, + header->message_authentication_code, + header->sequence_number, + length - size); + /* Integrity protected the NAS message */ + if (bytes > 0) { + /* Compute offset of the sequence number field */ + int offset = size - sizeof(UInt8_t); + /* Compute the NAS message authentication code */ + UInt32_t mac = _nas_message_get_mac(outbuf + offset, + 0, // TODO !!! ul counter + length - offset); + /* Set the message authentication code of the NAS message */ + *(UInt32_t*)(outbuf + sizeof(UInt8_t)) = mac; + } + } + else { + /* The input buffer does not need to be encrypted */ + memcpy(outbuf, inbuf, length); + } + + if (bytes < 0) { + LOG_FUNC_RETURN (bytes); + } + if (size > 1) { + LOG_FUNC_RETURN (size + bytes); + } + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: nas_message_decrypt() ** + ** ** + ** Description: Decripts security protected NAS message into plain NAS ** + ** message ** + ** ** + ** Inputs: inbuf: Input buffer containing security protected ** + ** NAS message ** + ** length: Number of bytes that should be decrypted ** + ** Others: None ** + ** ** + ** Outputs: outbuf: Output buffer containing plain NAS message ** + ** header: Security protected header applied ** + ** Return: The number of bytes in the output buffer ** + ** if the input buffer has been successfully ** + ** decrypted; Negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_message_decrypt(const char* inbuf, char* outbuf, + nas_message_security_header_t* header, int length) +{ + LOG_FUNC_IN; + + int bytes = length; + + /* Decode the header */ + int size = _nas_message_header_decode(inbuf, header, length); + + if (size < 0) { + LOG_FUNC_RETURN (TLV_DECODE_BUFFER_TOO_SHORT); + } + else if (size > 1) { + /* Compute offset of the sequence number field */ + int offset = size - sizeof(UInt8_t); + /* Compute the NAS message authentication code */ + UInt32_t mac = _nas_message_get_mac(inbuf + offset, + 0, // TODO !!! dl counter + length - offset); + /* Check NAS message integrity */ + if (mac != header->message_authentication_code) { + LOG_FUNC_RETURN (TLV_DECODE_MAC_MISMATCH); + } + + /* Decrypt the security protected NAS message */ + header->protocol_discriminator = + _nas_message_decrypt(outbuf, inbuf + size, + header->security_header_type, + header->message_authentication_code, + header->sequence_number, + length - size); + bytes = length - size; + } + else { + /* The input buffer contains a plain NAS message */ + memcpy(outbuf, inbuf, length); + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: nas_message_decode() ** + ** ** + ** Description: Decode layer 3 NAS message ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing layer 3 ** + ** NAS message data ** + ** length: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: L3 NAS message structure to be filled ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_message_decode(const char* buffer, nas_message_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes; + + /* Decode the header */ + int size = _nas_message_header_decode(buffer, &msg->header, length); + + if (size < 0) { + LOG_FUNC_RETURN (TLV_DECODE_BUFFER_TOO_SHORT); + } + else if (size > 1) { + /* Compute offset of the sequence number field */ + int offset = size - sizeof(UInt8_t); + /* Compute the NAS message authentication code */ + UInt32_t mac = _nas_message_get_mac(buffer + offset, + 0, // TODO !!! dl counter + length - offset); + /* Check NAS message integrity */ + if (mac != msg->header.message_authentication_code) { + LOG_FUNC_RETURN (TLV_DECODE_MAC_MISMATCH); + } + + /* Decode security protected NAS message */ + bytes = _nas_message_protected_decode(buffer + size, &msg->header, + &msg->plain, length - size); + } + else { + /* Decode plain NAS message */ + bytes = _nas_message_plain_decode(buffer, &msg->header, + &msg->plain, length); + } + + if (bytes < 0) { + LOG_FUNC_RETURN (bytes); + } + if (size > 1) { + LOG_FUNC_RETURN (size + bytes); + } + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: nas_message_encode() ** + ** ** + ** Description: Encode layer 3 NAS message ** + ** ** + ** Inputs msg: L3 NAS message structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_message_encode(char* buffer, const nas_message_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes; + + /* Encode the header */ + int size = _nas_message_header_encode(buffer, &msg->header, length); + + if (size < 0) { + LOG_FUNC_RETURN (TLV_ENCODE_BUFFER_TOO_SHORT); + } + else if (size > 1) { + /* Encode security protected NAS message */ + bytes = _nas_message_protected_encode(buffer + size, &msg->protected, + length - size); + /* Integrity protect the NAS message */ + if (bytes > 0) { + /* Compute offset of the sequence number field */ + int offset = size - sizeof(UInt8_t); + /* Compute the NAS message authentication code */ + UInt32_t mac = _nas_message_get_mac(buffer + offset, + 0, // TODO !!! ul counter + length - offset); + /* Set the message authentication code of the NAS message */ + *(UInt32_t*)(buffer + sizeof(UInt8_t)) = mac; + } + } + else { + /* Encode plain NAS message */ + bytes = _nas_message_plain_encode(buffer, &msg->header, + &msg->plain, length); + } + + if (bytes < 0) { + LOG_FUNC_RETURN (bytes); + } + if (size > 1) { + LOG_FUNC_RETURN (size + bytes); + } + LOG_FUNC_RETURN (bytes); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Functions used to decode layer 3 NAS messages + * ----------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _nas_message_header_decode() ** + ** ** + ** Description: Decode header of a security protected NAS message ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing layer 3 ** + ** message data ** + ** length: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: header: Security header structure to be filled ** + ** Return: The size in bytes of the security header ** + ** if data have been successfully decoded; ** + ** 1, if the header is not a security header ** + ** (header of plain NAS message); ** + ** -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_header_decode(const char* buffer, + nas_message_security_header_t* header, + int length) +{ + LOG_FUNC_IN; + + int size = 0; + + /* Decode the first octet of the header (security header type or EPS bearer + * identity, and protocol discriminator) */ + DECODE_U8(buffer, *(UInt8_t*)(header), size); + + if (header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) + { + if (length < NAS_MESSAGE_SECURITY_HEADER_SIZE) { + /* The buffer is not big enough to contain security header */ + LOG_TRACE(WARNING, "NET-API - The size of the header (%u) " + "exceeds the buffer length (%u)", + NAS_MESSAGE_SECURITY_HEADER_SIZE, length); + LOG_FUNC_RETURN (-1); + } + /* Decode the message authentication code */ + DECODE_U32(buffer+size, header->message_authentication_code, size); + /* Decode the sequence number */ + DECODE_U8(buffer+size, header->sequence_number, size); + } + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: _nas_message_plain_decode() ** + ** ** + ** Description: Decode plain NAS message ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing plain NAS ** + ** message data ** + ** header: Header of the plain NAS message ** + ** length: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: Decoded NAS message ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_plain_decode(const char* buffer, + const nas_message_security_header_t* header, + nas_message_plain_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = TLV_DECODE_PROTOCOL_NOT_SUPPORTED; + + if (header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + /* Decode EPS Mobility Management L3 message */ + bytes = emm_msg_decode(&msg->emm, (uint8_t *)buffer, length); + } + else if (header->protocol_discriminator == EPS_SESSION_MANAGEMENT_MESSAGE) { + /* Decode EPS Session Management L3 message */ + bytes = esm_msg_decode(&msg->esm, (uint8_t *)buffer, length); + } + else { + /* Discard L3 messages with not supported protocol discriminator */ + LOG_TRACE(WARNING,"NET-API - Protocol discriminator 0x%x is " + "not supported", header->protocol_discriminator); + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _nas_message_protected_decode() ** + ** ** + ** Description: Decode security protected NAS message ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the secu- ** + ** rity protected NAS message data ** + ** header: Header of the security protected NAS mes- ** + ** sage ** + ** length: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: Decoded NAS message ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_protected_decode(const char* buffer, + nas_message_security_header_t* header, + nas_message_plain_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = TLV_DECODE_BUFFER_TOO_SHORT; + + char* plain_msg = (char*)malloc(length); + if (plain_msg) + { + /* Decrypt the security protected NAS message */ + header->protocol_discriminator = + _nas_message_decrypt(plain_msg, buffer, + header->security_header_type, + header->message_authentication_code, + header->sequence_number, length); + /* Decode the decrypted message as plain NAS message */ + bytes = _nas_message_plain_decode(plain_msg, header, msg, length); + free(plain_msg); + } + + LOG_FUNC_RETURN (bytes); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to encode layer 3 NAS messages + * ----------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _nas_message_header_encode() ** + ** ** + ** Description: Encode header of a security protected NAS message ** + ** ** + ** Inputs header: Security header structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully encoded; ** + ** 1, if the header is not a security header ** + ** (header of plain NAS message); ** + ** -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_header_encode(char* buffer, + const nas_message_security_header_t* header, int length) +{ + LOG_FUNC_IN; + + int size = 0; + + /* Encode the first octet of the header (security header type or EPS bearer + * identity, and protocol discriminator) */ + ENCODE_U8(buffer, *(UInt8_t*)(header), size); + + if (header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) + { + if (length < NAS_MESSAGE_SECURITY_HEADER_SIZE) { + /* The buffer is not big enough to contain security header */ + LOG_TRACE(WARNING, "NET-API - The size of the header (%u) " + "exceeds the buffer length (%u)", + NAS_MESSAGE_SECURITY_HEADER_SIZE, length); + LOG_FUNC_RETURN (-1); + } + /* Encode the message authentication code */ + ENCODE_U32(buffer+size, header->message_authentication_code, size); + /* Encode the sequence number */ + ENCODE_U8(buffer+size, header->sequence_number, size); + } + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: _nas_message_plain_encode() ** + ** ** + ** Description: Encode plain NAS message ** + ** ** + ** Inputs: pd: Protocol discriminator of the NAS message ** + ** to encode ** + ** msg: Plain NAS message structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_plain_encode(char* buffer, + const nas_message_security_header_t* header, + const nas_message_plain_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = TLV_ENCODE_PROTOCOL_NOT_SUPPORTED; + + if (header->protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + /* Encode EPS Mobility Management L3 message */ + bytes = emm_msg_encode((EMM_msg*)(&msg->emm), (uint8_t*)buffer, length); + } + else if (header->protocol_discriminator == EPS_SESSION_MANAGEMENT_MESSAGE) { + /* Encode EPS Session Management L3 message */ + bytes = esm_msg_encode((ESM_msg*)(&msg->esm), (uint8_t*)buffer, length); + } + else { + /* Discard L3 messages with not supported protocol discriminator */ + LOG_TRACE(WARNING,"NET-API - Protocol discriminator 0x%x is " + "not supported", header->protocol_discriminator); + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _nas_message_protected_encode() ** + ** ** + ** Description: Encode security protected NAS message ** + ** ** + ** Inputs msg: Security protected NAS message structure ** + ** to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if the ** + ** data have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_protected_encode(char* buffer, + const nas_message_security_protected_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = TLV_ENCODE_BUFFER_TOO_SHORT; + + char* plain_msg = (char*)malloc(length); + if (plain_msg) { + /* Encode the security protected NAS message as plain NAS message */ + int size = _nas_message_plain_encode(plain_msg, &msg->header, + &msg->plain, length); + if (size > 0) { + /* Encrypt the encoded plain NAS message */ + bytes = _nas_message_encrypt(buffer, plain_msg, + msg->header.security_header_type, + msg->header.message_authentication_code, + msg->header.sequence_number, size); + } + free(plain_msg); + } + + LOG_FUNC_RETURN (bytes); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to decrypt and encrypt layer 3 NAS messages + * ----------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _nas_message_decrypt() ** + ** ** + ** Description: Decrypt security protected NAS message ** + ** ** + ** Inputs src: Pointer to the encrypted data buffer ** + ** type: The security header type ** + ** code: The message authentication code ** + ** seq: The sequence number ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: dest: Pointer to the decrypted data buffer ** + ** Return: The protocol discriminator of the message ** + ** that has been decrypted; ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_decrypt(char* dest, const char* src, UInt8_t type, + UInt32_t code, UInt8_t seq, int length) +{ + LOG_FUNC_IN; + + int size = 0; + nas_message_security_header_t header; + + /* TODO: run the uncyphering algorithm */ + memcpy(dest, src, length); + + /* Decode the first octet (security header type or EPS bearer identity, + * and protocol discriminator) */ + DECODE_U8(src, *(UInt8_t*)(&header), size); + + LOG_FUNC_RETURN (header.protocol_discriminator); +} + +/**************************************************************************** + ** ** + ** Name: _nas_message_encrypt() ** + ** ** + ** Description: Encrypt plain NAS message ** + ** ** + ** Inputs src: Pointer to the decrypted data buffer ** + ** type: The security header type ** + ** code: The message authentication code ** + ** seq: The sequence number ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: dest: Pointer to the encrypted data buffer ** + ** Return: The number of bytes in the output buffer ** + ** if data have been successfully encrypted; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_message_encrypt(char* dest, const char* src, UInt8_t type, + UInt32_t code, UInt8_t seq, int length) +{ + LOG_FUNC_IN; + + int size = length; + + /* TODO: run the cyphering algorithm */ + memcpy(dest, src, length); + + LOG_FUNC_RETURN (size); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used for integrity protection of layer 3 NAS messages + * ----------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _nas_message_get_mac() ** + ** ** + ** Description: Run integrity algorithm onto cyphered or uncyphered NAS ** + ** message encoded in the input buffer and return the compu- ** + ** ted message authentication code ** + ** ** + ** Inputs buffer: Pointer to the integrity protected data ** + ** buffer ** + ** count: Value of the uplink NAS counter ** + ** length: Length of the input buffer ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The message authentication code ** + ** Others: None ** + ** ** + ***************************************************************************/ +static UInt32_t _nas_message_get_mac(const char* buffer, UInt32_t count, + int length) +{ + LOG_FUNC_IN; + /* TODO: run integrity protection algorithm */ + /* TODO: Return the message authentication code */ + LOG_FUNC_RETURN (0xabababab); +} + + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.h b/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.h new file mode 100644 index 0000000000..992dd88e3b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/nas_message.h @@ -0,0 +1,89 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_message.h + +Version 0.1 + +Date 2012/26/09 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the layer 3 messages supported by the NAS sublayer + protocol and functions used to encode and decode + +*****************************************************************************/ +#ifndef __NAS_MESSAGE_H__ +#define __NAS_MESSAGE_H__ + +#include "commonDef.h" +#include "emm_msg.h" +#include "esm_msg.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#define NAS_MESSAGE_SECURITY_HEADER_SIZE 6 + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* Structure of security protected header */ +typedef struct { +#ifdef __LITTLE_ENDIAN_BITFIELD + UInt8_t protocol_discriminator:4; + UInt8_t security_header_type:4; +#endif +#ifdef __BIG_ENDIAN_BITFIELD + UInt8_t security_header_type:4; + UInt8_t protocol_discriminator:4; +#endif + UInt32_t message_authentication_code; + UInt8_t sequence_number; +} nas_message_security_header_t; + +/* Structure of plain NAS message */ +typedef union { + EMM_msg emm; /* EPS Mobility Management messages */ + ESM_msg esm; /* EPS Session Management messages */ +} nas_message_plain_t; + +/* Structure of security protected NAS message */ +typedef struct { + nas_message_security_header_t header; + nas_message_plain_t plain; +} nas_message_security_protected_t; + +/* + * Structure of a layer 3 NAS message + */ +typedef union { + nas_message_security_header_t header; + nas_message_security_protected_t protected; + nas_message_plain_t plain; +} nas_message_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int nas_message_encrypt(const char* inbuf, char* outbuf, const nas_message_security_header_t* header, int length); + +int nas_message_decrypt(const char* inbuf, char* outbuf, nas_message_security_header_t* header, int length); + +int nas_message_decode(const char* buffer, nas_message_t* msg, int length); + +int nas_message_encode(char* buffer, const nas_message_t* msg, int length); + +#endif /* __NAS_MESSAGE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.c b/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.c new file mode 100644 index 0000000000..f7c94b673d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.c @@ -0,0 +1,416 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network_api.c + +Version 0.1 + +Date 2012/03/01 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer to send/receive + message to/from the network sublayer + +*****************************************************************************/ + +#include "network_api.h" +#include "commonDef.h" +#include "nas_log.h" +#include "socket.h" + +#include "as_message.h" + +#include <string.h> // strerror, memset +#include <netdb.h> // gai_strerror +#include <errno.h> // errno +#include <unistd.h> // gethostname + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* ------------------- + * Connection endpoint + * ------------------- + * The connection endpoint is used to send/receive data to/from the + * network sublayer. Its definition depends on the underlaying mechanism + * chosen to communicate (network socket, I/O terminal device, async FIFO). + * A connection endpoint is handled using an identifier, and functions + * used to retreive the file descriptor actually allocated by the system, + * to receive data, to send data, and to perform clean up when connection + * is shut down. + * Only one single end to end connection with the network sublayer is + * managed at a time. + */ +static struct { + /* Connection endpoint reference */ + void* endpoint; + /* Connection endpoint handlers */ + void* (*open) (int, const char*, const char*); + int (*getfd)(const void*); + ssize_t (*recv) (void*, char*, size_t); + ssize_t (*send) (const void*, const char*, size_t); + void (*close)(void*); +} _network_api_id; + +#define NETWORK_API_OPEN(a, b, c) _network_api_id.open(a, b, c) +#define NETWORK_API_GETFD() _network_api_id.getfd(_network_api_id.endpoint) +#define NETWORK_API_RECV(a, b) _network_api_id.recv(_network_api_id.endpoint, a, b) +#define NETWORK_API_SEND(a, b) _network_api_id.send(_network_api_id.endpoint, a, b) +#define NETWORK_API_CLOSE() _network_api_id.close(_network_api_id.endpoint) + +/* + * The buffer used to receive data from the network sublayer + */ +#define NETWORK_API_RECV_BUFFER_SIZE 4096 +static char _network_api_recv_buffer[NETWORK_API_RECV_BUFFER_SIZE]; + +/* + * The buffer used to send data to the network sublayer + */ +#define NETWORK_API_SEND_BUFFER_SIZE NETWORK_API_RECV_BUFFER_SIZE +static char _network_api_send_buffer[NETWORK_API_SEND_BUFFER_SIZE]; + +/* + * The decoded data received from the network sublayer + */ +static as_message_t _as_data = {}; /* Access Stratum message */ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: network_api_initialize() ** + ** ** + ** Description: Initializes the network API from which the NAS layer ** + ** will send/receive messages to/from the network sublayer ** + ** ** + ** Inputs: host: The name of the host from which the net- ** + ** work sublayer will connect ** + ** port: The local port number ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: _network_api_id ** + ** ** + ***************************************************************************/ +int network_api_initialize(const char* host, const char* port) +{ + LOG_FUNC_IN; + + /* Initialize network socket handlers */ + _network_api_id.open = socket_udp_open; + _network_api_id.getfd = socket_get_fd; + _network_api_id.recv = socket_recv; + _network_api_id.send = socket_send; + _network_api_id.close = socket_close; + /* Initialize UDP communication channel with the network layer */ +#ifdef NAS_UE + _network_api_id.endpoint = NETWORK_API_OPEN(SOCKET_CLIENT, host, port); +#endif +#ifdef NAS_MME + _network_api_id.endpoint = NETWORK_API_OPEN(SOCKET_SERVER, NULL, port); +#endif + if (_network_api_id.endpoint == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + LOG_TRACE(ERROR, "NET-API - Failed to open connection endpoint, %s", + error); + LOG_FUNC_RETURN (RETURNerror); + } + + gethostname(_network_api_send_buffer, NETWORK_API_SEND_BUFFER_SIZE); + LOG_TRACE(INFO, "NET-API - Network's UDP socket %d is BOUND to %s/%s", + network_api_get_fd(), _network_api_send_buffer, port); + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: network_api_get_fd() ** + ** ** + ** Description: Get the file descriptor of the connection endpoint used ** + ** to send/receive messages to/from the network sublayer ** + ** ** + ** Inputs: None ** + ** Others: _network_api_id ** + ** ** + ** Outputs: Return: The file descriptor of the connection end- ** + ** point used by the network sublayer ** + ** Others: None ** + ** ** + ***************************************************************************/ +int network_api_get_fd(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (NETWORK_API_GETFD()); +} + +/**************************************************************************** + ** ** + ** Name: network_api_get_data() ** + ** ** + ** Description: Get a generic pointer to the network data structure. ** + ** Casting to the proper type is necessary before its usage. ** + ** ** + ** Inputs: None ** + ** Others: _as_data ** + ** ** + ** Outputs: Return: A generic pointer to the network data ** + ** structure ** + ** Others: None ** + ** ** + ***************************************************************************/ +const void* network_api_get_data(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN ((void*)(&_as_data)); +} + +/**************************************************************************** + ** ** + ** Name: network_api_read_data() ** + ** ** + ** Description: Read data received from the network sublayer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** from which data have been received ** + ** Others: _network_api_id ** + ** ** + ** Outputs: Return: The number of bytes read when success; ** + ** RETURNerror otherwise ** + ** Others: _network_api_recv_buffer, _network_api_id ** + ** ** + ***************************************************************************/ +int network_api_read_data(int fd) +{ + LOG_FUNC_IN; + + int rbytes; + + /* Sanity check */ + int sfd = network_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "NET-API - Endpoint %d is not the one created for communication with the network sublayer (%d)", fd, sfd); + LOG_FUNC_RETURN (RETURNerror); + } + + memset(_network_api_recv_buffer, 0, NETWORK_API_RECV_BUFFER_SIZE); + + /* Receive data from the network sublayer */ + rbytes = NETWORK_API_RECV(_network_api_recv_buffer, + NETWORK_API_RECV_BUFFER_SIZE); + if (rbytes == RETURNerror) { + LOG_TRACE(ERROR, "NET-API - recv() failed, %s", strerror(errno)); + LOG_FUNC_RETURN (RETURNerror); + } + else if (rbytes == 0) { + LOG_TRACE(WARNING, "NET-API - A signal was caught"); + } + else { + LOG_TRACE(INFO, "NET-API - %d bytes received from the network " + "sublayer", rbytes); + LOG_DUMP(_network_api_recv_buffer, rbytes); + } + + LOG_FUNC_RETURN (rbytes); +} + +/**************************************************************************** + ** ** + ** Name: network_api_send_data() ** + ** ** + ** Description: Send data to the network sublayer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** to which data have to be sent ** + ** length: Number of bytes to send ** + ** Others: _network_api_send_buffer, _network_api_id ** + ** ** + ** Outputs: Return: The number of bytes sent when success; ** + ** RETURNerror otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +int network_api_send_data(int fd, int length) +{ + LOG_FUNC_IN; + + int sbytes; + + /* Sanity check */ + int sfd = network_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "NET-API - Endpoint %d is not the one created for communication with the network sublayer (%d)", fd, sfd); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Send data to the network sublayer */ + sbytes = NETWORK_API_SEND(_network_api_send_buffer, length); + if (sbytes == RETURNerror) { + LOG_TRACE(ERROR, "NET-API - send() failed, %s", strerror(errno)); + LOG_FUNC_RETURN (RETURNerror); + } + else if (sbytes == 0) { + LOG_TRACE(WARNING, "NET-API - A signal was caught"); + } + else { + LOG_TRACE(INFO, "NET-API - %d bytes sent to the network sublayer", + sbytes); + LOG_DUMP(_network_api_send_buffer, sbytes); + } + + LOG_FUNC_RETURN (sbytes); +} + +/**************************************************************************** + ** ** + ** Name: network_api_close() ** + ** ** + ** Description: Clean the network API from which the NAS layer sent/recei-** + ** ved messages to/from the network sublayer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** allocated by the system to communicate ** + ** with the network sublayer ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: _network_api_id ** + ** ** + ***************************************************************************/ +void network_api_close(int fd) +{ + LOG_FUNC_IN; + + /* Sanity check */ + int sfd = network_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "NET-API - Endpoint %d is not the one created for communication with the network sublayer (%d)", fd, sfd); + LOG_FUNC_OUT; + return; + } + + /* Cleanup the connection endpoint */ + NETWORK_API_CLOSE(); + _network_api_id.endpoint = NULL; + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: network_api_decode_data() ** + ** ** + ** Description: Decodes the message received from the network and fills ** + ** the corresponding network data structure. ** + ** ** + ** Inputs: length: Number of bytes to decode ** + ** Others: _network_api_recv_buffer ** + ** ** + ** Outputs: Return: The identifier of the received AS ** + ** message when successfully decoded; ** + ** RETURNerror otherwise ** + ** Others: _as_data ** + ** ** + ***************************************************************************/ +int network_api_decode_data(int length) +{ + LOG_FUNC_IN; + + /* Decode the Access Stratum message received from the network */ + int as_id = as_message_decode(_network_api_recv_buffer, &_as_data, length); + + if (as_id != RETURNerror) { + LOG_TRACE(INFO, "NET-API - AS message id=0x%x successfully decoded", + as_id); + } + LOG_FUNC_RETURN (as_id); +} + +/**************************************************************************** + ** ** + ** Name: network_api_encode_data() ** + ** ** + ** Description: Encodes Access Stratum message to be sent to the network ** + ** ** + ** Inputs data: Generic pointer to the AS data to encode ** + ** Others: None ** + ** ** + ** Outputs: Return: The number of characters that have been ** + ** successfully encoded; ** + ** RETURNerror otherwise. ** + ** Others: _network_api_send_buffer ** + ** ** + ***************************************************************************/ +int network_api_encode_data(void* data) +{ + LOG_FUNC_IN; + + /* Encode the Access Stratum message */ + int bytes = as_message_encode(_network_api_send_buffer, + (as_message_t*)(data), + NETWORK_API_SEND_BUFFER_SIZE); + + if (bytes != RETURNerror) { + LOG_TRACE(INFO, "NET-API - %d bytes encoded", bytes); + } + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: as_message_send() ** + ** ** + ** Description: Service provided to the EPS Mobility Management protocol ** + ** at the EMMAS Access Point (EMMAS-SAP) to send AS messages ** + ** to the Access Stratum sublayer. ** + ** ** + ** Inputs: as_msg: The AS message to send ** + ** Others: _network_api_send_buffer, _network_api_id ** + ** ** + ** Outputs: Return: The number of bytes sent when success; ** + ** RETURNerror Otherwise ** + ** Others: _network_api_send_buffer ** + ** ** + ***************************************************************************/ +int as_message_send(as_message_t* as_msg) +{ + int bytes; + LOG_FUNC_IN; + + LOG_TRACE(INFO, "NET-API - Send message 0x%.4x to the Access Stratum " + "layer", as_msg->msgID); + + /* Encode the AS message */ + bytes = network_api_encode_data(as_msg); + + if (bytes > 0) { + /* Get the network file descriptor */ + int fd = network_api_get_fd(); + if (fd != RETURNerror) { + /* Send the AS message to the network */ + bytes = network_api_send_data(fd, bytes); + } + } + + LOG_FUNC_RETURN (bytes); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.h b/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.h new file mode 100644 index 0000000000..5e898ed15b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/network/network_api.h @@ -0,0 +1,52 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network_api.h + +Version 0.1 + +Date 2012/03/01 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer to send/receive + message to/from the network layer + +*****************************************************************************/ +#ifndef __NETWORK_API_H__ +#define __NETWORK_API_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int network_api_initialize(const char* host, const char* port); + +int network_api_get_fd(void); +const void* network_api_get_data(void); + +int network_api_read_data(int fd); +int network_api_send_data(int fd, int length); +void network_api_close(int fd); + +int network_api_decode_data(int length); +int network_api_encode_data(void* data); + +#endif /* __NETWORK_API_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/user/Makefile new file mode 100644 index 0000000000..17da9df138 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/Makefile @@ -0,0 +1,21 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(EMMMSGDIR) -I$(ESMMSGDIR) +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +all: $(OBJS) + +%.o: %.c Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) $(OBJS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.c new file mode 100644 index 0000000000..86f6ca6c9f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.c @@ -0,0 +1,1831 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source at_command.c + +Version 0.1 + +Date 2012/03/07 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel, Baris Demiray + +Description Defines the ATtention (AT) command set supported by the NAS + sublayer protocol + +*****************************************************************************/ + +#include "at_command.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "at_error.h" + +#include <ctype.h> // isspace, isdigit +#include <stdlib.h> // strtol, malloc, free +#include <string.h> // strncpy, strstr, strchr, strcmp, strncasecmp + // strlen, memmove, strdup, strtok +#include <stdarg.h> // va_start, va_arg, va_end + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +extern int at_response_format_v1; +extern int at_error_code_suppression_q1; +extern at_error_format_t at_error_format; + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Handlers used to parse AT commands */ +static int parse_e0(const char*, int, at_command_t*); +static int parse_e1(const char*, int, at_command_t*); +static int parse_q0(const char*, int, at_command_t*); +static int parse_q1(const char*, int, at_command_t*); +static int parse_v0(const char*, int, at_command_t*); +static int parse_v1(const char*, int, at_command_t*); +static int parse_cgsn(const char*, int, at_command_t*); +static int parse_cgsn_test(const char*, int, at_command_t*); +static int parse_cgmi(const char*, int, at_command_t*); +static int parse_cgmi_test(const char*, int, at_command_t*); +static int parse_cgmm(const char*, int, at_command_t*); +static int parse_cgmm_test(const char*, int, at_command_t*); +static int parse_cgmr(const char*, int, at_command_t*); +static int parse_cgmr_test(const char*, int, at_command_t*); +static int parse_cimi(const char*, int, at_command_t*); +static int parse_cimi_test(const char*, int, at_command_t*); +static int parse_cfun_set(const char*, int, at_command_t*); +static int parse_cfun_get(const char*, int, at_command_t*); +static int parse_cfun_test(const char*, int, at_command_t*); +static int parse_cpin_set(const char*, int, at_command_t*); +static int parse_cpin_get(const char*, int, at_command_t*); +static int parse_cpin_test(const char*, int, at_command_t*); +static int parse_csq(const char*, int, at_command_t*); +static int parse_csq_test(const char*, int, at_command_t*); +static int parse_cesq(const char*, int, at_command_t*); +static int parse_cesq_test(const char*, int, at_command_t*); +static int parse_clac(const char*, int, at_command_t*); +static int parse_clac_test(const char*, int, at_command_t*); +static int parse_cmee_set(const char*, int, at_command_t*); +static int parse_cmee_get(const char*, int, at_command_t*); +static int parse_cmee_test(const char*, int, at_command_t*); +static int parse_cnum(const char*, int, at_command_t*); +static int parse_cnum_test(const char*, int, at_command_t*); +static int parse_clck_set(const char*, int, at_command_t*); +static int parse_clck_test(const char*, int, at_command_t*); +static int parse_cops_set(const char*, int, at_command_t*); +static int parse_cops_get(const char*, int, at_command_t*); +static int parse_cops_test(const char*, int, at_command_t*); +static int parse_creg_set(const char*, int, at_command_t*); +static int parse_creg_get(const char*, int, at_command_t*); +static int parse_creg_test(const char*, int, at_command_t*); +static int parse_cgatt_set(const char*, int, at_command_t*); +static int parse_cgatt_get(const char*, int, at_command_t*); +static int parse_cgatt_test(const char*, int, at_command_t*); +static int parse_cgreg_set(const char*, int, at_command_t*); +static int parse_cgreg_get(const char*, int, at_command_t*); +static int parse_cgreg_test(const char*, int, at_command_t*); +static int parse_cereg_set(const char*, int, at_command_t*); +static int parse_cereg_get(const char*, int, at_command_t*); +static int parse_cereg_test(const char*, int, at_command_t*); +static int parse_cgdcont_set(const char*, int, at_command_t*); +static int parse_cgdcont_get(const char*, int, at_command_t*); +static int parse_cgdcont_test(const char*, int, at_command_t*); +static int parse_cgact_set(const char*, int, at_command_t*); +static int parse_cgact_get(const char*, int, at_command_t*); +static int parse_cgact_test(const char*, int, at_command_t*); +static int parse_cgpaddr_set(const char*, int, at_command_t*); +static int parse_cgpaddr_test(const char*, int, at_command_t*); + +/* List of AT command handlers */ +typedef struct { + char *command; + int (*handler)(const char *, int, at_command_t*); + at_command_type_t type; +} at_command_handler_t; + +static const at_command_handler_t _at_command_handler[] = { + /* TE-TA interface commands */ + { "E0", parse_e0, AT_COMMAND_ACT }, + { "E1", parse_e1, AT_COMMAND_ACT }, + { "Q0", parse_q0, AT_COMMAND_ACT }, + { "Q1", parse_q1, AT_COMMAND_ACT }, + { "V0", parse_v0, AT_COMMAND_ACT }, + { "V1", parse_v1, AT_COMMAND_ACT }, + { "E0Q0V0", parse_v0, AT_COMMAND_ACT }, + { "E0Q0V1", parse_v1, AT_COMMAND_ACT }, + { "E1Q0V0", parse_v0, AT_COMMAND_ACT }, + { "E1Q0V1", parse_v1, AT_COMMAND_ACT }, + /* Request Product Serial Number identification (IMEI) */ + { "+CGSN", parse_cgsn, AT_COMMAND_ACT }, + { "+CGSN=?", parse_cgsn_test, AT_COMMAND_TST }, + /* Request manufacturer identification */ + { "+CGMI", parse_cgmi, AT_COMMAND_ACT }, + { "+CGMI=?", parse_cgmi_test, AT_COMMAND_TST }, + /* Request model identification */ + { "+CGMM", parse_cgmm, AT_COMMAND_ACT }, + { "+CGMM=?", parse_cgmm_test, AT_COMMAND_TST }, + /* Request revision identification */ + { "+CGMR", parse_cgmr, AT_COMMAND_ACT }, + { "+CGMR=?", parse_cgmr_test, AT_COMMAND_TST }, + /* Request International Mobile Subscriber Identity */ + { "+CIMI", parse_cimi, AT_COMMAND_ACT }, + { "+CIMI=?", parse_cimi_test, AT_COMMAND_TST }, + /* Set phone functionality */ + { "+CFUN=", parse_cfun_set, AT_COMMAND_SET }, + { "+CFUN?", parse_cfun_get, AT_COMMAND_GET }, + { "+CFUN=?", parse_cfun_test, AT_COMMAND_TST }, + /* Enter PIN */ + { "+CPIN=", parse_cpin_set, AT_COMMAND_SET }, + { "+CPIN?", parse_cpin_get, AT_COMMAND_GET }, + { "+CPIN=?", parse_cpin_test, AT_COMMAND_TST }, + /* Signal quality */ + { "+CSQ", parse_csq, AT_COMMAND_ACT }, + { "+CSQ=?", parse_csq_test, AT_COMMAND_TST }, + /* Extended signal quality */ + { "+CESQ", parse_cesq, AT_COMMAND_ACT }, + { "+CESQ=?", parse_cesq_test, AT_COMMAND_TST }, + /* List all available AT commands */ + { "+CLAC", parse_clac, AT_COMMAND_ACT }, + { "+CLAC=?", parse_clac_test, AT_COMMAND_TST }, + /* Report mobile termination error */ + { "+CMEE=", parse_cmee_set, AT_COMMAND_SET }, + { "+CMEE?", parse_cmee_get, AT_COMMAND_GET }, + { "+CMEE=?", parse_cmee_test, AT_COMMAND_TST }, + /* Subscriber number */ + { "+CNUM", parse_cnum, AT_COMMAND_ACT }, + { "+CNUM=?", parse_cnum_test, AT_COMMAND_TST }, + /* Facility lock */ + { "+CLCK=", parse_clck_set, AT_COMMAND_SET }, + { "+CLCK=?", parse_clck_test, AT_COMMAND_TST }, + /* PLMN selection */ + { "+COPS=", parse_cops_set, AT_COMMAND_SET }, + { "+COPS?", parse_cops_get, AT_COMMAND_GET }, + { "+COPS=?", parse_cops_test, AT_COMMAND_TST }, + /* Network registration */ + { "+CREG=", parse_creg_set, AT_COMMAND_SET }, + { "+CREG?", parse_creg_get, AT_COMMAND_GET }, + { "+CREG=?", parse_creg_test, AT_COMMAND_TST }, + /* GPRS service attach/detach */ + { "+CGATT=", parse_cgatt_set, AT_COMMAND_SET }, + { "+CGATT?", parse_cgatt_get, AT_COMMAND_GET }, + { "+CGATT=?", parse_cgatt_test, AT_COMMAND_TST }, + /* GPRS network registration status */ + { "+CGREG=", parse_cgreg_set, AT_COMMAND_SET }, + { "+CGREG?", parse_cgreg_get, AT_COMMAND_GET }, + { "+CGREG=?", parse_cgreg_test, AT_COMMAND_TST }, + /* EPS network registration status */ + { "+CEREG=", parse_cereg_set, AT_COMMAND_SET }, + { "+CEREG?", parse_cereg_get, AT_COMMAND_GET }, + { "+CEREG=?", parse_cereg_test, AT_COMMAND_TST }, + /* Define PDP Context */ + { "+CGDCONT=", parse_cgdcont_set, AT_COMMAND_SET }, + { "+CGDCONT?", parse_cgdcont_get, AT_COMMAND_GET }, + { "+CGDCONT=?", parse_cgdcont_test, AT_COMMAND_TST }, + /* PDP context activate or deactivate */ + { "+CGACT=", parse_cgact_set, AT_COMMAND_SET }, + { "+CGACT?", parse_cgact_get, AT_COMMAND_GET }, + { "+CGACT=?", parse_cgact_test, AT_COMMAND_TST }, + /* Show PDP address(es) */ + { "+CGPADDR=", parse_cgpaddr_set, AT_COMMAND_SET }, + { "+CGPADDR=?", parse_cgpaddr_test, AT_COMMAND_TST }, + + { "null", NULL } +}; + +static int ParseString(char * at_str, at_command_t* at_command); +static int ParseCommand(const unsigned char *str, const char *format, ...); +static size_t GrabString(const unsigned char *str, char **output); +static unsigned int NumberOfParameters(const unsigned char* str); +static unsigned int IsNumeric(const char* str, size_t len); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: at_command_decode() ** + ** ** + ** Description: Parses AT command line and accordingly fills data struc- ** + ** ture. The main functions of the AT command parser are: ** + ** - check the AT command syntax ** + ** - fill parameter values into the data structure ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing AT com- ** + ** mand line ** + ** length: Number of bytes that should be processed ** + ** Others: None ** + ** ** + ** Outputs: at_command: AT command data structure to be filled ** + ** Return: The number of AT commands successfully ** + ** decoded; RETURNerror if an error occurred ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_command_decode(const char* buffer, int length, at_command_t* at_command) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if (length < 3) { + /* Minimum size to carry an AT command is 3 */ + LOG_TRACE(ERROR, "USR-API - Input is short of size to carry an AT command!"); + return RETURNerror; + } else if (strncasecmp(buffer, "AT", 2) != 0) { + /* There must be AT initials in input... */ + LOG_TRACE(ERROR, "USR-API - There is no proper initials (AT) in input!"); + return RETURNerror; + } else if (buffer[length - 1] != '\r') { + /* And there must be CR at the end */ + LOG_TRACE(ERROR, "USR-API - There is no Carriage Return at the end!"); + return RETURNerror; + } else if (strcasecmp(buffer, "AT\r") == 0) { + /* AT command alone; just return OK */ + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return (1); + } + + /* Parse the AT command line */ + int i; + char* buf = strdup(buffer+2); + char* cmd = strtok(buf, ";"); + for (i=0; cmd && (rc != RETURNerror); i++) { + rc = ParseString(cmd, &at_command[i]); + cmd = strtok(NULL, ";"); + } + free(buf); + + if (rc != RETURNerror) { + LOG_FUNC_RETURN (i); + } + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: at_command_get_list() ** + ** ** + ** Description: Returns the list of supported AT commands. ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the ** + ** string representaton of the first AT com- ** + ** mand that is supported by the NAS sublayer ** + ** n_max: Maximum number of AT commands the buffer ** + ** may contain ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of AT commands actually suppor- ** + ** ted by the NAS sublayer ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_command_get_list(const char** buffer, int n_max) +{ + LOG_FUNC_IN; + + int handler_index = 0; + while ( (strcmp(_at_command_handler[handler_index].command, "null") != 0) && + (handler_index < n_max) ) + { + *buffer++ = _at_command_handler[handler_index++].command; + } + + LOG_FUNC_RETURN (handler_index); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: ParseString() ** + ** ** + ** Description: Calls the appropriate parsing handler after having ** + ** successfully parsed the AT command prefix. ** + ** ** + ** Inputs: at_str: Pointer to the buffer containing AT com- ** + ** mand line ** + ** Others: None ** + ** ** + ** Outputs: at_command: AT command structure to be filled ** + ** Return: The AT command identifier when the buffer ** + ** has been successfully processed; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int ParseString(char * at_str, at_command_t* at_command) +{ + char* terminal_character_index = NULL; + int num_of_chars_to_compare = -1; + int handler_index; + int handler_found = FALSE; + int check_for_carriage_return_index = 0; + + /* + * Find the number of characters we should be comparing against + * the command list + */ + if ((terminal_character_index = strstr(at_str, "=?")) != NULL) { + /* `test' command */ + num_of_chars_to_compare = terminal_character_index - at_str + 2; + check_for_carriage_return_index = 1; + at_command->type = AT_COMMAND_TST; + } else if ((terminal_character_index = strchr(at_str, '?')) != NULL) { + /* `read' command */ + num_of_chars_to_compare = terminal_character_index - at_str + 1; + check_for_carriage_return_index = 1; + at_command->type = AT_COMMAND_GET; + } else if ((terminal_character_index = strchr(at_str, '=')) != NULL) { + /* `set' command */ + num_of_chars_to_compare = terminal_character_index - at_str + 1; + at_command->type = AT_COMMAND_SET; + } else if ((terminal_character_index = strchr(at_str, '\r')) != NULL) { + /* Basic/action command */ + num_of_chars_to_compare = terminal_character_index - at_str; + check_for_carriage_return_index = 1; + at_command->type = AT_COMMAND_ACT; + } else { + /* One action command among many commands */ + num_of_chars_to_compare = strchr(at_str, '\0') - at_str; + at_command->type = AT_COMMAND_ACT; + } + + /* + * The AT command strings in `Commands' list (that we compare the incoming + * command against) don't have CR at the end. So we have to ensure that CR + * comes just after characters like = and ? + */ + if (check_for_carriage_return_index == 1) { + if ( (at_str[num_of_chars_to_compare] != '\0') && + (at_str[num_of_chars_to_compare] != '\r') ) { + LOG_TRACE(ERROR, "USR-API - Carriage return is not at where it should be!"); + return RETURNerror; + } + } + + /* Check if this command has a relevant command handler */ + for (handler_index=0; + strcmp(_at_command_handler[handler_index].command, "null") != 0; + handler_index++) + { + /* First match the command types... */ + if (at_command->type != _at_command_handler[handler_index].type) + continue; + /* Match the command length... */ + if (strlen(_at_command_handler[handler_index].command) != + num_of_chars_to_compare) continue; + /* Now do string comparison... */ + if (strncasecmp(at_str, _at_command_handler[handler_index].command, + num_of_chars_to_compare) != 0) continue; + handler_found = TRUE; + break; + } + + /* Call the relevant handler or return with error */ + if (!handler_found) { + LOG_TRACE(ERROR, "USR-API - Unsupported or invalid command!"); + return RETURNerror; + } + + return _at_command_handler[handler_index].handler(at_str, + num_of_chars_to_compare, + at_command); +} + +/**************************************************************************** + ** ** + ** Name: ParseCommand() ** + ** ** + ** Description: Parses the input string on the basis of the format string ** + ** provided. ** + ** ** + ** Inputs: str: The string to be parsed ** + ** format: The format of the input string ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int ParseCommand(const unsigned char *str, const char *format, ...) +{ + const unsigned char *fmt = (unsigned char*) format; + const char *inp = (char*) str; + char *endptr; + char *out_us; + char *buffer; + size_t length; + size_t storage_size; + int *out_i; + long int *out_l; + va_list ap; + int error = RETURNok; + + va_start(ap, format); + while (*fmt) { + switch (*fmt++) + { + case '@': + if (*fmt == 0) { + /* Invalid format string */ + LOG_TRACE(ERROR, "USR-API - Invalid format string!"); + error = RETURNerror; + goto end; + } + switch (*fmt++) + { + case 'i': + out_i = va_arg(ap, int *); + *out_i = strtol(inp, &endptr, 10); + if (endptr == inp) { + error = RETURNerror; + goto end; + } + inp = endptr; + break; + case 'I': + out_i = va_arg(ap, int *); + *out_i = strtol(inp, &endptr, 10); + if (endptr == inp) { + /* Number empty */ + /* optional parameter ??? */ + LOG_TRACE(WARNING, "USR-API - Number empty!"); + *out_i = 0; + } else { + inp = endptr; + } + break; + case 'l': + out_l = va_arg(ap, long int *); + *out_l = strtol(inp, &endptr, 10); + if (endptr == inp) { + error = RETURNerror; + goto end; + } + inp = endptr; + break; + case 'r': + out_us = va_arg(ap, char *); + storage_size = va_arg(ap, size_t); + length = GrabString((unsigned char*) inp, &buffer); + if (strlen(buffer) > storage_size) { + free(buffer); + error = RETURNerror; + goto end; + } + strcpy(out_us, buffer); + free(buffer); + inp += length; + break; + case '@': + if (*inp++ != '@') { + error = RETURNerror; + goto end; + } + break; + case '0': + /* Just skip the rest */ + goto end; + default: + /* Invalid format string */ + error = RETURNerror; + goto end; + } + break; + + case ' ': + while (isspace(*inp)) + inp++; + break; + + default: + if (*inp++ != *(fmt - 1)) { + error = RETURNerror; + goto end; + } + break; + } + } + + /* Ignore trailing spaces */ + while (isspace(*inp)) + inp++; + + if (*inp != 0) { + error = RETURNerror; + goto end; + } + + end: va_end(ap); + + return error; +} + +/**************************************************************************** + ** ** + ** Name: GrabString() ** + ** ** + ** Description: Grabs single string, removing possible quotes. ** + ** ** + ** Inputs: str: The string to be parsed ** + ** Others: None ** + ** ** + ** Outputs: output: Allocated output string buffer ** + ** Return: Length of parsed string ** + ** Others: None ** + ** ** + ***************************************************************************/ +static size_t GrabString(const unsigned char *str, char **output) +{ + size_t size = 4, position = 0; + int inside_quotes = 0; + + /* Allocate initial buffer in case string is empty */ + *output = malloc(size); + if (*output == NULL) { + return 0; + } + + while (inside_quotes || (*str != ',' && *str != ')' && + *str != 0x0d && *str != 0x0a && *str != 0x00)) + { + /* Check for quotes */ + if (*str == '"') { + inside_quotes = !inside_quotes; + } + + /* We also allocate space for trailing zero */ + if (position + 2 > size) { + size += 10; + *output = realloc(*output, size); + if (*output == NULL) { + return 0; + } + } + + /* Copy to output */ + (*output)[position] = *str; + position++; + str++; + } + + (*output)[position] = 0; + + /* Strip quotes */ + if ((*output)[0] == '"' && (*output)[position - 1]) { + memmove(*output, (*output) + 1, position - 2); + (*output)[position - 2] = 0; + } + + return position; +} + +/**************************************************************************** + ** ** + ** Name: NumberOfParameters() ** + ** ** + ** Description: Returns the number of parameters found in the given AT ** + ** command line. ** + ** ** + ** Inputs: str: The string to be parsed ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of parameter delimiter (comma) ** + ** found in the input string buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static unsigned int NumberOfParameters(const unsigned char* str) +{ + if (*str == '\r') + return 0; + + int count = 1; + while (*str) { + if (*str++ == ',') { + ++count; + } + } + return count; +} + +/**************************************************************************** + ** ** + ** Name: IsNumeric() ** + ** ** + ** Description: Checks whether the input string buffer has all digits ** + ** ** + ** Inputs: str: The string to be parsed ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE, FALSE ** + ** Others: None ** + ** ** + ***************************************************************************/ +static unsigned int IsNumeric(const char* str, size_t len) +{ + while (len-- > 0) { + if (!isdigit(str[len])) { + return FALSE; + } + } + return TRUE; +} + +/****************************************************************************/ +/******************** Handlers used to parse AT commands ********************/ +/****************************************************************************/ + +static int parse_e0(const char* string, int position, at_command_t* at_command) +{ + /* Command echo E0 */ + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_e1(const char* string, int position, at_command_t* at_command) +{ + /* Command echo E1 */ + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_q0(const char* string, int position, at_command_t* at_command) +{ + /* Result code suppression Q0 */ + at_error_code_suppression_q1 = FALSE; + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_q1(const char* string, int position, at_command_t* at_command) +{ + /* Result code suppression Q1 */ + at_error_code_suppression_q1 = TRUE; + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_v0(const char* string, int position, at_command_t* at_command) +{ + /* Response format V0 (numeric result code + limited header) */ + at_error_format = AT_ERROR_NUMERIC; + at_response_format_v1 = FALSE; + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_v1(const char* string, int position, at_command_t* at_command) +{ + /* Response format V1 (verbose result code + full header) */ + at_error_format = AT_ERROR_VERBOSE; + at_response_format_v1 = TRUE; + at_command->id = 0; + at_command->mask = AT_COMMAND_NO_PARAM; + return at_command->id; +} + +static int parse_cgsn(const char* string, int position, at_command_t* at_command) +{ + /* CGSN action command - No parameter */ + at_command->id = AT_CGSN; + at_command->mask = AT_COMMAND_CGSN_MASK; + return at_command->id; +} + +static int parse_cgsn_test(const char* string, int position, at_command_t* at_command) +{ + /* CGSN test command - No parameter */ + at_command->id = AT_CGSN; + return at_command->id; +} + +static int parse_cgmi(const char* string, int position, at_command_t* at_command) +{ + /* CGMI action command - No parameter */ + at_command->id = AT_CGMI; + at_command->mask = AT_COMMAND_CGMI_MASK; + return at_command->id; +} + +static int parse_cgmi_test(const char* string, int position, at_command_t* at_command) +{ + /* CGMI test command - No parameter */ + at_command->id = AT_CGMI; + return at_command->id; +} + +static int parse_cgmm(const char* string, int position, at_command_t* at_command) +{ + /* CGMM action command - No parameter */ + at_command->id = AT_CGMM; + at_command->mask = AT_COMMAND_CGMM_MASK; + return at_command->id; +} + +static int parse_cgmm_test(const char* string, int position, at_command_t* at_command) +{ + /* CGMM test command - No parameter */ + at_command->id = AT_CGMM; + return at_command->id; +} + +static int parse_cgmr(const char* string, int position, at_command_t* at_command) +{ + /* CGMR action command - No parameter */ + at_command->id = AT_CGMR; + at_command->mask = AT_COMMAND_CGMR_MASK; + return at_command->id; +} + +static int parse_cgmr_test(const char* string, int position, at_command_t* at_command) +{ + /* CGMR test command - No parameter */ + at_command->id = AT_CGMR; + return at_command->id; +} + +static int parse_cimi(const char* string, int position, at_command_t* at_command) +{ + /* CIMI action command - No parameter */ + at_command->id = AT_CIMI; + at_command->mask = AT_COMMAND_CIMI_MASK; + return at_command->id; +} + +static int parse_cimi_test(const char* string, int position, at_command_t* at_command) +{ + /* CIMI test command - No parameter */ + at_command->id = AT_CIMI; + return at_command->id; +} + +static int parse_cfun_set(const char* string, int position, at_command_t* at_command) +{ + /* CFUN parameter command - Parameters [<fun>[,<rst>]] */ + at_command->id = AT_CFUN; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CFUN= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <fun> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cfun.fun) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CFUN=<fun> command failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CFUN=<fun> command succeed (fun:%d)", at_command->command.cfun.fun); + + at_command->mask = AT_CFUN_FUN_MASK; + break; + + case 2: // <fun>,<rst> parameters are present + if (ParseCommand(parameter_start_index, "@i,@i", + &at_command->command.cfun.fun, + &at_command->command.cfun.rst) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CFUN=<fun>,<rst> command failed"); + return RETURNerror; + } + + LOG_TRACE(INFO, "USR-API - Parsing of AT+CFUN=<fun>,<rst> command succeed (fun:%d, rst:%d)", at_command->command.cfun.fun, at_command->command.cfun.rst); + + at_command->mask = AT_CFUN_FUN_MASK | AT_CFUN_RST_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cfun_get(const char* string, int position, at_command_t* at_command) +{ + /* CFUN action command - No parameter */ + at_command->id = AT_CFUN; + return at_command->id; +} + +static int parse_cfun_test(const char* string, int position, at_command_t* at_command) +{ + /* CFUN test command - No parameter */ + at_command->id = AT_CFUN; + return at_command->id; +} + +static int parse_cpin_set(const char* string, int position, at_command_t* at_command) +{ + /* CPIN parameter command - Parameters <pin>[,<newpin>] */ + at_command->id = AT_CPIN; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 1: // Only <pin> parameter is present + if (ParseCommand(parameter_start_index, "@r", + at_command->command.cpin.pin, AT_CPIN_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CPIN=<pin> command failed"); + return RETURNerror; + } + + if (!IsNumeric(at_command->command.cpin.pin, AT_CPIN_SIZE)) + { + LOG_TRACE(ERROR, "USR-API - Incoming parameter is not a valid PIN code!"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CPIN=<pin> command succeed (pin:%s)", at_command->command.cpin.pin); + + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 2: // <pin>,<newpin> parameters are present + if (ParseCommand(parameter_start_index, "@r,@r", + at_command->command.cpin.pin, AT_CPIN_SIZE, + at_command->command.cpin.newpin, AT_CPIN_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CPIN=<pin>,<newpin> command failed"); + return RETURNerror; + } + + if (!IsNumeric(at_command->command.cpin.pin, AT_CPIN_SIZE) || + !IsNumeric(at_command->command.cpin.newpin, AT_CPIN_SIZE)) + { + LOG_TRACE(ERROR, "USR-API - Incoming parameter is not a valid PIN code!"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CPIN=<pin>,<newpin> command succeed (pin:%s, newpin:%s)", at_command->command.cpin.pin, at_command->command.cpin.newpin); + + at_command->mask = AT_CPIN_NEWPIN_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cpin_get(const char* string, int position, at_command_t* at_command) +{ + /* CPIN action command - No parameter */ + at_command->id = AT_CPIN; + return at_command->id; +} + +static int parse_cpin_test(const char* string, int position, at_command_t* at_command) +{ + /* CPIN test command - No parameter */ + at_command->id = AT_CPIN; + return at_command->id; +} + +static int parse_csq(const char* string, int position, at_command_t* at_command) +{ + /* CSQ action command - No parameter */ + at_command->id = AT_CSQ; + at_command->mask = AT_COMMAND_CSQ_MASK; + return at_command->id; +} + +static int parse_csq_test(const char* string, int position, at_command_t* at_command) +{ + /* CSQ test command - No parameter */ + at_command->id = AT_CSQ; + return at_command->id; +} + +static int parse_cesq(const char* string, int position, at_command_t* at_command) +{ + /* CESQ action command - No parameter */ + at_command->id = AT_CESQ; + at_command->mask = AT_COMMAND_CESQ_MASK; + return at_command->id; +} + +static int parse_cesq_test(const char* string, int position, at_command_t* at_command) +{ + /* CESQ test command - No parameter */ + at_command->id = AT_CESQ; + return at_command->id; +} + +static int parse_clac(const char* string, int position, at_command_t* at_command) +{ + /* CLAC action command - No parameter */ + at_command->id = AT_CLAC; + at_command->mask = AT_COMMAND_CLAC_MASK; + return at_command->id; +} + +static int parse_clac_test(const char* string, int position, at_command_t* at_command) +{ + /* CLAC test command - No parameter */ + at_command->id = AT_CLAC; + return at_command->id; +} + +static int parse_cmee_set(const char* string, int position, at_command_t* at_command) +{ + /* CMEE parameter command - Parameter [<n>] */ + at_command->id = AT_CMEE; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CMEE= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <n> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cmee.n) != RETURNok) { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CMEE=<n> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CMEE=<n> command succeed (n:%d)", at_command->command.cmee.n); + + at_command->mask = AT_CMEE_N_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cmee_get(const char* string, int position, at_command_t* at_command) +{ + /* CMEE read command - No parameter */ + at_command->id = AT_CMEE; + return at_command->id; +} + +static int parse_cmee_test(const char* string, int position, at_command_t* at_command) +{ + /* CMEE test command - No parameter */ + at_command->id = AT_CMEE; + return at_command->id; +} + +static int parse_cnum(const char* string, int position, at_command_t* at_command) +{ + /* CNUM action command - No parameter */ + at_command->id = AT_CNUM; + at_command->mask = AT_COMMAND_CNUM_MASK; + return at_command->id; +} + +static int parse_cnum_test(const char* string, int position, at_command_t* at_command) +{ + /* CNUM test command - No parameter */ + at_command->id = AT_CNUM; + return at_command->id; +} + +static int parse_clck_set(const char* string, int position, at_command_t* at_command) +{ + /* CLCK action command - Parameters <fac>,<mode>[,<passwd>] */ + at_command->id = AT_CLCK; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + switch (number_of_parameters) + { + case 2: // <fac>,<mode> parameters are present + if (ParseCommand(parameter_start_index, "@r,@i", + &at_command->command.clck.fac, AT_CLCK_FAC_SIZE, + &at_command->command.clck.mode) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CLCK=<fac>,<mode> " + "failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CLCK=<fac>,<mode> " + "succeed (fac:%s, mode:%d)", + at_command->command.clck.fac, + at_command->command.clck.mode); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 3: // <fac>,<mode>,<passwd> parameters are present + if (ParseCommand(parameter_start_index, "@r,@i,@r", + &at_command->command.clck.fac, AT_CLCK_FAC_SIZE, + &at_command->command.clck.mode, + &at_command->command.clck.passwd, + AT_CLCK_PASSWD_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CLCK=<fac>,<mode>" + "<passwd> failed"); + return RETURNerror; + } + if (!IsNumeric(at_command->command.clck.passwd,AT_CLCK_PASSWD_SIZE)) + { + LOG_TRACE(ERROR, "USR-API - Incoming parameter is not a valid password!"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CLCK=<fac>,<mode>" + "<passwd> succeed (fac:%s, mode:%d, passwd:%s)", + at_command->command.clck.fac, + at_command->command.clck.mode, + at_command->command.clck.passwd); + at_command->mask = AT_CLCK_PASSWD_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return -1; + } + + return at_command->id; +} + +static int parse_clck_test(const char* string, int position, at_command_t* at_command) +{ + /* CLCK test command - No parameter */ + at_command->id = AT_CLCK; + return at_command->id; +} + +static int parse_cops_set(const char* string, int position, at_command_t* at_command) +{ + /* COPS parameter command - Parameters [<mode>[,<format>[,<oper>[,<AcT>]]]] */ + at_command->id = AT_COPS; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + char oper_value[AT_COPS_NUM_SIZE]; + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <mode> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cops.mode) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode> command failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode> command succeed (mode:%d)", at_command->command.cops.mode); + + at_command->mask = AT_COPS_MODE_MASK; + break; + + case 2: // <mode>,<format> parameters are present + if (ParseCommand(parameter_start_index, "@i,@i", + &at_command->command.cops.mode, + &at_command->command.cops.format) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format> command failed"); + return RETURNerror; + } + + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format> command succeed (mode:%d, format:%d)", at_command->command.cops.mode, at_command->command.cops.format); + + at_command->mask = AT_COPS_MODE_MASK | AT_COPS_FORMAT_MASK; + break; + + case 3: // <mode>,<format>,<oper> parameters are present + if (ParseCommand(parameter_start_index, "@i,@i,@r", + &at_command->command.cops.mode, + &at_command->command.cops.format, + oper_value, NET_FORMAT_MAX_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper> command failed"); + return RETURNerror; + } + + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper> command succeed (mode:%d, format:%d)", at_command->command.cops.mode, at_command->command.cops.format); + + /* Now, process <oper> parameter according to the specified <format> parameter */ + switch (at_command->command.cops.format) + { + case AT_COPS_LONG: /* long format alphanumeric <oper> */ + strncpy((char*) at_command->command.cops.plmn.id.alpha_long, + oper_value, AT_COPS_LONG_SIZE); + LOG_TRACE(INFO, "USR-API - <oper> parameter's value is '%s'", at_command->command.cops.plmn.id.alpha_long); + break; + + case AT_COPS_SHORT: /* short format alphanumeric <oper> */ + strncpy((char*) at_command->command.cops.plmn.id.alpha_short, oper_value, AT_COPS_SHORT_SIZE); + LOG_TRACE(INFO, "USR-API - <oper> parameter's value is '%s'", at_command->command.cops.plmn.id.alpha_short); + break; + + case AT_COPS_NUM: /* numeric <oper> */ + strncpy((char*) at_command->command.cops.plmn.id.num, + oper_value, AT_COPS_NUM_SIZE); + LOG_TRACE(INFO, "USR-API - <oper> parameter's value is '%s'", at_command->command.cops.plmn.id.num); + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid format value (%d)", + at_command->command.cops.format); + return RETURNerror; + } + + at_command->mask = AT_COPS_MODE_MASK | AT_COPS_FORMAT_MASK | AT_COPS_OPER_MASK; + break; + + case 4: // <mode>,<format>,<oper>,<AcT> parameters are present + if (ParseCommand(parameter_start_index, "@i,@i,@0", + &at_command->command.cops.mode, + &at_command->command.cops.format) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format> command failed"); + return RETURNerror; + } + + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper> command succeed (mode:%d, format:%d)", at_command->command.cops.mode, at_command->command.cops.format); + + /* Now, process <oper> parameter according to the specified <format> parameter */ + switch (at_command->command.cops.format) + { + case AT_COPS_LONG: /* long format alphanumeric <oper> */ + if (ParseCommand(parameter_start_index, "@i,@i,@r,@i", + &at_command->command.cops.mode, + &at_command->command.cops.format, + oper_value, AT_COPS_LONG_SIZE, + &at_command->command.cops.AcT) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command failed"); + return RETURNerror; + } + strncpy((char*) at_command->command.cops.plmn.id.alpha_long, + oper_value, AT_COPS_LONG_SIZE); + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command succeed (oper:%s, Act:%d)", at_command->command.cops.plmn.id.alpha_long, at_command->command.cops.AcT); + break; + + case AT_COPS_SHORT: /* short format alphanumeric <oper> */ + if (ParseCommand(parameter_start_index, "@i,@i,@r,@i", + &at_command->command.cops.mode, + &at_command->command.cops.format, + oper_value, AT_COPS_SHORT_SIZE, + &at_command->command.cops.AcT) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command failed"); + return RETURNerror; + } + strncpy((char*) at_command->command.cops.plmn.id.alpha_short, + oper_value, AT_COPS_SHORT_SIZE); + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command succeed (oper:%s, Act:%d)", + at_command->command.cops.plmn.id.alpha_short, + at_command->command.cops.AcT); + break; + + case AT_COPS_NUM: /* numeric <oper> */ + if (ParseCommand(parameter_start_index, "@i,@i,@r,@i", + &at_command->command.cops.mode, + &at_command->command.cops.format, + oper_value, AT_COPS_NUM_SIZE, + &at_command->command.cops.AcT) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command failed"); + return RETURNerror; + } + strncpy((char*) at_command->command.cops.plmn.id.num, + oper_value, AT_COPS_NUM_SIZE); + LOG_TRACE(INFO, "USR-API - Parsing of AT+COPS=<mode>,<format>,<oper>,<AcT> command succeed (oper:%s, Act:%d)", + at_command->command.cops.plmn.id.num, + at_command->command.cops.AcT); + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid format value (%d)", + at_command->command.cops.format); + return RETURNerror; + } + + at_command->mask = AT_COPS_MODE_MASK | AT_COPS_FORMAT_MASK | AT_COPS_OPER_MASK | AT_COPS_ACT_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cops_get(const char* string, int position, at_command_t* at_command) +{ + /* COPS test command - No parameter */ + at_command->id = AT_COPS; + return at_command->id; +} + +static int parse_cops_test(const char* string, int position, at_command_t* at_command) +{ + /* COPS test command - No parameter */ + at_command->id = AT_COPS; + return at_command->id; +} + +static int parse_creg_set(const char* string, int position, at_command_t* at_command) +{ + /* CREG parameter command - Parameter [<n>] */ + at_command->id = AT_CREG; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CREG= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <n> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.creg.n) != RETURNok) { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CREG=<n> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CREG=<n> command succeed (n:%d)", at_command->command.creg.n); + + at_command->mask = AT_CREG_N_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_creg_get(const char* string, int position, at_command_t* at_command) +{ + /* CREG read command - No parameter */ + at_command->id = AT_CREG; + return at_command->id; +} + +static int parse_creg_test(const char* string, int position, at_command_t* at_command) +{ + /* CREG test command - No parameter */ + at_command->id = AT_CREG; + return at_command->id; +} + +static int parse_cgatt_set(const char* string, int position, at_command_t* at_command) +{ + /* CGATT parameter command - Parameter [<state>] */ + at_command->id = AT_CGATT; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGATT= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <state> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cgatt.state) != RETURNok) { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGATT=<state> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGATT=<state> command succeed (state:%d)", at_command->command.cgatt.state); + + at_command->mask = AT_CGATT_STATE_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cgatt_get(const char* string, int position, at_command_t* at_command) +{ + /* CGATT read command - No parameter */ + at_command->id = AT_CGATT; + return at_command->id; +} + +static int parse_cgatt_test(const char* string, int position, at_command_t* at_command) +{ + /* CGATT test command - No parameter */ + at_command->id = AT_CGATT; + return at_command->id; +} + +static int parse_cgreg_set(const char* string, int position, at_command_t* at_command) +{ + /* CGREG parameter command - Parameter [<n>] */ + at_command->id = AT_CGREG; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGREG= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <n> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cgreg.n) != RETURNok) { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGREG=<n> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGREG=<n> command succeed (n:%d)", at_command->command.cgreg.n); + + at_command->mask = AT_CGREG_N_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cgreg_get(const char* string, int position, at_command_t* at_command) +{ + /* CGREG read command - No parameter */ + at_command->id = AT_CGREG; + return at_command->id; +} + +static int parse_cgreg_test(const char* string, int position, at_command_t* at_command) +{ + /* CGREG test command - No parameter */ + at_command->id = AT_CGREG; + return at_command->id; +} + +static int parse_cereg_set(const char* string, int position, at_command_t* at_command) +{ + /* CEREG parameter command - Parameter [<n>] */ + at_command->id = AT_CEREG; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CEREG= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <n> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cereg.n) != RETURNok) { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CEREG=<n> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CEREG=<n> command succeed (n:%d)", at_command->command.cereg.n); + + at_command->mask = AT_CEREG_N_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cereg_get(const char* string, int position, at_command_t* at_command) +{ + /* CEREG read command - No parameter */ + at_command->id = AT_CEREG; + return at_command->id; +} + +static int parse_cereg_test(const char* string, int position, at_command_t* at_command) +{ + /* CEREG test command - No parameter */ + at_command->id = AT_CEREG; + return at_command->id; +} + +static int parse_cgdcont_set(const char* string, int position, at_command_t* at_command) +{ + /* CGDCONT parameter command - Parameters [<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp>[,<IPv4AddrAlloc>[,<emergency indication>[,<P-CSCF_discovery>[,<IM_CN_Signalling_Flag_Ind>]]]]]]]]]] */ + at_command->id = AT_CGDCONT; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + /* Parse the parameters */ + switch (number_of_parameters) + { + case 1: // Only <cid> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cgdcont.cid) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid> command succeed (cid:%d)", at_command->command.cgdcont.cid); + + at_command->mask = AT_CGDCONT_CID_MASK; + break; + + case 2: // <cid>,<PDP_type> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type> succeed (cid:%d, pdp_type:%s)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK; + break; + + case 3: // <cid>,<PDP_type>,<APN> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN> succeed (cid:%d, pdp_type:%s, apn:%s)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK; + break; + + case 4: // <cid>,<PDP_type>,<APN>,<PDP_addr> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK; + break; + + case 5: // <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK; + break; + + case 6: // <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp, + &at_command->command.cgdcont.h_comp) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d, h_comp:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp, + at_command->command.cgdcont.h_comp); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK; + break; + + case 7: // <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i,@i,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp, + &at_command->command.cgdcont.h_comp, + &at_command->command.cgdcont.IPv4AddrAlloc) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d, h_comp:%d, ipv4addralloc:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp, + at_command->command.cgdcont.h_comp, + at_command->command.cgdcont.IPv4AddrAlloc); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK | AT_CGDCONT_IPV4ADDRALLOC_MASK; + break; + + case 8: // <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication> parameters are present + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i,@i,@i,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp, + &at_command->command.cgdcont.h_comp, + &at_command->command.cgdcont.IPv4AddrAlloc, + &at_command->command.cgdcont.emergency_indication) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d, h_comp:%d, ipv4addralloc:%d, emergency_indication:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp, + at_command->command.cgdcont.h_comp, + at_command->command.cgdcont.IPv4AddrAlloc, + at_command->command.cgdcont.emergency_indication); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK | AT_CGDCONT_IPV4ADDRALLOC_MASK | AT_CGDCONT_EMERGECY_INDICATION_MASK; + break; + + case 9: /* <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>, + * <IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery> + * parameters are present */ + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i,@i,@i,@i,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp, + &at_command->command.cgdcont.h_comp, + &at_command->command.cgdcont.IPv4AddrAlloc, + &at_command->command.cgdcont.emergency_indication, + &at_command->command.cgdcont.P_CSCF_discovery) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d, h_comp:%d, ipv4addralloc:%d, emergency_indication:%d, p_cscf_discovery:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp, + at_command->command.cgdcont.h_comp, + at_command->command.cgdcont.IPv4AddrAlloc, + at_command->command.cgdcont.emergency_indication, + at_command->command.cgdcont.P_CSCF_discovery); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK | AT_CGDCONT_IPV4ADDRALLOC_MASK | AT_CGDCONT_EMERGECY_INDICATION_MASK | AT_CGDCONT_P_CSCF_DISCOVERY_MASK; + break; + + case 10: /* <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>, + * <IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery>, + * <IM_CN_Signalling_Flag_Ind> parameters are present */ + if (ParseCommand(parameter_start_index, "@i,@r,@r,@r,@i,@i,@i,@i,@i,@i", + &at_command->command.cgdcont.cid, + &at_command->command.cgdcont.PDP_type, AT_CGDCONT_PDP_SIZE, + &at_command->command.cgdcont.APN, AT_CGDCONT_APN_SIZE, + &at_command->command.cgdcont.PDP_addr, AT_CGDCONT_ADDR_SIZE, + &at_command->command.cgdcont.d_comp, + &at_command->command.cgdcont.h_comp, + &at_command->command.cgdcont.IPv4AddrAlloc, + &at_command->command.cgdcont.emergency_indication, + &at_command->command.cgdcont.P_CSCF_discovery, + &at_command->command.cgdcont.IM_CN_Signalling_Flag_Ind) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery>, <IM_CN_Signalling_Flag_Ind> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGDCONT=<cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>,<h_comp>,<IPv4AddrAlloc>,<emergency indication>,<P-CSCF_discovery>, <IM_CN_Signalling_Flag_Ind> succeed (cid:%d, pdp_type:%s, apn:%s, pdp_addr:%s, d_comp:%d, h_comp:%d, ipv4addralloc:%d, emergency_indication:%d, p_cscf_discovery:%d, im_cn_signalling_flag:%d)", + at_command->command.cgdcont.cid, + at_command->command.cgdcont.PDP_type, + at_command->command.cgdcont.APN, + at_command->command.cgdcont.PDP_addr, + at_command->command.cgdcont.d_comp, + at_command->command.cgdcont.h_comp, + at_command->command.cgdcont.IPv4AddrAlloc, + at_command->command.cgdcont.emergency_indication, + at_command->command.cgdcont.P_CSCF_discovery, + at_command->command.cgdcont.IM_CN_Signalling_Flag_Ind); + + at_command->mask = AT_CGDCONT_CID_MASK | AT_CGDCONT_PDP_TYPE_MASK | AT_CGDCONT_APN_MASK | AT_CGDCONT_PDP_ADDR_MASK | AT_CGDCONT_D_COMP_MASK | AT_CGDCONT_H_COMP_MASK | AT_CGDCONT_IPV4ADDRALLOC_MASK | AT_CGDCONT_EMERGECY_INDICATION_MASK | AT_CGDCONT_P_CSCF_DISCOVERY_MASK | AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return RETURNerror; + } + + return at_command->id; +} + +static int parse_cgdcont_get(const char* string, int position, at_command_t* at_command) +{ + /* CGDCONT read command - No parameter */ + at_command->id = AT_CGDCONT; + return at_command->id; +} + +static int parse_cgdcont_test(const char* string, int position, at_command_t* at_command) +{ + /* CGDCONT test command - No parameter */ + at_command->id = AT_CGDCONT; + return at_command->id; +} + +static int parse_cgact_set(const char* string, int position, at_command_t* at_command) +{ + /* CGACT parameter command - Parameters <state>[,<cid>] */ + at_command->id = AT_CGACT; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + switch (number_of_parameters) + { + case 1: // Only <state> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cgact.state) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGACT=<state> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGACT=<state> succeed (state:%d)", at_command->command.cgact.state); + at_command->mask = AT_CGACT_STATE_MASK; + break; + + case 2: // <state>,<cid> parameters are present + if (ParseCommand(parameter_start_index, "@i,@i", + &at_command->command.cgact.state, + &at_command->command.cgact.cid) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGACT=<state>,<cid> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGACT=<state>,<cid> succeed (state:%d, cid:%d)", + at_command->command.cgact.state, + at_command->command.cgact.cid); + + at_command->mask = AT_CGACT_STATE_MASK | AT_CGACT_CID_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return -1; + } + + return at_command->id; +} + +static int parse_cgact_get(const char* string, int position, at_command_t* at_command) +{ + /* CGACT read command - No parameter */ + at_command->id = AT_CGACT; + return at_command->id; +} + +static int parse_cgact_test(const char* string, int position, at_command_t* at_command) +{ + /* CGACT test command - No parameter */ + at_command->id = AT_CGACT; + return at_command->id; +} + +static int parse_cgpaddr_set(const char* string, int position, at_command_t* at_command) +{ + /* CGPADDR parameter command - Parameters [<cid>] */ + at_command->id = AT_CGPADDR; + unsigned char* parameter_start_index = (unsigned char*) string + position; + + /* Check the number of parameters */ + unsigned number_of_parameters = NumberOfParameters(parameter_start_index); + + switch (number_of_parameters) + { + case 0: // No any parameter + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGPADDR= command succeed"); + at_command->mask = AT_COMMAND_NO_PARAM; + break; + + case 1: // Only <cid> parameter is present + if (ParseCommand(parameter_start_index, "@i", + &at_command->command.cgpaddr.cid) != RETURNok) + { + LOG_TRACE(ERROR, "USR-API - Parsing of AT+CGPADDR=<state> failed"); + return RETURNerror; + } + LOG_TRACE(INFO, "USR-API - Parsing of AT+CGPADDR=<cid> succeed (cid:%d)", at_command->command.cgpaddr.cid); + at_command->mask = AT_CGPADDR_CID_MASK; + break; + + default: + LOG_TRACE(ERROR, "USR-API - Invalid number of parameters (%d)", number_of_parameters); + return -1; + } + + return at_command->id; +} + +static int parse_cgpaddr_test(const char* string, int position, at_command_t* at_command) +{ + /* CGPADDR test command - No parameter */ + at_command->id = AT_CGPADDR; + return at_command->id; +} diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.h b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.h new file mode 100644 index 0000000000..2d1e084015 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_command.h @@ -0,0 +1,839 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source at_command.h + +Version 0.1 + +Date 2012/03/07 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines the ATtention (AT) command set supported by the NAS + sublayer protocol + +*****************************************************************************/ +#ifndef __AT_COMMAND_H__ +#define __AT_COMMAND_H__ + +#include "userDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Bit masks indicating presence of AT command's optional parameters */ +#define AT_COMMAND_PARAM0 0x0000 /* no any parameter is present */ +#define AT_COMMAND_PARAM1 0x0001 /* first parameter is present */ +#define AT_COMMAND_PARAM2 0x0002 /* 2nd parameter is present */ +#define AT_COMMAND_PARAM3 0x0004 /* 3rd parameter is present */ +#define AT_COMMAND_PARAM4 0x0008 /* 4th parameter is present */ +#define AT_COMMAND_PARAM5 0x0010 /* 5th parameter is present */ +#define AT_COMMAND_PARAM6 0x0020 /* 6th parameter is present */ +#define AT_COMMAND_PARAM7 0x0040 /* 7th parameter is present */ +#define AT_COMMAND_PARAM8 0x0080 /* 8th parameter is present */ +#define AT_COMMAND_PARAM9 0x0100 /* 9th parameter is present */ +#define AT_COMMAND_PARAM10 0x0200 /* 10th parameter is present */ +#define AT_COMMAND_PARAM11 0x0400 /* 11th parameter is present */ +#define AT_COMMAND_PARAM12 0x0800 /* 12th parameter is present */ +#define AT_COMMAND_PARAM13 0x1000 /* 13th parameter is present */ +#define AT_COMMAND_PARAM14 0x2000 /* 14th parameter is present */ +#define AT_COMMAND_PARAM15 0x4000 /* 15th parameter is present */ +#define AT_COMMAND_PARAM16 0x8000 /* 16th parameter is present */ + +/* Value of the mask parameter for AT commands without any parameters */ +#define AT_COMMAND_NO_PARAM AT_COMMAND_PARAM0 + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * AT command identifiers + * ---------------------- + * Those currently supported by our Mobile Equipment (ME) + */ +typedef enum { + /* + * General commands + * ---------------- + */ + AT_CGSN=1, /* Request Product Serial Number identification (IMEI) */ + AT_CGMI, /* Request manufacturer identification */ + AT_CGMM, /* Request model identification */ + AT_CGMR, /* Request revision identification */ + AT_CIMI, /* Request International Mobile Subscriber Identity */ + /* + * Mobile Termination control and status commands + * ---------------------------------------------- + */ + AT_CFUN, /* Set phone functionality */ + AT_CPIN, /* Enter PIN */ + AT_CSQ, /* Signal quality */ + AT_CESQ, /* Extented signal quality */ + AT_CLAC, /* List all available AT commands */ + /* + * Mobile Termination errors + * ------------------------- + */ + AT_CMEE, /* Report mobile termination error */ + /* + * Network service related commands + * --------------------------------- + */ + AT_CNUM, /* Subscriber number */ + AT_CLCK, /* Facility lock */ + AT_COPS, /* PLMN selection */ + AT_CREG, /* Network registration */ + /* + * Commands for Packet Domain + * --------------------------- + */ + AT_CGATT, /* PS attach/detach */ + AT_CGREG, /* GPRS network registration status */ + AT_CEREG, /* EPS network registration status */ + AT_CGDCONT, /* Define PDP Context */ + AT_CGACT, /* PDP context activate or deactivate */ + AT_CGPADDR, /* Show PDP address(es) */ + AT_CGEV, /* Packet Domain event unsolicited result code */ + AT_COMMAND_ID_MAX +} at_command_id_t; + +/* + * AT command types + * ---------------- + * - AT action command, used to execute a particular function, which + * generally involves more than the simple storage of a value. + * - AT set parameter command, used to store a value or values of + * subparameters. + * - AT read parameter command, used to check the current values of + * subparameters. + * - AT test parameter command, used to test the existence of the + * command and to give information about the type of its subparameters. + */ +typedef enum { + AT_COMMAND_ACT, /* AT action command (ATCMD) */ + AT_COMMAND_SET, /* AT set parameter command (ATCMD=) */ + AT_COMMAND_GET, /* AT read parameter command (ATCMD?) */ + AT_COMMAND_TST, /* AT test parameter command (ATCMD=?) */ + AT_COMMAND_TYPE_MAX +} at_command_type_t; + +/* + * ================ + * General commands + * ================ + */ + +/* CGSN: Request Product Serial Number identification (IMEI) + * --------------------------------------------------------- + * Returns information text intended to permit the user to identify the + * individual Mobile Equipment to which it is connected to. + * Action command: + * no parameters + */ + +/* CGSN AT command type */ +#define AT_COMMAND_CGSN_MASK AT_COMMAND_NO_PARAM +typedef struct at_cgsn_s {} at_cgsn_t; + +/* CGMI: Request manufacturer identification + * ----------------------------------------- + * Returns information text intended to permit the user to identify the + * manufacturer of the Mobile Equipment to which it is connected to. + * Action command: + * no parameters + */ + +/* CGMI AT command type */ +#define AT_COMMAND_CGMI_MASK AT_COMMAND_NO_PARAM +typedef struct at_cgmi_s {} at_cgmi_t; + +/* CGMM: Request model identification + * ---------------------------------- + * Returns information text intended to permit the user to identify the + * specific model of the Mobile Equipment to which it is connected to. + * Action command: + * no parameters + */ + +/* CGMM AT command type */ +#define AT_COMMAND_CGMM_MASK AT_COMMAND_NO_PARAM +typedef struct at_cgmm_s {} at_cgmm_t; + +/* CGMR: Request revision identification + * ------------------------------------- + * Returns information text intended to permit the user to identify the + * version, revision level or date, or other pertinent information of the + * Mobile Equipment to which it is connected to. + * Action command: + * no parameters + */ + +/* CGMR AT command type */ +#define AT_COMMAND_CGMR_MASK AT_COMMAND_NO_PARAM +typedef struct at_cgmr_s {} at_cgmr_t; + +/* CIMI: Request International Mobile Subscriber Identity + * ------------------------------------------------------ + * Returns <IMSI>, which is intended to permit the user to identify the + * individual SIM card or active application in the UICC (GSM or USIM) + * which is attached to the Mobile Equipment to which it is connected to. + * Action command: + * no parameters + */ + +/* CIMI AT command type */ +#define AT_COMMAND_CIMI_MASK AT_COMMAND_NO_PARAM +typedef struct at_cimi_s {} at_cimi_t; + +/* + * ============================================== + * Mobile Termination control and status commands + * ============================================== + */ +/* CFUN: Set phone functionality + * ----------------------------- + * Used to set the Mobile Equipment to different power consumption states + * Parameter command: + * +CFUN=[<fun>[,<rst>]] + * <fun> level of functionality + * <rst> resetting parameter + */ + +/* Functionality levels */ +#define AT_CFUN_MIN 0 /* minimum functionality */ +#define AT_CFUN_FULL 1 /* full functionality */ +#define AT_CFUN_SEND 2 /* disable phone transmit RF circuits only */ +#define AT_CFUN_RECV 3 /* disable phone receive RF circuits only */ +#define AT_CFUN_BOTH 4 /* disable phone both transmit and receive + * RF circuits */ +#define AT_CFUN_MAX AT_CFUN_BOTH + /* Maximum value of supported functionality + * level */ +#define AT_CFUN_FUN_DEFAULT AT_CFUN_MIN + /* Default functionality level applied when + * no value is given */ +/* Resetting parameter values */ +#define AT_CFUN_NORST 0 /* do not reset the ME before setting it + * to <fun> power level (default when <rst> + * is not given) */ +#define AT_CFUN_RST 1 /* reset the ME before setting it to <fun> + * power level */ +#define AT_CFUN_RST_DEFAULT AT_CFUN_NORST + /* Default resetting action applied when + * no value is given */ +/* Optional parameter bitmask */ +#define AT_CFUN_FUN_MASK AT_COMMAND_PARAM1 +#define AT_CFUN_RST_MASK AT_COMMAND_PARAM2 + +/* CFUN AT command type */ +typedef struct { + int fun; + int rst; +} at_cfun_t; + +/* CPIN: Enter PIN + * --------------- + * Used to enter MT passwords which are needed before any other + * functionality of the MT can be used + * Parameter command: + * +CPIN=<pin>[,<newpin>] + * <pin> personal identification number + * <newpin> new personal identification number + */ + +/* Optional parameter bitmask */ +#define AT_CPIN_NEWPIN_MASK AT_COMMAND_PARAM2 + +/* CPIN AT command type */ +typedef struct { +#define AT_CPIN_SIZE USER_PIN_SIZE /* Number of characters in pin parameter */ + char pin[AT_CPIN_SIZE+1]; + char newpin[AT_CPIN_SIZE+1]; +} at_cpin_t; + +/* CSQ: Signal quality + * ------------------- + * Returns received signal strength indication and channel bit error rate + * from the Mobile Equipment + * Action command: + * no parameters + */ + +/* CSQ AT command type */ +#define AT_COMMAND_CSQ_MASK AT_COMMAND_NO_PARAM +typedef struct at_csq_s {} at_csq_t; + +/* CESQ: Extented signal quality + * ----------------------------- + * Returns received signal quality parameters. + * Action command: + * no parameters + */ + +/* CESQ AT command type */ +#define AT_COMMAND_CESQ_MASK AT_COMMAND_NO_PARAM +typedef struct at_cesq_s {} at_cesq_t; + +/* CLAC: List all available AT commands + * ------------------------------------ + * Returns one or more lines of AT Commands that are available for the user. + * Action command: + * no parameters + */ + +/* CLAC AT command type */ +#define AT_COMMAND_CLAC_MASK AT_COMMAND_NO_PARAM +typedef struct at_clac_s {} at_clac_t; + +/* + * ========================= + * Mobile Termination errors + * ========================= + */ +/* + * CMEE: Report mobile termination error + * ------------------------------------- + * Disables or enables the use of final result code +CME ERROR: <err> as an + * indication of an error relating to the functionality of the MT. + * <n> = 0, disables result code and displays ERROR instead. + * <n> = 1, enables result code and displays numeric <err> + * <n> = 2, enables result code and displays verbose <err> + * Parameter command: + * +CMEE=[<n>] + * <n> numeric parameter + */ + +/* Numeric parameter values */ +#define AT_CMEE_OFF 0 /* disable result code */ +#define AT_CMEE_NUMERIC 1 /* enable numeric result code */ +#define AT_CMEE_VERBOSE 2 /* enable verbose result code */ +#define AT_CMEE_N_MIN AT_CMEE_OFF + /* Minimum value of supported numeric parameter */ +#define AT_CMEE_N_MAX AT_CMEE_VERBOSE + /* Maximum value of supported numeric parameter */ +#define AT_CMEE_N_DEFAULT AT_CMEE_OFF + /* Default value of supported numeric parameter */ + +/* Optional parameter bitmask */ +#define AT_CMEE_N_MASK AT_COMMAND_PARAM1 + +/* CMEE AT command type */ +typedef struct { + int n; +} at_cmee_t; + +/* + * ================================ + * Network service related commands + * ================================ + */ +/* CNUM: Subscriber number + * ----------------------- + * Returns the MSISDNs related to the subscriber. + * Action command: + * no parameters + */ + +/* CNUM AT command type */ +#define AT_COMMAND_CNUM_MASK AT_COMMAND_NO_PARAM +typedef struct at_cnum_s {} at_cnum_t; + +/* CLCK: Facility lock + * ------------------- + * Used to lock, unlock or interrogate a MT or a network facility <fac>. + * Action command: + * +CLCK=<fac>,<mode>[,<passwd>] + * <fac> facility value + * <mode> operation mode + * <passwd> password (pin code) + */ + +/* Facility values */ +#define AT_CLCK_SC "SC" /* SIM lock/unlock */ + +/* Operation mode */ +#define AT_CLCK_UNLOCK 0 /* Unlock (enable) a service */ +#define AT_CLCK_LOCK 1 /* Lock (disable) a service */ +#define AT_CLCK_STATUS 2 /* Query the status of a network service */ + +/* Optional parameter bitmask */ +#define AT_CLCK_PASSWD_MASK AT_COMMAND_PARAM3 + +/* CLCK AT command type */ +typedef struct { +#define AT_CLCK_FAC_SIZE 2 + char fac[AT_CLCK_FAC_SIZE+1]; + int mode; +#define AT_CLCK_PASSWD_SIZE USER_PIN_SIZE + char passwd[AT_CLCK_PASSWD_SIZE+1]; +} at_clck_t; + +/* COPS: PLMN selection + * -------------------- + * Forces an attempt to select and register the GSM/UMTS/EPS network operator + * using the SIM/USIM card installed in the currently selected card slot. + * Parameter command: + * +COPS=[<mode>[,<format>[,<oper>[,<AcT>]]]] + * <mode> operation mode of the network selection + * <format> representation format of the network operator + * <oper> APN operator identifier + * <AcT> access technology + */ + +/* Network selection operation modes */ +#define AT_COPS_AUTO 0 /* automatic mode */ +#define AT_COPS_MANUAL 1 /* manual mode */ +#define AT_COPS_DEREG 2 /* deregister from network */ +#define AT_COPS_FORMAT 3 /* set only <format> for read command +COPS? */ +#define AT_COPS_MANAUTO 4 /* manual/automatic mode; if manual selection + * fails, automatic mode is entered */ +#define AT_COPS_MODE_DEFAULT AT_COPS_AUTO + /* Default operation mode applied when no + * value is given */ +/* Representation formats */ +#define AT_COPS_LONG NET_FORMAT_LONG /* long format alphanumeric */ +#define AT_COPS_SHORT NET_FORMAT_SHORT /* short format alphanumeric */ +#define AT_COPS_NUM NET_FORMAT_NUM /* numeric */ +#define AT_COPS_FORMAT_MIN AT_COPS_LONG + /* Minimum value of supported representation + * format */ +#define AT_COPS_FORMAT_MAX AT_COPS_NUM + /* Maximum value of supported representation + * format */ +#define AT_COPS_FORMAT_DEFAULT AT_COPS_LONG + /* Default representation format applied when + * no value is given */ +/* Access technology indicators */ +#define AT_COPS_GSM NET_ACCESS_GSM /* GSM */ +#define AT_COPS_COMPACT NET_ACCESS_COMPACT /* GSM Compact */ +#define AT_COPS_UTRAN NET_ACCESS_UTRAN /* UTRAN */ +#define AT_COPS_EGPRS NET_ACCESS_EGPRS /* GSM w/EGPRS */ +#define AT_COPS_HSDPA NET_ACCESS_HSDPA /* UTRAN w/HSDPA */ +#define AT_COPS_HSUPA NET_ACCESS_HSUPA /* UTRAN w/HSUPA */ +#define AT_COPS_HSDUPA NET_ACCESS_HSDUPA /* w/HSDPA and HSUPA */ +#define AT_COPS_EUTRAN NET_ACCESS_EUTRAN /* E-UTRAN */ +#define AT_COPS_ACT_MIN AT_COPS_GSM + /* Minimum value of supported access + * technology */ +#define AT_COPS_ACT_MAX AT_COPS_EUTRAN + /* Maximum value of supported access + * technology */ +#define AT_COPS_ACT_DEFAULT AT_COPS_GSM + /* Default access technology applied when + * no value is given */ + +/* Optional parameter bitmask */ +#define AT_COPS_MODE_MASK AT_COMMAND_PARAM1 +#define AT_COPS_FORMAT_MASK AT_COMMAND_PARAM2 +#define AT_COPS_OPER_MASK AT_COMMAND_PARAM3 +#define AT_COPS_ACT_MASK AT_COMMAND_PARAM4 + +/* COPS AT command type */ +typedef struct { + int mode; + int format; +#define AT_COPS_NUM_SIZE NET_FORMAT_NUM_SIZE + /* Size of numeric representation format */ +#define AT_COPS_LONG_SIZE NET_FORMAT_LONG_SIZE + /* Size of long alphanumeric representation format */ +#define AT_COPS_SHORT_SIZE NET_FORMAT_SHORT_SIZE + /* Size of short alphanumeric representation format */ + network_plmn_t plmn; + int AcT; +} at_cops_t; + +/* CREG: network registration + * -------------------------- + * When <n>=1, returns +CREG: <stat>, the Mobile Equipment's circuit mode + * network registration status in GERA/UTRA/E-UTRA Network. + * When <n>=2, returns +CREG: <stat>[,<lac>,<ci>[,<AcT>]], the Mobile + * Equipment's circuit mode network registration status and location information + * in GERA/UTRA/E-UTRA Network. + * Parameter command: + * +CREG=[<n>] + * <n> numeric parameter + */ + +/* Numeric parameter values */ +#define AT_CREG_OFF 0 /* disable network registration unsolicited + * result code */ +#define AT_CREG_ON 1 /* enable network registration unsolicited + * result code +CREG: <stat> */ +#define AT_CREG_BOTH 2 /* enable network registration and location + * information unsolicited result code + * +CREG: <stat>[,<lac>,<ci>[,<AcT>]] */ +#define AT_CREG_N_MIN AT_CREG_OFF + /* Minimum value of supported unsolicited + * result code */ +#define AT_CREG_N_MAX AT_CREG_BOTH + /* Maximum value of supported unsolicited + * result code */ +#define AT_CREG_N_DEFAULT AT_CREG_OFF + /* Default unsolicited result code applied + * when no value is given */ + +/* Optional parameter bitmask */ +#define AT_CREG_N_MASK AT_COMMAND_PARAM1 + +/* CREG AT command type */ +typedef struct { + int n; +} at_creg_t; + +/* + * ========================== + * Commands for Packet Domain + * ========================== + */ +/* CGATT: EPS service attach/detach + * -------------------------------- + * Used to attach the MT to, or detach the MT from, the EPS service. + * Action command (with optional parameters): + * +CGATT=[<state>] + * <state> numeric parameter that indicates the state of EPS attachment + */ + +/* PS attachment status */ +#define AT_CGATT_DETACHED 0 /* To detach from EPS service */ +#define AT_CGATT_ATTACHED 1 /* To attach from EPS service */ +#define AT_CGATT_STATE_MIN AT_CGATT_DETACHED + /* Minimum value of EPS attachment code */ +#define AT_CGATT_STATE_MAX AT_CGATT_ATTACHED + /* Maximum value of EPS attachment code */ + +/* Optional parameter bitmask */ +#define AT_CGATT_STATE_MASK AT_COMMAND_PARAM1 + +/* CGATT AT command type */ +typedef struct { + int state; +} at_cgatt_t; + +/* CGREG: GPRS network registration status + * --------------------------------------- + * When <n>=1, returns +CGREG: <stat>, the Mobile Equipment's GPRS network + * registration status in GERA/UTRA Network. + * When <n>=2, returns +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]], the Mobile + * Equipment's GPRS network registration status and location information in + * GERA/UTRA Network. + * Parameter command: + * +CGREG=[<n>] + * <n> numeric parameter + */ + +/* Numeric parameter values */ +#define AT_CGREG_OFF 0 /* disable network registration unsolicited + * result code */ +#define AT_CGREG_ON 1 /* enable network registration unsolicited + * result code +CGREG: <stat> */ +#define AT_CGREG_BOTH 2 /* enable network registration and location + * information unsolicited result code + * +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]] */ +#define AT_CGREG_N_MIN AT_CGREG_OFF + /* Minimum value of supported unsolicited + * result code */ +#define AT_CGREG_N_MAX AT_CGREG_BOTH + /* Maximum value of supported unsolicited + * result code */ +#define AT_CGREG_N_DEFAULT AT_CGREG_OFF + /* Default unsolicited result code applied + * when no value is given */ + +/* Optional parameter bitmask */ +#define AT_CGREG_N_MASK AT_COMMAND_PARAM1 + +/* CGREG AT command type */ +typedef struct { + int n; +} at_cgreg_t; + +/* CEREG: EPS network registration status + * -------------------------------------- + * When <n>=1, returns +CEREG: <stat>, the Mobile Equipment's EPS services + * registration status in EUTRA Network. + * When <n>=2, returns +CEREG: <stat>[,<tac>,<ci>[,<AcT>]], the Mobile + * Equipment's EPS services registration status and location information in + * EUTRA Network. + * Parameter command: + * +CEREG=[<n>] + * <n> numeric parameter + */ + +/* Numeric parameter values */ +#define AT_CEREG_OFF 0 /* disable network registration unsolicited + * result code */ +#define AT_CEREG_ON 1 /* enable network registration unsolicited + * result code +CEREG: <stat> */ +#define AT_CEREG_BOTH 2 /* enable network registration and location + * information unsolicited result code + * +CEREG: <stat>[,<tac>,<ci>[,<AcT>]] */ +#define AT_CEREG_N_MIN AT_CEREG_OFF + /* Minimum value of supported unsolicited + * result code */ +#define AT_CEREG_N_MAX AT_CEREG_BOTH + /* Maximum value of supported unsolicited + * result code */ +#define AT_CEREG_N_DEFAULT AT_CEREG_OFF + /* Default unsolicited result code applied + * when no value is given */ + +/* Optional parameter bitmask */ +#define AT_CEREG_N_MASK AT_COMMAND_PARAM1 + +/* CEREG AT command type */ +typedef struct { + int n; +} at_cereg_t; + +/* CGDCONT: Define PDP Context + * --------------------------- + * Specifies PDP context parameter values for a PDP context identified by + * the (local) context identification parameter, <cid>. + * Parameter command: + * +CGDCONT=[<cid>[,<PDP_type>[,<APN>[,<PDP_addr>[,<d_comp>[,<h_comp> + * [,<IPv4AddrAlloc>[,<emergency indication>[,<P-CSCF_discovery> + * [,<IM_CN_Signalling_Flag_Ind>]]]]]]]]]] + * <cid> a numeric parameter which specifies a particular PDP + * context definition + * <PDP_type> type of packet data protocol ("IP", "IPV6", "IPV4V6") + * <APN> Access Point logical Name + * <PDP_addr> Mobile Equipment PDP address (not applicable to EPS) + * <d_comp> PDP data compression parameter + * <h_comp> PDP header compression parameter + * <IPv4AddrAlloc> IPv4 address allocation parameter + * <emergency indication> emergency bearer services support indication + * <P-CSCF_discovery> P-CSCF address discovery parameter + * <IM_CN_Signalling_Flag_Ind> IM CN subsystem-related signalling + * support indication + */ + +/* PDP context identifier */ +#define AT_CGDCONT_CID_MIN 1 /* Minimum value of context identifier */ +#define AT_CGDCONT_CID_DEFAULT AT_CGDCONT_CID_MIN +/* PDP data compression parameter values */ +#define AT_CGDCONT_D_COMP_OFF 0 /* PDP data compression is disabled */ +#define AT_CGDCONT_D_COMP_ON 1 /* manufacturer preferred compression */ +#define AT_CGDCONT_D_COMP_V42B 2 /* V.42bis */ +#define AT_CGDCONT_D_COMP_V44 3 /* V.44 */ +#define AT_CGDCONT_D_COMP_MIN AT_CGDCONT_D_COMP_OFF +#define AT_CGDCONT_D_COMP_MAX AT_CGDCONT_D_COMP_V44 +#define AT_CGDCONT_D_COMP_DEFAULT AT_CGDCONT_D_COMP_OFF +/* PDP header compression parameter values */ +#define AT_CGDCONT_H_COMP_OFF 0 /* PDP header compression is disabled */ +#define AT_CGDCONT_H_COMP_ON 1 /* manufacturer preferred compression */ +#define AT_CGDCONT_H_COMP_1144 2 /* RFC1144 (applicable for SNDCP only) */ +#define AT_CGDCONT_H_COMP_2507 3 /* RFC2507 */ +#define AT_CGDCONT_H_COMP_3095 4 /* RFC3095 (applicable for PDCP only) */ +#define AT_CGDCONT_H_COMP_MIN AT_CGDCONT_H_COMP_OFF +#define AT_CGDCONT_H_COMP_MAX AT_CGDCONT_H_COMP_3095 +#define AT_CGDCONT_H_COMP_DEFAULT AT_CGDCONT_H_COMP_OFF +/* IPv4AddrAlloc parameter values */ +#define AT_CGDCONT_IPV4_NAS 0 /* IPv4 Address Allocation through NAS + * Signalling */ +#define AT_CGDCONT_IPV4_DHCP 1 /* IPv4 Address Allocation through DHCP */ +#define AT_CGDCONT_IPV4_MIN AT_CGDCONT_IPV4_NAS +#define AT_CGDCONT_IPV4_MAX AT_CGDCONT_IPV4_DHCP +#define AT_CGDCONT_IPV4_DEFAULT AT_CGDCONT_IPV4_NAS +/* emergency_indication parameter values */ +#define AT_CGDCONT_EBS_OFF 0 /* PDP context is not for emergency bearer + * services */ +#define AT_CGDCONT_EBS_ON 1 /* PDP context is for emergency bearer + * services */ +#define AT_CGDCONT_EBS_MIN AT_CGDCONT_EBS_OFF +#define AT_CGDCONT_EBS_MAX AT_CGDCONT_EBS_ON +#define AT_CGDCONT_EBS_DEFAULT AT_CGDCONT_EBS_OFF +/* P_CSCF_discovery parameter values */ +#define AT_CGDCONT_PCSCF_OFF 0 /* Preference of P-CSCF address discovery + * not influenced by +CGDCONTPDP */ +#define AT_CGDCONT_PCSCF_NAS 1 /* Preference of P-CSCF address discovery + * through NAS Signalling */ +#define AT_CGDCONT_PCSCF_DHCP 2 /* Preference of P-CSCF address discovery + * through DHCP */ +#define AT_CGDCONT_PCSCF_MIN AT_CGDCONT_PCSCF_OFF +#define AT_CGDCONT_PCSCF_MAX AT_CGDCONT_PCSCF_DHCP +#define AT_CGDCONT_PCSCF_DEFAULT AT_CGDCONT_PCSCF_OFF +/* IM_CN_Signalling_Flag_Ind parameter values */ +#define AT_CGDCONT_IM_CN_OFF 0 /* UE indicates that the PDP context is not + * for IM CN subsystem-related signalling + * only */ +#define AT_CGDCONT_IM_CN_ON 1 /* UE indicates that the PDP context is for + * IM CN subsystem-related signalling + * only */ +#define AT_CGDCONT_IM_CM_MIN AT_CGDCONT_IM_CN_OFF +#define AT_CGDCONT_IM_CM_MAX AT_CGDCONT_IM_CN_ON +#define AT_CGDCONT_IM_CM_DEFAULT AT_CGDCONT_IM_CN_OFF + +/* Optional parameter bitmask */ +#define AT_CGDCONT_CID_MASK AT_COMMAND_PARAM1 +#define AT_CGDCONT_PDP_TYPE_MASK AT_COMMAND_PARAM2 +#define AT_CGDCONT_APN_MASK AT_COMMAND_PARAM3 +#define AT_CGDCONT_PDP_ADDR_MASK AT_COMMAND_PARAM4 +#define AT_CGDCONT_D_COMP_MASK AT_COMMAND_PARAM5 +#define AT_CGDCONT_H_COMP_MASK AT_COMMAND_PARAM6 +#define AT_CGDCONT_IPV4ADDRALLOC_MASK AT_COMMAND_PARAM7 +#define AT_CGDCONT_EMERGECY_INDICATION_MASK AT_COMMAND_PARAM8 +#define AT_CGDCONT_P_CSCF_DISCOVERY_MASK AT_COMMAND_PARAM9 +#define AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK AT_COMMAND_PARAM10 + +/* CGDCONT AT command type */ +typedef struct { + int cid; +#define AT_CGDCONT_PDP_SIZE 6 /* PDP_type may be "IP", "IPV6", "IPV4V6" */ + char PDP_type[AT_CGDCONT_PDP_SIZE+1]; +#define AT_CGDCONT_APN_SIZE 100 /* number of characters in APN parameter */ + char APN[AT_CGDCONT_APN_SIZE+1]; +#define AT_CGDCONT_ADDR_SIZE 63 /* number of characters in PDP addr + * parameter (IPv6 address notation) */ + char PDP_addr[AT_CGDCONT_ADDR_SIZE+1]; /* Does not apply to EPS */ + int d_comp; + int h_comp; + int IPv4AddrAlloc; + int emergency_indication; + int P_CSCF_discovery; + int IM_CN_Signalling_Flag_Ind; +} at_cgdcont_t; + +/* CGACT: PDP context activate or deactivate + * ----------------------------------------- + * Used to activate or deactivate the specified PDP context(s). + * Action command (with optional parameters): + * +CGACT=[<state>[,<cid>[,<cid>[,...]]]] + * <state> numeric parameter that indicates the state of PDP context + * activation + * <cid> a numeric parameter which specifies a particular PDP context + * definition + */ + +/* PDP context identifier */ +#define AT_CGACT_CID_MIN 1 /* Minimum value of context identifier */ +/* PDP context activation status */ +#define AT_CGACT_DEACTIVATED 0 /* To deactivate the PDP context */ +#define AT_CGACT_ACTIVATED 1 /* To activate the PDP context */ +#define AT_CGACT_STATE_MIN AT_CGACT_DEACTIVATED +#define AT_CGACT_STATE_MAX AT_CGACT_ACTIVATED +#define AT_CGACT_STATE_DEFAULT AT_CGACT_DEACTIVATED + +/* Optional parameter bitmask */ +#define AT_CGACT_STATE_MASK AT_COMMAND_PARAM1 +#define AT_CGACT_CID_MASK AT_COMMAND_PARAM2 + +/* CGACT AT command type */ +typedef struct { + int state; + int cid; +} at_cgact_t; + +/* CGPADDR: Show PDP address(es) + * ----------------------------- + * Returns a list of PDP addresses for the specified context identifiers. + * +CGPADDR=[<cid>[,<cid>[,...]]] + * <cid> a numeric parameter which specifies a particular PDP + * context definition + */ + +/* PDP context identifier */ +#define AT_CGPADDR_CID_MIN 1 /* Minimum value of context identifier */ + +/* Optional parameter bitmask */ +#define AT_CGPADDR_CID_MASK AT_COMMAND_PARAM1 + +/* CGPADDR AT command type */ +typedef struct { + int cid; +} at_cgpaddr_t; + +/* + * ================================= + * Global AT command type definition + * ================================= + */ + +/* AT command type */ +typedef struct { + at_command_id_t id; /* AT command identifier */ + at_command_type_t type; /* AT command type */ + int mask; /* Optional parameter bitmask */ + union { + at_cgsn_t cgsn; + at_cgmm_t cgmm; + at_cgmr_t cgmr; + at_cimi_t cimi; + at_cfun_t cfun; + at_cpin_t cpin; + at_csq_t csq; + at_cesq_t cesq; + at_clac_t clac; + at_cmee_t cmee; + at_cnum_t cnum; + at_clck_t clck; + at_cops_t cops; + at_cgatt_t cgatt; + at_creg_t creg; + at_cgreg_t cgreg; + at_cereg_t cereg; + at_cgdcont_t cgdcont; + at_cgact_t cgact; + at_cgpaddr_t cgpaddr; + } command; +} at_command_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: at_command_decode() ** + ** ** + ** Description: Parses AT command line and accordingly fills data struc- ** + ** ture. The main functions of the AT command parser are: ** + ** - check the AT command syntax ** + ** - fill parameter values into the data structure ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing AT com- ** + ** mand line ** + ** length: Number of bytes that should be processed ** + ** Others: None ** + ** ** + ** Outputs: at_command: AT command data structure to be filled ** + ** Return: The number of AT commands successfully ** + ** decoded; RETURNerror if an error occurred ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_command_decode(const char* buffer, int length, at_command_t* at_command); + +/**************************************************************************** + ** ** + ** Name: at_command_get_list() ** + ** ** + ** Description: Returns the list of supported AT commands. ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the ** + ** string representaton of the first AT com- ** + ** mand that is supported by the NAS sublayer ** + ** n_max: Maximum number of AT commands the buffer ** + ** may contain ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of AT commands actually suppor- ** + ** ted by the NAS sublayer ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_command_get_list(const char** buffer, int n_max); + +#endif /* __AT_COMMAND_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.c new file mode 100644 index 0000000000..b631c66d90 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.c @@ -0,0 +1,420 @@ +/***************************************************************************** + +Source at_error.c + +Version 0.1 + +Date 2012/03/12 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines error codes returned when execution of AT command + failed. + +*****************************************************************************/ + +#include "at_error.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <string.h> // strcpy +#include <stdio.h> // sprintf + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +extern int at_response_format_v1; + +/* + * Result code suppression indicator (set by ATQ0 and ATQ1) + * ------------------------------------------------------- + * FALSE - Result codes are transmitted to the user application + * TRUE - Result codes are suppressed and not transmitted + */ +int at_error_code_suppression_q1 = FALSE; + +/* + * Verbose mode indicator (set by ATV0, ATV1 and AT+CMEE) + * ------------------------------------------------------ + */ +at_error_format_t at_error_format = AT_ERROR_OFF; + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * General errors + * -------------- + */ +static const char * _at_error_str[] = { + "phone failure", + "no connection to phone", + "phone-adaptor link reserved", + "operation not allowed", + "operation not supported", + "PH-SIM PIN required", + "PH-FSIM PIN required", + "PH-FSIM PUK required", + NULL, + NULL, + "SIM not inserted", + "SIM PIN required", + "SIM PUK required", + "SIM failure", + "SIM busy", + "SIM wrong", + "incorrect password", + "SIM PIN2 required", + "SIM PUK2 required", + NULL, + "memory full", + "invalid index", + "not found", + "memory failure", + "text string too long", + "invalid characters in text string", + "dial string too long", + "invalid characters in dial string", + NULL, + NULL, + "no network service", + "network timeout", + "network not allowed - emergency calls only", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "network personalization PIN required", + "network personalization PUK required", + "network subset personalization PIN required", + "network subset personalization PUK required", + "service provider personalization PIN required", + "service provider personalization PUK required", + "corporate personalization PIN required", + "corporate personalization PUK required", + "hidden key required", + "EAP method not supported", + "Incorrect parameters", +}; + +/* + * GPRS-related errors + * ------------------- + */ +static const char* _at_error_gprs[] = { + "Illegal MS", + NULL, + NULL, + "Illegal ME", + "GPRS services not allowed", + NULL, + NULL, + NULL, + "PLMN not allowed", + "Location area not allowed", + "Roaming not allowed in this location area", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "service option not supported", + "requested service option not subscribed", + "service option temporarily out of order", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "unspecified GPRS error", + "PDP authentication failure", + "invalid mobile class", + "Last PDN disconnection not allowed", +}; + +/* + * VBS / VGCS and eMLPP -related errors + * ------------------------------------ + */ +static const char* _at_error_vbs[] = { +/* 151 "VBS/VGCS not supported by the network" */ + "No service subscription on SIM", + "No subscription for group ID", + "Group Id not activated on SIM", + "No matching notification", + "VBS/VGCS call already present", + "Congestion", + "Network failure", + "Uplink busy", + "No access rights for SIM file", + "No subscription for priority", + "operation not applicable or not possible", + "Group Id prefixes not supported", + "Group Id prefixes not usable for VBS", + "Group Id prefix value invalid", +}; + +/* Returns the verbose value of AT command error */ +static const char* _at_error_to_string(int error); + +static int _at_error_encode_ok(char* buffer); +static int _at_error_encode_ko(char* buffer, at_error_type_t type, int error); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: at_error_set_format() ** + ** ** + ** Description: Sets the format of the error code ** + ** ** + ** Inputs: format: Format of the error code ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: at_error_format ** + ** ** + ***************************************************************************/ +void at_error_set_format(at_error_format_t format) +{ + LOG_FUNC_IN; + + at_error_format = format; + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: at_error_get_format() ** + ** ** + ** Description: Gets the format of the error code ** + ** ** + ** Inputs: format: Format of the error code ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: at_error_format ** + ** ** + ***************************************************************************/ +at_error_format_t at_error_get_format(void) +{ + LOG_FUNC_IN; + + LOG_FUNC_RETURN (at_error_format); +} + +/**************************************************************************** + ** ** + ** Name: at_error_encode() ** + ** ** + ** Description: Encodes result code returned when AT command has been ** + ** processed. Result code can be OK or 0, if the command ** + ** succeed, ERROR or 4, if the command failed; depending of ** + ** the response format selected by the user. ** + ** ** + ** Inputs type: Type of the error code to encode ** + ** error: Error code to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters that have been ** + ** successfully encoded; ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_error_encode(char* buffer, at_error_type_t type, int error) +{ + LOG_FUNC_IN; + + int bytes = 0; + + /* Result code suppression (ATQ0, ATQ1) */ + if (at_error_code_suppression_q1) { + LOG_FUNC_RETURN (0); + } + + if (type == AT_ERROR_OK) { + /* Encode success return code */ + bytes = _at_error_encode_ok(buffer); + } + else { + /* Encode failure return code */ + bytes = _at_error_encode_ko(buffer, type, error); + } + + LOG_FUNC_RETURN (bytes); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _at_error_encode_ok() ** + ** ** + ** Description: Encodes AT command success result code message ** + ** ** + ** Inputs None ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters that have been ** + ** successfully encoded; ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_error_encode_ok(char* buffer) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer + offset, "OK\r\n"); + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_error_encode_ko() ** + ** ** + ** Description: Encodes AT command error code message ** + ** ** + ** Inputs type: Type of the error code to encode ** + ** error: Error code to encode ** + ** Others: at_error_format ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters that have been ** + ** successfully encoded; ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_error_encode_ko(char* buffer, at_error_type_t type, int error) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + + /* Result code is disabled */ + if (at_error_format == AT_ERROR_OFF) { + offset += sprintf(buffer + offset, "ERROR\r\n"); + } + else + { + /* Error related to execution of AT command operation */ + if (type == AT_ERROR_CME) { + offset += sprintf(buffer + offset, "+CME ERROR: "); + } + + /* Result code is enabled for numeric values */ + if (at_error_format == AT_ERROR_NUMERIC) { + offset += sprintf(buffer + offset, "%d\r\n", error); + } + + /* Result code is enabled for verbose values */ + else { + const char* error_str = _at_error_to_string(error); + if (error_str != NULL) { + offset += sprintf(buffer + offset, "%s\r\n", error_str); + } + else { + /* Error code is not valid */ + offset += sprintf(buffer + offset, "invalid error code\r\n"); + } + } + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: at_error_to_string() ** + ** ** + ** Description: Returns the verbose value of AT command error ** + ** ** + ** Inputs: error: AT command error identifier ** + ** Others: None ** + ** ** + ** Outputs: Return: The error's verbose value ** + ** NULL if the error code is not valid ** + ** Others: None ** + ** ** + ***************************************************************************/ +static const char* _at_error_to_string(int error) +{ + if (error < AT_ERROR_LAST_GENERAL_ERROR + 1) + { + /* General errors */ + if (error > AT_ERROR_FIRST_GENERAL_ERROR - 1) { + return _at_error_str[error]; + } + else { + return NULL; + } + } + else if (error < AT_ERROR_LAST_GPRS_RELATED_ERROR + 1) + { + /* GPRS-related errors */ + if (error > AT_ERROR_FIRST_GPRS_RELATED_ERROR - 1) { + return _at_error_gprs[error - AT_ERROR_FIRST_GPRS_RELATED_ERROR]; + } + else { + return NULL; + } + } + else if (error < AT_ERROR_LAST_VBS_RELATED_ERROR + 1) + { + /* VBS / VGCS and eMLPP -related errors */ + if (error > AT_ERROR_FIRST_VBS_RELATED_ERROR - 1) { + return _at_error_vbs[error - AT_ERROR_FIRST_VBS_RELATED_ERROR]; + } + else { + return NULL; + } + } + + return NULL; +} diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.h b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.h new file mode 100644 index 0000000000..58554499fb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_error.h @@ -0,0 +1,173 @@ +/***************************************************************************** + +Source at_error.h + +Version 0.1 + +Date 2012/03/12 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines error codes returned when execution of AT command + failed. + +*****************************************************************************/ +#ifndef __AT_ERROR_H__ +#define __AT_ERROR_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Cause code used to notify that the NAS procedure has been successfully + * processed + */ +#define AT_ERROR_SUCCESS (-1) + +/* + * General errors + * -------------- + */ +#define AT_ERROR_FIRST_GENERAL_ERROR AT_ERROR_PHONE_FAILURE + +#define AT_ERROR_PHONE_FAILURE 0 +#define AT_ERROR_NO_CONNECTION_TO_PHONE 1 +#define AT_ERROR_PHONE_ADAPTOR_LINK_RESERVED 2 +#define AT_ERROR_OPERATION_NOT_ALLOWED 3 +#define AT_ERROR_OPERATION_NOT_SUPPORTED 4 +#define AT_ERROR_PHSIM_PIN_REQUIRED 5 +#define AT_ERROR_PHFSIM_PIN_REQUIRED 6 +#define AT_ERROR_PHFSIM_PUK_REQUIRED 7 + +#define AT_ERROR_SIM_NOT_INSERTED 10 +#define AT_ERROR_SIM_PIN_REQUIRED 11 +#define AT_ERROR_SIM_PUK_REQUIRED 12 +#define AT_ERROR_SIM_FAILURE 13 +#define AT_ERROR_SIM_BUSY 14 +#define AT_ERROR_SIM_WRONG 15 +#define AT_ERROR_INCORRECT_PASSWD 16 +#define AT_ERROR_SIM_PIN2_REQUIRED 17 +#define AT_ERROR_SIM_PUK2_REQUIRED 18 + +#define AT_ERROR_MEMORY_FULL 20 +#define AT_ERROR_INVALID_INDEX 21 +#define AT_ERROR_NOT_FOUND 22 +#define AT_ERROR_MEMORY_FAILURE 23 +#define AT_ERROR_TEXT_STRING_TOO_LONG 24 +#define AT_ERROR_TEXT_STRING_INVALID_CHAR 25 +#define AT_ERROR_DIAL_STRING_TOO_LONG 26 +#define AT_ERROR_DIAL_STRING_INVALID_CHAR 27 + +#define AT_ERROR_NO_NETWORK_SERVICE 30 +#define AT_ERROR_TIMEOUT 31 +#define AT_ERROR_NETWORK_NOT_ALLOWED 32 + +#define AT_ERROR_NETWORK_PERSO_PIN_REQUIRED 40 +#define AT_ERROR_NETWORK_PERSO_PUK_REQUIRED 41 +#define AT_ERROR_NETWORK_SUBNET_PERSO_PIN_REQUIRED 42 +#define AT_ERROR_SUBNET_PERSO_PUK_REQUIRED 43 +#define AT_ERROR_PROVIDER_PERSO_PIN_REQUIRED 44 +#define AT_ERROR_PROVIDER_PERSO_PUK_REQUIRED 45 +#define AT_ERROR_CORPORATE_PERSO_PIN_REQUIRED 46 +#define AT_ERROR_CORPORATE_PERSO_PUK_REQUIRED 47 +#define AT_ERROR_HIDDEN_KEY_REQUIRED 48 +#define AT_ERROR_EAP_METHOD_NOT_SUPPORTED 49 +#define AT_ERROR_INCORRECT_PARAMETERS 50 + +#define AT_ERROR_LAST_GENERAL_ERROR AT_ERROR_INCORRECT_PARAMETERS + +#define AT_ERROR_UNKNOWN 100 + +/* + * GPRS-related errors + * ------------------- + */ + /* Errors related to a failure to perform an attach */ +#define AT_ERROR_FIRST_GPRS_RELATED_ERROR AT_ERROR_ILLEGAL_MS + +#define AT_ERROR_ILLEGAL_MS 103 +#define AT_ERROR_ILLEGAL_ME 106 +#define AT_ERROR_GPRS_NOT_ALLOWED 107 +#define AT_ERROR_PLMN_NOT_ALLOWED 111 +#define AT_ERROR_LOCATION_AREA_NOT_ALLOWED 112 +#define AT_ERROR_ROAMING_NOT_ALLOWED 113 + /* Errors related to a failure to activate a context */ +#define AT_ERROR_OPTION_NOT_SUPPORTED 132 +#define AT_ERROR_OPTION_NOT_SUBSCRIBED 133 +#define AT_ERROR_OPTION_TEMPORARILY_OUT_OF_ORDER 134 +#define AT_ERROR_PDP_AUTHENTICATION_FAILURE 149 + /* Errors related to a failure to disconnect a PDN */ +#define AT_ERROR_LAST_PDP_DISCONNECT_NOT_ALLOWED 151 + /* Other GPRS errors */ +#define AT_ERROR_UNSPECIFIED_GPRS_ERROR 148 +#define AT_ERROR_INVALID_MOBILE_CLASS 150 + +#define AT_ERROR_LAST_GPRS_RELATED_ERROR AT_ERROR_LAST_PDP_DISCONNECT_NOT_ALLOWED + +/* + * VBS / VGCS and eMLPP -related errors + * ------------------------------------ + */ +#define AT_ERROR_FIRST_VBS_RELATED_ERROR AT_ERROR_NO_SERVICE_SUBSCRIPTION_ON_SIM + +/* AT_ERROR_VBS_VGCS_NOT_SUPPORTED=151,*/ /* !!! Conflict with AT_ERROR_LAST_PDP_DISCONNECT_NOT_ALLOWED !!! */ +#define AT_ERROR_NO_SERVICE_SUBSCRIPTION_ON_SIM 152 +#define AT_ERROR_NO_SUBSCRIPTION_FOR_GROUP_ID 153 +#define AT_ERROR_GROUP_ID_NOT_ACTIVATED_ON_SIM 154 +#define AT_ERROR_NO_MATCHING_NOTIFICATION 155 +#define AT_ERROR_VBS_VGCS_CALL_ALREADY_PRESENT 156 +#define AT_ERROR_CONGESTION 157 +#define AT_ERROR_NETWORK_FAILURE 158 +#define AT_ERROR_UPLINK_BUSY 159 +#define AT_ERROR_NO_ACCESS_RIGHTS_FOR_SIM_FILE 160 +#define AT_ERROR_NO_SUBSCRIPTION_FOR_PRIORITY 161 +#define AT_ERROR_OPERATION_NOT_APPLICABLE_OR_NOT_POSSIBLE 162 +#define AT_ERROR_GROUP_ID_PREFIXES_NOT_SUPPORTED 163 +#define AT_ERROR_GROUP_ID_PREFIXES_NOT_USABLE_FOR_VBS 164 +#define AT_ERROR_GROUP_ID_PREFIX_VALUE_INVALID 165 + +#define AT_ERROR_LAST_VBS_RELATED_ERROR AT_ERROR_GROUP_ID_PREFIX_VALUE_INVALID + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Error type identifiers + */ +typedef enum { + AT_ERROR_NONE, /* No error code displayed */ + AT_ERROR_OK, /* AT command successfully processed */ + AT_ERROR_SYNTAX, /* AT command syntax error */ + AT_ERROR_CME, /* Error related to execution of AT command + * operation */ +} at_error_type_t; + +/* + * Error code format identifiers + */ +typedef enum { + AT_ERROR_OFF, /* disable result code and use ERROR instead */ + AT_ERROR_NUMERIC, /* enable result code and use numeric error values */ + AT_ERROR_VERBOSE, /* enable result code and use verbose error values */ +} at_error_format_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void at_error_set_format(at_error_format_t format); +at_error_format_t at_error_get_format(void); + +int at_error_encode(char* buffer, at_error_type_t type, int error); + +#endif /* __AT_ERROR_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.c new file mode 100644 index 0000000000..0dbea18911 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.c @@ -0,0 +1,1126 @@ +/***************************************************************************** + +Source at_response.c + +Version 0.1 + +Date 2012/03/13 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines structure of the AT command response returned after + completion of AT command processing. + +*****************************************************************************/ + +#include "at_response.h" +#include "nas_log.h" + +#include <stdio.h> // sprintf, snprintf +#include <string.h> // strncpy +#include <assert.h> // assert + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/* + * Response format indicator (set by ATV0 and ATV1) + * ----------------------------------------------- + * TRUE - <CR><LF><text><CR><LF>, <CR><LF><verbose code><CR><LF> + * FALSE - <text><CR><LF>, <numeric code><CR><LF> + */ +int at_response_format_v1 = TRUE; + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static int _at_response_encode_cgsn (char* buffer, const at_response_t* data); +static int _at_response_encode_cgmi (char* buffer, const at_response_t* data); +static int _at_response_encode_cgmm (char* buffer, const at_response_t* data); +static int _at_response_encode_cgmr (char* buffer, const at_response_t* data); +static int _at_response_encode_cimi (char* buffer, const at_response_t* data); +static int _at_response_encode_cfun (char* buffer, const at_response_t* data); +static int _at_response_encode_cpin (char* buffer, const at_response_t* data); +static int _at_response_encode_csq (char* buffer, const at_response_t* data); +static int _at_response_encode_cesq (char* buffer, const at_response_t* data); +static int _at_response_encode_clac (char* buffer, const at_response_t* data); +static int _at_response_encode_cmee (char* buffer, const at_response_t* data); +static int _at_response_encode_cnum (char* buffer, const at_response_t* data); +static int _at_response_encode_clck (char* buffer, const at_response_t* data); +static int _at_response_encode_cops (char* buffer, const at_response_t* data); +static int _at_response_encode_cgatt (char* buffer, const at_response_t* data); +static int _at_response_encode_creg (char* buffer, const at_response_t* data); +static int _at_response_encode_cgreg (char* buffer, const at_response_t* data); +static int _at_response_encode_cereg (char* buffer, const at_response_t* data); +static int _at_response_encode_cgdcont(char* buffer, const at_response_t* data); +static int _at_response_encode_cgact (char* buffer, const at_response_t* data); +static int _at_response_encode_cgpaddr(char* buffer, const at_response_t* data); +static int _at_response_encode_cgev (char* buffer, const at_response_t* data); + +/* Encoding functions for AT command response messages */ +typedef int (*_at_response_encode_function_t) (char* buffer, const at_response_t*); + +static _at_response_encode_function_t _at_response_encode_function[AT_RESPONSE_ID_MAX] = { + NULL, + _at_response_encode_cgsn, /* CGSN */ + _at_response_encode_cgmi, /* CGMI */ + _at_response_encode_cgmm, /* CGMM */ + _at_response_encode_cgmr, /* CGMR */ + _at_response_encode_cimi, /* CIMI */ + _at_response_encode_cfun, /* CFUN */ + _at_response_encode_cpin, /* CPIN */ + _at_response_encode_csq, /* CSQ */ + _at_response_encode_cesq, /* CESQ */ + _at_response_encode_clac, /* CLAC */ + _at_response_encode_cmee, /* CMEE */ + _at_response_encode_cnum, /* CNUM */ + _at_response_encode_clck, /* CLCK */ + _at_response_encode_cops, /* COPS */ + _at_response_encode_creg, /* CREG */ + _at_response_encode_cgatt, /* CGATT */ + _at_response_encode_cgreg, /* CGREG */ + _at_response_encode_cereg, /* CEREG */ + _at_response_encode_cgdcont, /* CGDCONT */ + _at_response_encode_cgact, /* CGACT */ + _at_response_encode_cgpaddr, /* CGPADDR */ + _at_response_encode_cgev, /* CGEV: unsolicited result */ +}; + +/* String representation of Packet Domain events (cf. network_pdn_state_t) */ +static const char* _at_response_event_str[] = { + "UNKNOWN EVENT", + "ME PDN ACT", + "NW PDN DEACT", + "ME PDN DEACT", + "NW ACT", + "ME ACT", + "NW DEACT", + "ME DEACT", +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: at_response_encode() ** + ** ** + ** Description: Encodes AT command response message ** + ** ** + ** Inputs at_response: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters in the buffer ** + ** when data have been successfully encoded; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int at_response_encode(char* buffer, const at_response_t* at_response) +{ + LOG_FUNC_IN; + + int bytes = RETURNerror; + _at_response_encode_function_t encode; + + if (at_response->id < AT_RESPONSE_ID_MAX) + { + /* Call encoding function applicable to the AT command response */ + encode = _at_response_encode_function[at_response->id]; + if (encode != NULL) { + bytes = (*encode)(buffer, at_response); + } + else { + /* Generic encoding: OK, ERROR */ + bytes = 0; + } + } + + LOG_FUNC_RETURN (bytes); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgsn() ** + ** ** + ** Description: Encodes AT CGSN command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgsn(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cgsn_resp_t * cgsn = &(data->response.cgsn); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGSN: %s\r\n", cgsn->sn); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgmi() ** + ** ** + ** Description: Encodes AT CGMI command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgmi(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cgmi_resp_t * cgmi = &(data->response.cgmi); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGMI: %s\r\n", cgmi->manufacturer); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgmm() ** + ** ** + ** Description: Encodes AT CGMM command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgmm(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cgmm_resp_t * cgmm = &(data->response.cgmm); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGMM: %s\r\n", cgmm->model); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgmr() ** + ** ** + ** Description: Encodes AT CGMR command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgmr(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cgmr_resp_t * cgmr = &(data->response.cgmr); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGMR: %s\r\n", cgmr->revision); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cimi() ** + ** ** + ** Description: Encodes AT CIMI command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cimi(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cimi_resp_t * cimi = &(data->response.cimi); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CIMI: %s\r\n", cimi->IMSI); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cfun() ** + ** ** + ** Description: Encodes AT CFUN command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cfun(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + const at_cfun_resp_t * cfun = &(data->response.cfun); + int offset = 0; + + if (data->type == AT_COMMAND_GET) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CFUN: %d\r\n", cfun->fun); + } + else if (data->type == AT_COMMAND_TST) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CFUN: (%d-%d),(%d,%d)\r\n", + AT_CFUN_MIN, AT_CFUN_MAX, AT_CFUN_NORST, AT_CFUN_RST); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cpin() ** + ** ** + ** Description: Encodes AT CPIN command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cpin(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) { + const at_cpin_resp_t * cpin = &(data->response.cpin); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CPIN: %s\r\n", cpin->code); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_csq() ** + ** ** + ** Description: Encodes AT CSQ command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_csq(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + const at_csq_resp_t * csq = &(data->response.csq); + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CSQ: %d,%d\r\n", + csq->rssi, csq->ber); + } + else if (data->type == AT_COMMAND_TST) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CSQ: (%d-%d),(%d-%d)\r\n", + AT_CSQ_RSSI_0, AT_CSQ_RSSI_31, + AT_CSQ_BER_0, AT_CSQ_BER_7); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cesq() ** + ** ** + ** Description: Encodes AT CESQ command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cesq(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + const at_cesq_resp_t * cesq = &(data->response.cesq); + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CESQ: %d,%d,%d,%d,%d,%d\r\n", + cesq->rssi, cesq->ber, cesq->rscp, + cesq->ecno, cesq->rsrq, cesq->rsrp); + } + else if (data->type == AT_COMMAND_TST) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CESQ: (%d-%d),(%d-%d),(%d-%d)," + "(%d-%d),(%d-%d),(%d-%d)\r\n", + AT_CESQ_RSSI_0, AT_CESQ_RSSI_31, + AT_CESQ_BER_0, AT_CESQ_BER_7, + AT_CESQ_RSCP_0, AT_CESQ_RSCP_96, + AT_CESQ_ECNO_0, AT_CESQ_ECNO_49, + AT_CESQ_RSRQ_0, AT_CESQ_RSRQ_34, + AT_CESQ_RSRP_0, AT_CESQ_RSRP_97); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_clac() ** + ** ** + ** Description: Encodes AT CLAC command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_clac(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + const at_clac_resp_t * clac = &(data->response.clac); + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + if (clac->n_acs > 0) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "%s", clac->ac[0]); + for (int i = 1; i < clac->n_acs; i++) { + offset += sprintf(buffer+offset, "\r\n%s", clac->ac[i]); + } + } + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cnum() ** + ** ** + ** Description: Encodes AT CNUM command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cnum(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_ACT) { + const at_cnum_resp_t * cnum = &(data->response.cnum); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CNUM: ,%s,%u\r\n", + cnum->number, cnum->type); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_clck() ** + ** ** + ** Description: Encodes AT CLCK command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_clck(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + const at_clck_resp_t * clck = &(data->response.clck); + int offset = 0; + + if (data->type == AT_COMMAND_SET) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CLCK: %d\r\n", clck->status); + } + else if (data->type == AT_COMMAND_TST) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CLCK: %s\r\n", AT_CLCK_SC); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cops() ** + ** ** + ** Description: Encodes AT COPS command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cops(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cops_get_t * cops = &(data->response.cops.get); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+COPS: %d", cops->mode); + if (data->mask & AT_COPS_RESP_OPER_MASK) + { + /* If <oper> is present <format> must be given */ + assert(data->mask & AT_COPS_RESP_FORMAT_MASK); + offset += sprintf(buffer+offset, ",%d", cops->format); + if (cops->format == AT_COPS_LONG) { + offset += sprintf(buffer+offset, ",%s", + (char*)cops->plmn.id.alpha_long); + } + else if (cops->format == AT_COPS_SHORT) { + offset += sprintf(buffer+offset, ",%s", + (char*)cops->plmn.id.alpha_short); + } + else if (cops->format == AT_COPS_NUM) { + offset += sprintf(buffer+offset, ",%s", + (char*)cops->plmn.id.num); + } + } + if (data->mask & AT_COPS_RESP_ACT_MASK) { + offset += sprintf(buffer+offset, ",%d", cops->AcT); + } + offset += sprintf(buffer+offset, "\r\n"); + } + else if (data->type == AT_COMMAND_TST) + { + const at_cops_tst_t * cops = &(data->response.cops.tst); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+COPS: "); + + /* Display the list of operators present in the network */ + strncpy(buffer+offset, cops->data, cops->size); + offset += cops->size; + + /* Display the list of supported network registration modes and + * supported representation formats of network operators */ + //offset += sprintf(buffer+offset, ",,(%d-%d),(%d,%d,%d)", + // AT_COPS_AUTO, AT_COPS_MANAUTO, + // AT_COPS_LONG, AT_COPS_SHORT, AT_COPS_NUM); + offset += sprintf(buffer+offset, "\r\n"); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgatt() ** + ** ** + ** Description: Encodes AT CGATT command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgatt(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cgatt_resp_t * cgatt = &(data->response.cgatt); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGATT: %d\r\n", cgatt->state); + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGATT: (%d,%d)\r\n", + AT_CGATT_STATE_MIN, AT_CGATT_STATE_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_creg() ** + ** ** + ** Description: Encodes AT CGREG command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_creg(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_creg_resp_t * creg = &(data->response.creg); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CREG: %d,%d", + creg->n, creg->stat); + if (data->mask & AT_CREG_RESP_LAC_MASK) { + offset += sprintf(buffer+offset, ",%s", creg->lac); + } + if (data->mask & AT_CREG_RESP_CI_MASK) { + offset += sprintf(buffer+offset, ",%s", creg->ci); + } + if (data->mask & AT_CREG_RESP_ACT_MASK) { + offset += sprintf(buffer+offset, ",%d", creg->AcT); + } + offset += sprintf(buffer+offset, "\r\n"); + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CREG: (%d-%d)\r\n", + AT_CREG_N_MIN, AT_CREG_N_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgreg() ** + ** ** + ** Description: Encodes AT CGREG command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgreg(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cgreg_resp_t * cgreg = &(data->response.cgreg); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGREG: %d,%d", + cgreg->n, cgreg->stat); + if (data->mask & AT_CGREG_RESP_LAC_MASK) { + offset += sprintf(buffer+offset, ",%s", cgreg->lac); + } + if (data->mask & AT_CGREG_RESP_CI_MASK) { + offset += sprintf(buffer+offset, ",%s", cgreg->ci); + } + if (data->mask & AT_CGREG_RESP_ACT_MASK) { + offset += sprintf(buffer+offset, ",%d", cgreg->AcT); + } + if (data->mask & AT_CGREG_RESP_RAC_MASK) { + offset += sprintf(buffer+offset, ",%s", cgreg->rac); + } + offset += sprintf(buffer+offset, "\r\n"); + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGREG: (%d-%d)\r\n", + AT_CGREG_N_MIN, AT_CGREG_N_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cereg() ** + ** ** + ** Description: Encodes AT CEREG command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cereg(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cereg_resp_t * cereg = &(data->response.cereg); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CEREG: %d,%d", + cereg->n, cereg->stat); + if (data->mask & AT_CEREG_RESP_TAC_MASK) { + offset += sprintf(buffer+offset, ",%s", cereg->tac); + } + if (data->mask & AT_CEREG_RESP_CI_MASK) { + offset += sprintf(buffer+offset, ",%s", cereg->ci); + } + if (data->mask & AT_CEREG_RESP_ACT_MASK) { + offset += sprintf(buffer+offset, ",%d", cereg->AcT); + } + offset += sprintf(buffer+offset, "\r\n"); + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CEREG: (%d-%d)\r\n", + AT_CEREG_N_MIN, AT_CEREG_N_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgdcont() ** + ** ** + ** Description: Encodes AT CGDCONT command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgdcont(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cgdcont_get_t * cgdcont = &(data->response.cgdcont.get); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + + /* Display the list of defined PDN contexts */ + for (int i = 0; i < cgdcont->n_pdns; i++) { + offset += sprintf(buffer+offset, "+CGDCONT: %u", cgdcont->cid[i]); + if (cgdcont->PDP_type[i] == NET_PDN_TYPE_IPV4) { + offset += sprintf(buffer+offset, ",IP"); + } + else if (cgdcont->PDP_type[i] == NET_PDN_TYPE_IPV6) { + offset += sprintf(buffer+offset, ",IPV6"); + } + else if (cgdcont->PDP_type[i] == NET_PDN_TYPE_IPV4V6) { + offset += sprintf(buffer+offset, ",IPV4V6"); + } + offset += sprintf(buffer+offset, ",%s", cgdcont->APN[i]); + /* No data/header compression */ + offset += sprintf(buffer+offset, ",%u,%u\r\n", + AT_CGDCONT_D_COMP_OFF, AT_CGDCONT_H_COMP_OFF); + } + } + else if (data->type == AT_COMMAND_TST) + { + const at_cgdcont_tst_t * cgdcont = &(data->response.cgdcont.tst); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + + /* IPv4 PDN type */ + offset += sprintf(buffer+offset, "+CGDCONT: "); + offset += sprintf(buffer+offset, "(1-%u),IP,,,(%u-%u),(%u-%u)", + cgdcont->n_cid, + AT_CGDCONT_D_COMP_MIN, AT_CGDCONT_D_COMP_MAX, + AT_CGDCONT_H_COMP_MIN, AT_CGDCONT_H_COMP_MAX); + /* IPv6 PDN type */ + offset += sprintf(buffer+offset, "\r\n+CGDCONT: "); + offset += sprintf(buffer+offset, "(1-%u),IPV6,,,(%u-%u),(%u-%u)", + cgdcont->n_cid, + AT_CGDCONT_D_COMP_MIN, AT_CGDCONT_D_COMP_MAX, + AT_CGDCONT_H_COMP_MIN, AT_CGDCONT_H_COMP_MAX); + /* IPv4v6 PDN type */ + offset += sprintf(buffer+offset, "\r\n+CGDCONT: "); + offset += sprintf(buffer+offset, "(1-%u),IPV4V6,,,(%u-%u),(%u-%u)", + cgdcont->n_cid, + AT_CGDCONT_D_COMP_MIN, AT_CGDCONT_D_COMP_MAX, + AT_CGDCONT_H_COMP_MIN, AT_CGDCONT_H_COMP_MAX); + + offset += sprintf(buffer+offset, "\r\n"); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgact() ** + ** ** + ** Description: Encodes AT CGACT command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgact(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cgact_resp_t * cgact = &(data->response.cgact); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + /* Display the list of defined PDN status */ + for (int i = 0; i < cgact->n_pdns; i++) { + offset += sprintf(buffer+offset, "+CGACT: %u,%u\r\n", + cgact->cid[i], cgact->state[i]); + } + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGACT: (%d,%d)\r\n", + AT_CGACT_STATE_MIN, AT_CGACT_STATE_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgpaddr() ** + ** ** + ** Description: Encodes AT CGPADDR command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgpaddr(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + const at_cgpaddr_resp_t * cgpaddr = &(data->response.cgpaddr); + + if (data->type == AT_COMMAND_SET) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + /* Display the list of IP addresses assigned to each defined PDN + * connections */ + for (int i = 0; i < cgpaddr->n_pdns; i++) { + offset += sprintf(buffer+offset, "+CGPADDR: %u", cgpaddr->cid[i]); + if (cgpaddr->PDP_addr_1[i] != NULL) { + /* IPv4 address */ + offset += sprintf(buffer+offset, ",%hhu.%hhu.%hhu.%hhu", + cgpaddr->PDP_addr_1[i][0], + cgpaddr->PDP_addr_1[i][1], + cgpaddr->PDP_addr_1[i][2], + cgpaddr->PDP_addr_1[i][3]); + } + if (cgpaddr->PDP_addr_2[i] != NULL) { + /* IPv6 Link-local address prefixe */ + offset += sprintf(buffer+offset, + ",%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", + 0xfe, 0x80, 0, 0, 0, 0, 0, 0); + /* IPv6 Link-local address */ + offset += sprintf(buffer+offset, + ".%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", + cgpaddr->PDP_addr_2[i][0], + cgpaddr->PDP_addr_2[i][1], + cgpaddr->PDP_addr_2[i][2], + cgpaddr->PDP_addr_2[i][3], + cgpaddr->PDP_addr_2[i][4], + cgpaddr->PDP_addr_2[i][5], + cgpaddr->PDP_addr_2[i][6], + cgpaddr->PDP_addr_2[i][7]); + } + offset += sprintf(buffer+offset, "\r\n"); + } + } + else if (data->type == AT_COMMAND_TST) + { + /* Display the list of defined PDN contexts */ + if (cgpaddr->n_pdns > 0) { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CGPADDR: %u", cgpaddr->cid[0]); + for (int i = 1; i < cgpaddr->n_pdns; i++) { + offset += sprintf(buffer+offset, ",%u", cgpaddr->cid[i]); + } + offset += sprintf(buffer+offset, "\r\n"); + } + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cmee() ** + ** ** + ** Description: Encodes AT CMEE command response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cmee(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cmee_resp_t * cmee = &(data->response.cmee); + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CMEE: %d\r\n", cmee->n); + } + else if (data->type == AT_COMMAND_TST) + { + if (at_response_format_v1) { + offset += sprintf(buffer, "\r\n"); + } + offset += sprintf(buffer+offset, "+CMEE: (%d,%d)\r\n", + AT_CMEE_N_MIN, AT_CMEE_N_MAX); + } + + LOG_FUNC_RETURN (offset); +} + +/**************************************************************************** + ** ** + ** Name: _at_response_encode_cgev() ** + ** ** + ** Description: Encodes AT CGEV unsolicited result response message ** + ** ** + ** Inputs data: AT response data to encode ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of characters encoded in the ** + ** data buffer ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _at_response_encode_cgev(char* buffer, const at_response_t* data) +{ + LOG_FUNC_IN; + + int offset = 0; + + if (data->type == AT_COMMAND_GET) + { + const at_cgev_resp_t * cgev = &(data->response.cgev); + offset += sprintf(buffer+offset, "+CGEV: %s %u\r\n", + _at_response_event_str[cgev->code], cgev->cid); + } + + LOG_FUNC_RETURN (offset); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.h b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.h new file mode 100644 index 0000000000..710b543bb4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/at_response.h @@ -0,0 +1,761 @@ +/***************************************************************************** + +Source at_response.h + +Version 0.1 + +Date 2012/03/09 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines structure of the AT command response returned after + completion of AT command processing. + +*****************************************************************************/ +#ifndef __AT_RESPONSE_H__ +#define __AT_RESPONSE_H__ + +#include "at_command.h" +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Total number of characters, including line terminators, in information text + */ +#define AT_RESPONSE_INFO_TEXT_SIZE 2048 + +/* + * Value of the mask parameter for AT command reponses without any optional + * parameters + */ +#define AT_RESPONSE_NO_PARAM AT_COMMAND_PARAM0 + +/* + * Maximum value of an AT command response identifier + */ +#define AT_RESPONSE_ID_MAX AT_COMMAND_ID_MAX + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * ================ + * General commands + * ================ + */ + +/* CGSN: Request Product Serial Number identification (IMEI) + * --------------------------------------------------------- + * Returns information text intended to permit the user to identify the + * individual Mobile Equipment to which it is connected to. + * Action command: + * +CGSN returns <sn> + * <sn> information text containing the IMEI + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGSN_MASK AT_RESPONSE_NO_PARAM + +/* CGSN AT command response type */ +typedef struct { + char sn[AT_RESPONSE_INFO_TEXT_SIZE+1]; +} at_cgsn_resp_t; + +/* CGMI: Request manufacturer identification + * ----------------------------------------- + * Returns information text intended to permit the user to identify the + * manufacturer of the Mobile Equipment to which it is connected to. + * Action command: + * +CGMI returns <manufacturer> + * <manufacturer> information text containing the manufacturer id + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGMI_MASK AT_RESPONSE_NO_PARAM + +/* CGMI AT command response type */ +typedef struct { + char manufacturer[AT_RESPONSE_INFO_TEXT_SIZE+1]; +} at_cgmi_resp_t; + +/* CGMM: Request model identification + * ---------------------------------- + * Returns information text intended to permit the user to identify the + * specific model of the Mobile Equipment to which it is connected to. + * +CGMM returns <model> + * <model> information text containing the model id + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGMM_MASK AT_RESPONSE_NO_PARAM + +/* CGMM AT command response type */ +typedef struct { + char model[AT_RESPONSE_INFO_TEXT_SIZE+1]; +} at_cgmm_resp_t; + +/* CGMR: Request revision identification + * ------------------------------------- + * Returns information text intended to permit the user to identify the + * version, revision level or date, or other pertinent information of the + * Mobile Equipment to which it is connected to. + * +CGMR returns <revision> + * <revision> information text containing the revision of the firmware + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGMR_MASK AT_RESPONSE_NO_PARAM + +/* CGMR AT command response type */ +typedef struct { + char revision[AT_RESPONSE_INFO_TEXT_SIZE+1]; +} at_cgmr_resp_t; + +/* CIMI: Request International Mobile Subscriber Identity + * ------------------------------------------------------ + * Returns <IMSI>, which is intended to permit the user to identify the + * individual SIM card or active application in the UICC (GSM or USIM) + * which is attached to the Mobile Equipment to which it is connected to. + * Action command: + * +CIMI returns <IMSI> + * <IMSI> International Mobile Subscriber Identity (string without + * double quotes) + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CIMI_MASK AT_RESPONSE_NO_PARAM + +/* CIMI AT command response type */ +typedef struct { + char IMSI[AT_RESPONSE_INFO_TEXT_SIZE+1]; +} at_cimi_resp_t; + +/* + * ============================================== + * Mobile Termination control and status commands + * ============================================== + */ +/* CFUN: Set phone functionality + * ----------------------------- + * Used to set the Mobile Equipment to different power consumption states + * Read parameter command: + * +CFUN? returns +CFUN: <fun> + * <fun> integer type - level of functionality + * Test parameter command: + * +CFUN=? returns +CFUN: (list of supported <fun>s),(list of supported <rst>s) + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CFUN_MASK AT_RESPONSE_NO_PARAM + +/* CFUN AT command response type */ +typedef struct { + int fun; +} at_cfun_resp_t; + +/* CPIN: Enter PIN + * --------------- + * Used to enter MT passwords which are needed before any other + * functionality of the MT can be used + * Read parameter command: + * +CPIN? returns +CPIN: <code> + * <code> string - value may be: "READY", "SIM PIN" + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CPIN_MASK AT_RESPONSE_NO_PARAM + +/* CPIN AT command response type */ +typedef struct { +#define AT_CPIN_RESP_SIZE 16 + char code[AT_CPIN_RESP_SIZE+1]; +} at_cpin_resp_t; + +/* CSQ: Signal quality + * ------------------- + * Returns received signal strength indication and channel bit error rate + * from the Mobile Equipment + * Action command: + * +CSQ returns +CSQ: <rssi>, <ber> + * <rssi> integer type - received signal strength indication (in dBm) + * <ber> integer type - channel bit error rate (in percent) + */ + +/* Received signal strength indicator */ +#define AT_CSQ_RSSI_0 0 /* -113 dBm or less */ +#define AT_CSQ_RSSI_31 31 /* -51 dBm or greater */ +#define AT_CSQ_RSSI_UNKNOWN 99 /* not known or not detectable */ + +/* Channel bit error rate */ +#define AT_CSQ_BER_0 0 /* BER < 0.2 % */ +#define AT_CSQ_BER_1 1 /* 0.2 % < BER < 0.4 % */ +#define AT_CSQ_BER_2 2 /* 0.4 % < BER < 0.8 % */ +#define AT_CSQ_BER_3 3 /* 0.8 % < BER < 1.6 % */ +#define AT_CSQ_BER_4 4 /* 1.6 % < BER < 3.2 % */ +#define AT_CSQ_BER_5 5 /* 3.2 % < BER < 6.4 % */ +#define AT_CSQ_BER_6 6 /* 6.4 % < BER < 12.8 % */ +#define AT_CSQ_BER_7 7 /* 12.8 % < BER */ +#define AT_CSQ_BER_UNKNOWN 99 /* not known or not detectable */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CSQ_MASK AT_RESPONSE_NO_PARAM + +/* CSQ AT command response type */ +typedef struct { + int rssi; + int ber; +} at_csq_resp_t; + +/* CESQ: Extended signal quality + * ----------------------------- + * Returns received signal quality parameters. + * Action command: + * +CESQ returns +CESQ: <rssi>,<ber>,<rscp>,<ecno>,<rsrq>,<rsrp> + * <rssi> integer type - received signal strength indication (in dBm) + * <ber> integer type - channel bit error rate (in percent) + * <rscp> integer type - received signal code power (in dBm) + * <ecno> integer type - ratio of the received energy per PN chip (in dBm) + * <rsrq> integer type - reference signal received quality (in dBm) + * <rsrp> integer type - reference signal received power (in dBm) + */ + +/* Received signal strength indicator */ +#define AT_CESQ_RSSI_0 0 /* -113 dBm or less */ +#define AT_CESQ_RSSI_31 31 /* -51 dBm or greater */ +#define AT_CESQ_RSSI_UNKNOWN 99 /* not known or not detectable */ + +/* Channel bit error rate */ +#define AT_CESQ_BER_0 0 /* BER < 0.2 % */ +#define AT_CESQ_BER_1 1 /* 0.2 % < BER < 0.4 % */ +#define AT_CESQ_BER_2 2 /* 0.4 % < BER < 0.8 % */ +#define AT_CESQ_BER_3 3 /* 0.8 % < BER < 1.6 % */ +#define AT_CESQ_BER_4 4 /* 1.6 % < BER < 3.2 % */ +#define AT_CESQ_BER_5 5 /* 3.2 % < BER < 6.4 % */ +#define AT_CESQ_BER_6 6 /* 6.4 % < BER < 12.8 % */ +#define AT_CESQ_BER_7 7 /* 12.8 % < BER */ +#define AT_CESQ_BER_UNKNOWN 99 /* not known or not detectable */ + +/* Received signal code power */ +#define AT_CESQ_RSCP_0 0 /* -120 dBm or less */ +#define AT_CESQ_RSCP_96 96 /* -24 dBm or greater */ +#define AT_CESQ_RSCP_UNKNOWN 255 /* not known or not detectable */ + +/* Ratio of the received energy per PN chip (Ec/No) */ +#define AT_CESQ_ECNO_0 0 /* -24 dBm or less */ +#define AT_CESQ_ECNO_49 49 /* 0,5 dBm or greater */ +#define AT_CESQ_ECNO_UNKNOWN 255 /* not known or not detectable */ + +/* Reference signal received quality */ +#define AT_CESQ_RSRQ_0 0 /* -19,5 dBm or less */ +#define AT_CESQ_RSRQ_34 34 /* -2,5 dBm or greater */ +#define AT_CESQ_RSRQ_UNKNOWN 255 /* not known or not detectable */ + +/* Reference signal received power */ +#define AT_CESQ_RSRP_0 0 /* -140 dBm or less */ +#define AT_CESQ_RSRP_97 97 /* -43 dBm or greater */ +#define AT_CESQ_RSRP_UNKNOWN 255 /* not known or not detectable */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CESQ_MASK AT_RESPONSE_NO_PARAM + +/* CSQ AT command response type */ +typedef struct { + int rssi; + int ber; + int rscp; + int ecno; + int rsrq; + int rsrp; +} at_cesq_resp_t; + +/* CLAC: List all available AT commands + * ------------------------------------ + * Returns one or more lines of AT Commands that are available for the user. + * Action command: + * +CLAC returns +CLAC: <AT Command1>[<CR><LF><AT Command2>[...]] + * <AT Command> string - defines the AT command including the prefix AT + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CLAC_MASK AT_RESPONSE_NO_PARAM + +/* CLAC AT command response type */ +typedef struct { + int n_acs; +#define AT_CLAC_RESP_SIZE 100 + const char* ac[AT_CLAC_RESP_SIZE]; +} at_clac_resp_t; + +/* + * ========================= + * Mobile Termination errors + * ========================= + */ +/* + * CMEE: Report mobile termination error + * ------------------------------------- + * Disables or enables the use of final result code +CME ERROR: <err> as an + * indication of an error relating to the functionality of the MT. + * Read parameter command: + * +CMEE? returns +CMEE: <n> + * <n> numeric parameter + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CMEE_MASK AT_RESPONSE_NO_PARAM + +/* CMEE AT command response type */ +typedef at_cmee_t at_cmee_resp_t; + +/* + * ================================ + * Network service related commands + * ================================ + */ +/* CNUM: Subscriber number + * ----------------------- + * Returns the MSISDNs related to the subscriber. + * Action command: + * +CNUM returns +CNUM: <number1>,<type1>[<CR><LF> + * +CNUM: <number2>,<type2>[...]] + * <numberx> string type phone number of format specified by <typex> + * <typex> type of address octet in integer format + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CNUM_MASK AT_RESPONSE_NO_PARAM + +/* CNUM AT command response type */ +typedef struct { +#define AT_CNUM_NUMBER_SIZE MSISDN_DIGIT_SIZE + char number[AT_CNUM_NUMBER_SIZE]; + int type; +} at_cnum_resp_t; + +/* CLCK: Facility lock + * ------------------- + * Used to lock, unlock or interrogate a MT or a network facility <fac>. + * When <mode>=2, returns +CLCK: <status> + * <status> state of the network service + */ + +/* Network service status */ +#define AT_CLCK_RESP_STATUS_NOT_ACTIVE 0 +#define AT_CLCK_RESP_STATUS_ACTIVE 1 + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CLCK_MASK AT_RESPONSE_NO_PARAM + +/* CLCK AT command response type */ +typedef struct { + int status; +} at_clck_resp_t; + +/* COPS: PLMN selection + * -------------------- + * Forces an attempt to select and register the GSM/UMTS/EPS network operator + * using the SIM/USIM card installed in the currently selected card slot. + * Read parameter command: + * +COPS? returns +COPS:<mode>[,<format>,<oper>[,<AcT>]] + * <mode> operation mode of the network selection + * <format> representation format of the network operator + * <oper> APN operator identifier + * <AcT> access technology + * Test command returns a set of parameters, each representing an operator + * present in the network: + * +COPS=? returns +COPS: [list of supported (<stat>,long alphanumeric <oper>, + * short alphanumeric <oper>,numeric <oper>[,<AcT>])s][,,(list of supported + * <mode>s),(list of supported <format>s)] + * <stat> network operator availability + */ + +/* Optional parameter bitmask */ +#define AT_COPS_RESP_FORMAT_MASK AT_COMMAND_PARAM2 +#define AT_COPS_RESP_OPER_MASK AT_COMMAND_PARAM3 +#define AT_COPS_RESP_ACT_MASK AT_COMMAND_PARAM4 + +/* Structure of COPS AT test parameter command */ +typedef struct { + const char* data; /* String representation of the list of operators */ + int size; /* Size in byte of the data to be dislayed */ +} at_cops_tst_t; + +/* Structure of COPS AT read parameter command */ +typedef at_cops_t at_cops_get_t; + +/* COPS AT command response type */ +typedef union { + at_cops_tst_t tst; + at_cops_get_t get; +} at_cops_resp_t; + +/* CREG: network registration + * -------------------------- + * When <n>=1, returns +CREG: <stat>, the Mobile Equipment's circuit mode + * network registration status in GERA/UTRA/E-UTRA Network. + * When <n>=2, returns +CREG: <stat>[,<lac>,<ci>[,<AcT>]], the Mobile + * Equipment's circuit mode network registration status and location information + * in GERA/UTRA/E-UTRA Network. + * Read parameter command: + * +CREG? returns +CREG:<n>,<stat>[,<lac>,<ci>[,<AcT>]] + * <n> numeric parameter + * <stat> numeric parameter that indicates the circuit mode registration + * status + * <lac> string type; two byte location area code in hexadecimal format + * <ci> string type; four byte GERAN/UTRAN/E-UTRAN cell ID in hexadeci- + * mal format + * <AcT> a numeric parameter that indicates the access technology of + * the serving cell + */ + +/* Network registration status */ +#define AT_CREG_RESP_REG_OFF NET_REG_STATE_OFF +#define AT_CREG_RESP_REG_HN NET_REG_STATE_HN +#define AT_CREG_RESP_REG_ON NET_REG_STATE_ON +#define AT_CREG_RESP_REG_DENIED NET_REG_STATE_DENIED +#define AT_CREG_RESP_REG_UNKNOWN NET_REG_STATE_UNKNOWN +#define AT_CREG_RESP_REG_SMS_HN NET_REG_STATE_SMS_HN +#define AT_CREG_RESP_REG_SMS_ROAMING NET_REG_STATE_SMS_ROAMING +#define AT_CREG_RESP_REG_ROAMING NET_REG_STATE_ROAMING + +/* Access technology indicators */ +#define AT_CREG_RESP_GSM NET_ACCESS_GSM /* GSM */ +#define AT_CREG_RESP_COMPACT NET_ACCESS_COMPACT /* GSM Compact */ +#define AT_CREG_RESP_UTRAN NET_ACCESS_UTRAN /* UTRAN */ +#define AT_CREG_RESP_EGPRS NET_ACCESS_EGPRS /* GSM w/EGPRS */ +#define AT_CREG_RESP_HSDPA NET_ACCESS_HSDPA /* UTRAN w/HSDPA */ +#define AT_CREG_RESP_HSUPA NET_ACCESS_HSUPA /* UTRAN w/HSUPA */ +#define AT_CREG_RESP_HSDUPA NET_ACCESS_HSDUPA /* w/HSDPA and HSUPA */ +#define AT_CREG_RESP_EUTRAN NET_ACCESS_EUTRAN /* E-UTRAN */ + +/* Optional parameter bitmask */ +//#define AT_CREG_RESP_N_MASK AT_COMMAND_PARAM1 +#define AT_CREG_RESP_LAC_MASK AT_COMMAND_PARAM3 +#define AT_CREG_RESP_CI_MASK AT_COMMAND_PARAM4 +#define AT_CREG_RESP_ACT_MASK AT_COMMAND_PARAM5 + +/* CREG AT command response type */ +typedef struct { + int n; + int stat; +#define AT_CREG_RESP_LAC_SIZE 4 + char lac[AT_CREG_RESP_LAC_SIZE+1]; +#define AT_CREG_RESP_CI_SIZE 8 + char ci[AT_CREG_RESP_CI_SIZE+1]; + int AcT; +} at_creg_resp_t; + +/* + * ========================== + * Commands for Packet Domain + * ========================== + */ +/* CGATT: GPRS service attach/detach + * --------------------------------- + * Used to attach the MT to, or detach the MT from, the GPRS service. + * Read parameter command: + * +CGATT? returns CGATT: <state> + * <state> numeric parameter that indicates the state of GPRS attachment + * Test parameter command: + * +CGATT=? returns CGATT: (list of supported <state>s) + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGATT_MASK AT_RESPONSE_NO_PARAM + +/* CGATT AT command response type */ +typedef struct { + int state; +} at_cgatt_resp_t; + +/* CGREG: GPRS network registration status + * --------------------------------------- + * When <n>=1, returns +CGREG: <stat>, the Mobile Equipment's GPRS network + * registration status in GERA/UTRA Network. + * When <n>=2, returns +CGREG: <stat>[,<lac>,<ci>[,<AcT>,<rac>]], the Mobile + * Equipment's GPRS network registration status and location information in + * GERA/UTRA Network. + * Read parameter command: + * +CGREG? returns +CGREG:<n>,<stat>[,<lac>,<ci>[,<AcT>,<rac>]] + * <n> numeric parameter + * <stat> numeric parameter that indicates the GPRS registration status + * <lac> string type; two byte location area code in hexadecimal format + * <ci> string type; four byte GERAN/UTRAN cell ID in hexadecimal format + * <AcT> a numeric parameter that indicates the access technology of + * the serving cell + * <rac> string type; one byte routing area code in hexadecimal format + */ + +/* Network registration status */ +#define AT_CGREG_RESP_REG_OFF NET_REG_STATE_OFF +#define AT_CGREG_RESP_REG_HN NET_REG_STATE_HN +#define AT_CGREG_RESP_REG_ON NET_REG_STATE_ON +#define AT_CGREG_RESP_REG_DENIED NET_REG_STATE_DENIED +#define AT_CGREG_RESP_REG_UNKNOWN NET_REG_STATE_UNKNOWN +#define AT_CGREG_RESP_REG_ROAMING NET_REG_STATE_ROAMING +#define AT_CGREG_RESP_REG_EMERGENCY NET_REG_STATE_EMERGENCY + +/* Access technology indicators */ +#define AT_CGREG_RESP_GSM NET_ACCESS_GSM /* GSM */ +#define AT_CGREG_RESP_COMPACT NET_ACCESS_COMPACT /* GSM Compact */ +#define AT_CGREG_RESP_UTRAN NET_ACCESS_UTRAN /* UTRAN */ +#define AT_CGREG_RESP_EGPRS NET_ACCESS_EGPRS /* GSM w/EGPRS */ +#define AT_CGREG_RESP_HSDPA NET_ACCESS_HSDPA /* UTRAN w/HSDPA */ +#define AT_CGREG_RESP_HSUPA NET_ACCESS_HSUPA /* UTRAN w/HSUPA */ +#define AT_CGREG_RESP_HSDUPA NET_ACCESS_HSDUPA /* w/HSDPA and HSUPA */ + +/* Optional parameter bitmask */ +//#define AT_CGREG_RESP_N_MASK AT_COMMAND_PARAM1 +#define AT_CGREG_RESP_LAC_MASK AT_COMMAND_PARAM3 +#define AT_CGREG_RESP_CI_MASK AT_COMMAND_PARAM4 +#define AT_CGREG_RESP_ACT_MASK AT_COMMAND_PARAM5 +#define AT_CGREG_RESP_RAC_MASK AT_COMMAND_PARAM6 + +/* CGREG AT command response type */ +typedef struct { + int n; + int stat; +#define AT_CGREG_RESP_LAC_SIZE 4 + char lac[AT_CGREG_RESP_LAC_SIZE+1]; +#define AT_CGREG_RESP_CI_SIZE 8 + char ci[AT_CGREG_RESP_CI_SIZE+1]; + int AcT; +#define AT_CGREG_RESP_RAC_SIZE 2 + char rac[AT_CGREG_RESP_RAC_SIZE+1]; +} at_cgreg_resp_t; + +/* CEREG: EPS network registration status + * -------------------------------------- + * When <n>=1, returns +CEREG: <stat>, the Mobile Equipment's EPS services + * registration status in EUTRA Network. + * When <n>=2, returns +CEREG: <stat>[,<tac>,<ci>[,<AcT>]], the Mobile + * Equipment's EPS services registration status and location information in + * EUTRA Network. + * Read parameter command: + * +CEREG? returns +CEREG:<n>,<stat>[,<tac>,<ci>[,<AcT>]] + * <n> numeric parameter + * <stat> numeric parameter that indicates the EPS registration status + * <tac> string type; two byte tracking area code in hexadecimal format + * <ci> string type; four byte E-UTRAN cell ID in hexadecimal format + * <AcT> a numeric parameter that indicates the access technology of + * the serving cell + */ + +/* Network registration status */ +#define AT_CEREG_RESP_REG_OFF NET_REG_STATE_OFF +#define AT_CEREG_RESP_REG_HN NET_REG_STATE_HN +#define AT_CEREG_RESP_REG_ON NET_REG_STATE_ON +#define AT_CEREG_RESP_REG_DENIED NET_REG_STATE_DENIED +#define AT_CEREG_RESP_REG_UNKNOWN NET_REG_STATE_UNKNOWN +#define AT_CEREG_RESP_REG_ROAMING NET_REG_STATE_ROAMING +#define AT_CEREG_RESP_REG_EMERGENCY NET_REG_STATE_EMERGENCY + +/* Access technology indicators */ +#define AT_CEREG_RESP_EUTRAN NET_ACCESS_EUTRAN /* E-UTRAN */ + +/* Optional parameter bitmask */ +//#define AT_CEREG_RESP_N_MASK AT_COMMAND_PARAM1 +#define AT_CEREG_RESP_TAC_MASK AT_COMMAND_PARAM3 +#define AT_CEREG_RESP_CI_MASK AT_COMMAND_PARAM4 +#define AT_CEREG_RESP_ACT_MASK AT_COMMAND_PARAM5 + +/* CEREG AT command response type */ +typedef struct { + int n; + int stat; +#define AT_CEREG_RESP_TAC_SIZE 4 + char tac[AT_CEREG_RESP_TAC_SIZE+1]; +#define AT_CEREG_RESP_CI_SIZE 8 + char ci[AT_CEREG_RESP_CI_SIZE+1]; + int AcT; +} at_cereg_resp_t; + +/* CGDCONT: Define PDP Context + * --------------------------- + * Specifies PDP context parameter values for a PDP context identified by + * the (local) context identification parameter, <cid>. + * Read parameter command: + * +CGDCONT? returns +CGDCONT: <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>, + * <h_comp>[,<IPv4AddrAlloc>[,<emergency indication>[,<P-CSCF_ + * discovery>[,<IM_CN_Signalling_Flag_Ind>]]]][<CR><LF> + * +CGDCONT: <cid>,<PDP_type>,<APN>,<PDP_addr>,<d_comp>, + * <h_comp>[,<IPv4AddrAlloc>[,<emergency indication>[,<P-CSCF_ + * discovery>[,<IM_CN_Signalling_Flag_Ind>]]]] + * [...]] + * <cid> a numeric parameter which specifies a particular PDP + * context definition + * <PDP_type> type of packet data protocol ("IP", "IPV6", "IPV4V6") + * <APN> Access Point logical Name + * <PDP_addr> Mobile Equipment PDP address (not applicable to EPS) + * <d_comp> PDP data compression parameter + * <h_comp> PDP header compression parameter + * <IPv4AddrAlloc> IPv4 address allocation parameter + * <emergency indication> emergency bearer services support indication + * <P-CSCF_discovery> P-CSCF address discovery parameter + * <IM_CN_Signalling_Flag_Ind> IM CN subsystem-related signalling + * support indication + */ + +/* Optional parameter bitmask */ +#define AT_CGDCONT_RESP_IPV4ADDRALLOC_MASK AT_COMMAND_PARAM7 +#define AT_CGDCONT_RESP_EMERGECY_INDICATION_MASK AT_COMMAND_PARAM8 +#define AT_CGDCONT_RESP_P_CSCF_DISCOVERY_MASK AT_COMMAND_PARAM9 +#define AT_CGDCONT_RESP_IM_CN_SIGNALLING_FLAG_IND_MASK AT_COMMAND_PARAM10 + +/* Structure of CGDCONT AT read parameter command */ +typedef struct { +#define AT_CGDCONT_RESP_SIZE 8 + int n_pdns; /* Number of defined PDN contexts in the lists */ + int cid[AT_CGDCONT_RESP_SIZE]; /* List of PDN context identifiers */ + int PDP_type[AT_CGDCONT_RESP_SIZE]; + const char* APN[AT_CGDCONT_RESP_SIZE]; + int d_comp[AT_CGDCONT_RESP_SIZE]; + int h_comp[AT_CGDCONT_RESP_SIZE]; +} at_cgdcont_get_t; + +/* Structure of CGDCONT AT read parameter command */ +typedef struct { + int n_cid; /* Range of supported PDN context identifiers */ +} at_cgdcont_tst_t; + +/* CGDCONT AT command response type */ +typedef union { + at_cgdcont_tst_t tst; + at_cgdcont_get_t get; +} at_cgdcont_resp_t; + +/* CGACT: PDP context activate or deactivate + * ----------------------------------------- + * Read command returns the current activation states for all the defined + * PDP contexts. + * Read parameter command: + * +CGACT? returns +CGACT: <cid>,<state>[<CR><LF>+CGACT: <cid>,<state>[...]] + * <cid> a numeric parameter which specifies a particular PDP context + * definition + * <state> numeric parameter that indicates the state of PDP context + * activation + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGACT_MASK AT_RESPONSE_NO_PARAM + +/* CGACT AT command response type */ +typedef struct { +#define AT_CGACT_RESP_SIZE AT_CGDCONT_RESP_SIZE + int n_pdns; /* Number of defined PDN contexts in the lists */ + int cid[AT_CGACT_RESP_SIZE]; /* List of PDN context identifiers */ + int state[AT_CGACT_RESP_SIZE]; /* List of PDN context states */ +} at_cgact_resp_t; + +/* CGPADDR: Show PDP address(es) + * ----------------------------- + * Returns a list of PDP addresses for the specified context identifiers. + * +CGPADDR= returns +CGPADDR: <cid>[,PDP_addr_1[,PDP_addr_2]][<CR><LF> + * +CGPADDR: <cid>[,PDP_addr_1[,PDP_addr_2]][...]] + * <cid> a numeric parameter which specifies a particular PDP + * context definition + * <PDP_addr_x> string that identifies the MT in the address space + * applicable to the PDP + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGPADDR_MASK AT_RESPONSE_NO_PARAM + +/* CGPADDR AT command response type */ +typedef struct { +#define AT_CGPADDR_RESP_SIZE AT_CGDCONT_RESP_SIZE + int n_pdns; /* Number of defined PDP addresses in the lists */ + int cid[AT_CGPADDR_RESP_SIZE]; /* List of PDN context identifiers */ + /* List of IPv4 addresses */ + const char* PDP_addr_1[AT_CGPADDR_RESP_SIZE]; + /* List of IPv6 addresses */ + const char* PDP_addr_2[AT_CGPADDR_RESP_SIZE]; +} at_cgpaddr_resp_t; + +/* CGEV: Unsolicited result + * ------------------------ + * Returns unsolicited result codes in case of certain events occurring + * in the Packet Domain MT or the network. + * +CGREV: <code> <cid> + * <code> unsolicited result code + * <cid> a numeric parameter which specifies a particular PDP + * context definition + */ + +/* Optional parameter bitmask */ +#define AT_RESPONSE_CGEV_MASK AT_RESPONSE_NO_PARAM + +/* Unsolicited result codes */ +#define AT_CGEV_RESP_NW_PDN_ACT (-1) /* Not applicable for LTE */ +#define AT_CGEV_RESP_ME_PDN_ACT NET_PDN_MT_DEFAULT_ACT +#define AT_CGEV_RESP_NW_PDN_DEACT NET_PDN_NW_DEFAULT_DEACT +#define AT_CGEV_RESP_ME_PDN_DEACT NET_PDN_MT_DEFAULT_DEACT +#define AT_CGEV_RESP_NW_ACT NET_PDN_NW_DEDICATED_ACT +#define AT_CGEV_RESP_ME_ACT NET_PDN_MT_DEDICATED_ACT +#define AT_CGEV_RESP_NW_DEACT NET_PDN_NW_DEDICATED_DEACT +#define AT_CGEV_RESP_ME_DEACT NET_PDN_MT_DEDICATED_DEACT + +/* CGEV unsolicited result type */ +typedef struct { + int code; + int cid; +} at_cgev_resp_t; + +/* + * ========================================== + * Global AT command response type definition + * ========================================== + */ + +/* AT command response type */ +typedef struct { + at_command_id_t id; /* AT command identifier */ + at_command_type_t type; /* AT command type */ + int mask; /* Optional parameter bitmask */ + int cause_code; /* AT command error cause code */ + union { + at_cgsn_resp_t cgsn; + at_cgmi_resp_t cgmi; + at_cgmm_resp_t cgmm; + at_cgmr_resp_t cgmr; + at_cimi_resp_t cimi; + at_cfun_resp_t cfun; + at_cpin_resp_t cpin; + at_csq_resp_t csq; + at_cesq_resp_t cesq; + at_clac_resp_t clac; + at_cmee_resp_t cmee; + at_cnum_resp_t cnum; + at_clck_resp_t clck; + at_cops_resp_t cops; + at_cgatt_resp_t cgatt; + at_creg_resp_t creg; + at_cgreg_resp_t cgreg; + at_cereg_resp_t cereg; + at_cgdcont_resp_t cgdcont; + at_cgact_resp_t cgact; + at_cgpaddr_resp_t cgpaddr; + at_cgev_resp_t cgev; + } response; +} at_response_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int at_response_encode(char* buffer, const at_response_t* at_response); + +#endif /* __AT_RESPONSE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/Makefile new file mode 100644 index 0000000000..d1f871dfcb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/Makefile @@ -0,0 +1,37 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +LIBS = -lutil -lapi -lEMMmsg -lESMmsg -lies +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(USERAPIDIR) + +LIBSAPI = $(LIBDIR)/$(LIBAPI).a $(LIBDIR)/$(LIBAPI).so + +TST_OBJ = at_parser.o + +TST_TARGET = at_parser + +TARGETS = $(TST_TARGET) + +all: $(TARGETS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(TST_TARGET): $(TST_OBJ) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(OBJS) $(TARGETS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +at_parser.o: $(USERAPIDIR)/at_command.h +at_parser.o: $(INCDIR)/commonDef.h $(INCDIR)/userDef.h +at_parser.o: $(INCDIR)/networkDef.h $(UTILDIR)/log.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.c new file mode 100644 index 0000000000..84ff4529dd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.c @@ -0,0 +1,130 @@ +/***************************************************************************** + Source main.c + Version 0.1 + Date 01/04/2012 + Product NAS stack + Subsystem Application Programming Interface + Author Baris Demiray + Description Interacts with AT parser for testing purposes + *****************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include "at_command.h" + +#include "nas_log.h" + +int main() { + const char * sample_at_commands[] = { + "AT+CGSN\r", "AT+CGSN=?\r", "AT+CGMI\r", "AT+CGMI=?\r", "AT+CGMM\r", + "AT+CGMM=?\r", "AT+CIMI\r", "AT+CIMI=?\r", "AT+CFUN=1,1\r", + "AT+CFUN=2\r", "AT+CFUN?\r", "AT+CFUN=?\r", "AT+CPIN=1234\r", + "AT+CPIN=1234,4321\r", "AT+CPIN?\r", "AT+CPIN=?\r", "AT+CSQ\r", + "AT+CSQ=?\r", "AT+COPS=1,1,EURECOM\r", "AT+COPS=2,3\r", "AT+COPS=5\r", + "AT+COPS?\r", "AT+COPS=?\r", "AT+CGREG=1\r", "AT+CGREG?\r", + "AT+CGREG=?\r", "AT+CGDCONT=1\r", "AT+CGDCONT?\r", "AT+CGDCONT=?\r", + "AT+CGACT=1\r", "AT+CGACT?\r", "AT+CGACT=?\r", "AT+CGMR\r", + "AT+CGMR=?\r", "AT+CESQ\r", "AT+CESQ=?\r", "AT+CMEE=2\r", + "AT+CMEE?\r", "AT+CMEE=?\r", "AT+CLCK=SC,2\r", "AT+CLCK=?\r", + "AT+CREG=1\r", "AT+CREG?\r", "AT+CREG=?\r", + "AT+CEREG=1\r", "AT+CEREG?\r", "AT+CEREG=?\r", + "AT+CGATT=1\r", "AT+CGATT?\r", "AT+CGATT=?\r", + "AT\r", "null" + }; + + const char * sample_faulty_at_commands[] = { + "AT+CGSN=3,4\r", "AT+CGSN=??\r", "AT+CGMI=1,b\r", "AT+CGMI==\r", + "AT+CGMM?\r", "AT+CGMM==n\r", "AT+CIMI=4\r", "AT+CIMI=?t\r", + "AT+CFUN=n1,1\r", "AT+CFUN??\r", "AT+CFUN=a?\r", "AT+CPIN=1fd4\r", + "AT+CPIN=1sd+,432\r", "AT+CPIN?4\r", "AT+CPIN=?,?\r", "AT+CSQ=AT\r", + "AT+CSQ=q\r", + "AT+COPS=123121123123123123,EURECOMEURECOMEURECOMEURECOM\r", + "AT+COPS=2asd3,33ads1\r", "AT+COPS.=5\r", "AT+COPS?/r\\r", + "AT+COPS=?\n\r\r", "AT+CGREG=da1243\42r", "AT+CGREG.?\r", + "AT+CGREG1=?\r", "AT+CGDCONT=d31\r", "AT+CGDCONTxc?\\crca", + "AT+CGDCONcTc=c?\r", "AT+CGA12C3T=11\123r", "AT+CGACT';;.,?\r", + "AT+CGACT=?]\\;e23\r", "\r\r\r", "AT+COP\r", "null" + }; + + at_command_t at_command; + unsigned int at_command_index; + + //log_init(0x2f); + + /* Parse valid AT commands */ + at_command_index = 0; + while (strncmp(sample_at_commands[at_command_index], "null", 4) != 0) { + if (at_command_decode(sample_at_commands[at_command_index], + strlen(sample_at_commands[at_command_index]), + &at_command) > 0) + { + printf("INFO: Fine, parser interpreted valid command %s\n", + sample_at_commands[at_command_index]); + } else { + printf("ERROR: Parser rejected valid command %s\n", + sample_at_commands[at_command_index]); + } + + at_command_index++; + } + + /* Parse invalid AT commands */ + at_command_index = 0; + while (strncmp(sample_faulty_at_commands[at_command_index], "null", 4) != 0) + { + if (at_command_decode(sample_faulty_at_commands[at_command_index], + strlen(sample_faulty_at_commands[at_command_index]), + &at_command) > 0) + { + printf("ERROR: Parser interpreted invalid command %s\n", + sample_faulty_at_commands[at_command_index]); + } else { + printf("INFO: Fine, parser rejected the command %s\n", + sample_faulty_at_commands[at_command_index]); + } + + at_command_index++; + } + + /* + * Provide a console to the user + */ + int bytes_read; + size_t input_size = 100; + char *input; + + printf("Note 1: Carriage return will be appended to every command by default\n"); + printf("Note 2: Enter 'quit' to exit\n"); + printf("AT Command> "); + + input = (char *)malloc(input_size + 1); + + bytes_read = getline(&input, &input_size, stdin); + + while (strncmp(input, "quit", 4) != 0) + { + if (bytes_read == -1) { + puts("Cannot read user input!\n"); + } + else { + input[bytes_read - 1] = '\r'; + + if (at_command_decode(input, bytes_read, &at_command) > 0) + printf("INFO: Parser interpreted command %s\n", input); + else + printf("ERROR: Parser rejected command %s\n", input); + } + + printf("\nAT Command> "); + memset(input, 0x00, input_size); + bytes_read = getline(&input, &input_size, stdin); + } + + free(input); + + printf("Exiting...\n"); + + return 0; +} diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in new file mode 100644 index 0000000000..24ba718cad --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in @@ -0,0 +1,2 @@ +AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? +quit diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in.bis b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in.bis new file mode 100644 index 0000000000..ef9bde30f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.in.bis @@ -0,0 +1,59 @@ +ATE0Q0V1 +ATE0Q0V1 +ATS0=0 +AT+CMEE=1 +AT+CREG=2 +AT+CGREG=1 +AT+CCWA=1 +AT+CMOD=0 +AT+CSSN=0,1 +AT+COLP=0 +AT+CSCS="HEX" +AT+CUSD=1 +AT+CGEREP=1,0 +AT+CMGF=0 +AT+CFUN? +AT+CPIN? +AT+CSMS=1 +AT+CNMI=1,2,2,1,0 +AT+CFUN=0 +AT+CFUN=1 +AT+CPIN? +AT+CSMS=1 +AT+CNMI=1,2,2,1,0 +AT+CGSN +AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? +AT+CGREG? +AT+CREG? +AT+COPS? +AT+CLCC +AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? +AT+CGREG? +AT+CREG? +AT+COPS? +AT+COPS=0 +AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? +AT+CGREG? +AT+CREG? +AT+COPS? +AT+CIMI +AT+CRSM=192,12258,0,0,15 +AT+CRSM=192,28480,0,0,15 +AT+CRSM=192,28617,0,0,15 +AT+CRSM=192,28589,0,0,15 +AT+CRSM=192,28618,0,0,15 +AT+CRSM=192,28433,0,0,15 +AT+CRSM=192,28619,0,0,15 +AT+CRSM=192,28435,0,0,15 +AT+CRSM=192,28486,0,0,15 +AT+CRSM=192,28621,0,0,15 +AT+CRSM=192,28613,0,0,15 +AT+CRSM=192,28472,0,0,15 +AT+CRSM=192,28438,0,0,15 +AT+CRSM=192,28437,0,0,15 +AT+CPIN? +AT+CRSM=192,28439,0,0,15 +AT+CRSM=192,28436,0,0,15 +AT+CRSM=192,28440,0,0,15 +AT+CSQ +quit diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out new file mode 100644 index 0000000000..8c9db5d7d3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out @@ -0,0 +1,90 @@ +INFO: Fine, parser interpreted valid command AT+CGSN +INFO: Fine, parser interpreted valid command AT+CGSN=? +INFO: Fine, parser interpreted valid command AT+CGMI +INFO: Fine, parser interpreted valid command AT+CGMI=? +INFO: Fine, parser interpreted valid command AT+CGMM +INFO: Fine, parser interpreted valid command AT+CGMM=? +INFO: Fine, parser interpreted valid command AT+CIMI +INFO: Fine, parser interpreted valid command AT+CIMI=? +INFO: Fine, parser interpreted valid command AT+CFUN=1,1 +INFO: Fine, parser interpreted valid command AT+CFUN=2 +INFO: Fine, parser interpreted valid command AT+CFUN? +INFO: Fine, parser interpreted valid command AT+CFUN=? +INFO: Fine, parser interpreted valid command AT+CPIN=1234 +INFO: Fine, parser interpreted valid command AT+CPIN=1234,4321 +INFO: Fine, parser interpreted valid command AT+CPIN? +INFO: Fine, parser interpreted valid command AT+CPIN=? +INFO: Fine, parser interpreted valid command AT+CSQ +INFO: Fine, parser interpreted valid command AT+CSQ=? +INFO: Fine, parser interpreted valid command AT+COPS=1,1,EURECOM +INFO: Fine, parser interpreted valid command AT+COPS=2,3 +INFO: Fine, parser interpreted valid command AT+COPS=5 +INFO: Fine, parser interpreted valid command AT+COPS? +INFO: Fine, parser interpreted valid command AT+COPS=? +INFO: Fine, parser interpreted valid command AT+CGREG=1 +INFO: Fine, parser interpreted valid command AT+CGREG? +INFO: Fine, parser interpreted valid command AT+CGREG=? +INFO: Fine, parser interpreted valid command AT+CGDCONT=1 +INFO: Fine, parser interpreted valid command AT+CGDCONT? +INFO: Fine, parser interpreted valid command AT+CGDCONT=? +INFO: Fine, parser interpreted valid command AT+CGACT=1 +INFO: Fine, parser interpreted valid command AT+CGACT? +INFO: Fine, parser interpreted valid command AT+CGACT=? +INFO: Fine, parser interpreted valid command AT+CGMR +INFO: Fine, parser interpreted valid command AT+CGMR=? +INFO: Fine, parser interpreted valid command AT+CESQ +INFO: Fine, parser interpreted valid command AT+CESQ=? +INFO: Fine, parser interpreted valid command AT+CMEE=2 +INFO: Fine, parser interpreted valid command AT+CMEE? +INFO: Fine, parser interpreted valid command AT+CMEE=? +INFO: Fine, parser interpreted valid command AT+CLCK=SC,2 +INFO: Fine, parser interpreted valid command AT+CLCK=? +INFO: Fine, parser interpreted valid command AT+CREG=1 +INFO: Fine, parser interpreted valid command AT+CREG? +INFO: Fine, parser interpreted valid command AT+CREG=? +INFO: Fine, parser interpreted valid command AT+CEREG=1 +INFO: Fine, parser interpreted valid command AT+CEREG? +INFO: Fine, parser interpreted valid command AT+CEREG=? +INFO: Fine, parser interpreted valid command AT+CGATT=1 +INFO: Fine, parser interpreted valid command AT+CGATT? +INFO: Fine, parser interpreted valid command AT+CGATT=? +INFO: Fine, parser interpreted valid command AT +INFO: Fine, parser rejected the command AT+CGSN=3,4 +INFO: Fine, parser rejected the command AT+CGSN=?? +INFO: Fine, parser rejected the command AT+CGMI=1,b +INFO: Fine, parser rejected the command AT+CGMI== +INFO: Fine, parser rejected the command AT+CGMM? +INFO: Fine, parser rejected the command AT+CGMM==n +INFO: Fine, parser rejected the command AT+CIMI=4 +INFO: Fine, parser rejected the command AT+CIMI=?t +INFO: Fine, parser rejected the command AT+CFUN=n1,1 +INFO: Fine, parser rejected the command AT+CFUN?? +INFO: Fine, parser rejected the command AT+CFUN=a? +INFO: Fine, parser rejected the command AT+CPIN=1fd4 +INFO: Fine, parser rejected the command AT+CPIN=1sd+,432 +INFO: Fine, parser rejected the command AT+CPIN?4 +INFO: Fine, parser rejected the command AT+CPIN=?,? +INFO: Fine, parser rejected the command AT+CSQ=AT +INFO: Fine, parser rejected the command AT+CSQ=q +INFO: Fine, parser rejected the command AT+COPS=123121123123123123,EURECOMEURECOMEURECOMEURECOM +INFO: Fine, parser rejected the command AT+COPS=2asd3,33ads1 +INFO: Fine, parser rejected the command AT+COPS.=5 +INFO: Fine, parser rejected the command AT+COPS?/r\r +INFO: Fine, parser rejected the command AT+COPS=? + +INFO: Fine, parser rejected the command AT+CGREG=da1243"r +INFO: Fine, parser rejected the command AT+CGREG.? +INFO: Fine, parser rejected the command AT+CGREG1=? +INFO: Fine, parser rejected the command AT+CGDCONT=d31 +INFO: Fine, parser rejected the command AT+CGDCONTxc?\crca +INFO: Fine, parser rejected the command AT+CGDCONcTc=c? +INFO: Fine, parser rejected the command AT+CGA12C3T=11Sr +INFO: Fine, parser rejected the command AT+CGACT';;.,? +INFO: Fine, parser rejected the command AT+CGACT=?]\;e23 +INFO: Fine, parser rejected the command +INFO: Fine, parser rejected the command AT+COP +Note 1: Carriage return will be appended to every command by default +Note 2: Enter 'quit' to exit +AT Command> INFO: Parser interpreted command AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? + +AT Command> Exiting... diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out.bis b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out.bis new file mode 100644 index 0000000000..802433c742 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/at_parser.out.bis @@ -0,0 +1,204 @@ +INFO: Fine, parser interpreted valid command AT+CGSN +INFO: Fine, parser interpreted valid command AT+CGSN=? +INFO: Fine, parser interpreted valid command AT+CGMI +INFO: Fine, parser interpreted valid command AT+CGMI=? +INFO: Fine, parser interpreted valid command AT+CGMM +INFO: Fine, parser interpreted valid command AT+CGMM=? +INFO: Fine, parser interpreted valid command AT+CIMI +INFO: Fine, parser interpreted valid command AT+CIMI=? +INFO: Fine, parser interpreted valid command AT+CFUN=1,1 +INFO: Fine, parser interpreted valid command AT+CFUN=2 +INFO: Fine, parser interpreted valid command AT+CFUN? +INFO: Fine, parser interpreted valid command AT+CFUN=? +INFO: Fine, parser interpreted valid command AT+CPIN=1234 +INFO: Fine, parser interpreted valid command AT+CPIN=1234,4321 +INFO: Fine, parser interpreted valid command AT+CPIN? +INFO: Fine, parser interpreted valid command AT+CPIN=? +INFO: Fine, parser interpreted valid command AT+CSQ +INFO: Fine, parser interpreted valid command AT+CSQ=? +INFO: Fine, parser interpreted valid command AT+COPS=1,1,EURECOM +INFO: Fine, parser interpreted valid command AT+COPS=2,3 +INFO: Fine, parser interpreted valid command AT+COPS=5 +INFO: Fine, parser interpreted valid command AT+COPS? +INFO: Fine, parser interpreted valid command AT+COPS=? +INFO: Fine, parser interpreted valid command AT+CGREG=1 +INFO: Fine, parser interpreted valid command AT+CGREG? +INFO: Fine, parser interpreted valid command AT+CGREG=? +INFO: Fine, parser interpreted valid command AT+CGDCONT=1 +INFO: Fine, parser interpreted valid command AT+CGDCONT? +INFO: Fine, parser interpreted valid command AT+CGDCONT=? +INFO: Fine, parser interpreted valid command AT+CGACT=1 +INFO: Fine, parser interpreted valid command AT+CGACT? +INFO: Fine, parser interpreted valid command AT+CGACT=? +INFO: Fine, parser interpreted valid command AT+CGMR +INFO: Fine, parser interpreted valid command AT+CGMR=? +INFO: Fine, parser interpreted valid command AT+CESQ +INFO: Fine, parser interpreted valid command AT+CESQ=? +INFO: Fine, parser interpreted valid command AT+CMEE=2 +INFO: Fine, parser interpreted valid command AT+CMEE? +INFO: Fine, parser interpreted valid command AT+CMEE=? +INFO: Fine, parser interpreted valid command AT+CLCK=SC,2 +INFO: Fine, parser interpreted valid command AT+CLCK=? +INFO: Fine, parser interpreted valid command AT+CREG=1 +INFO: Fine, parser interpreted valid command AT+CREG? +INFO: Fine, parser interpreted valid command AT+CREG=? +INFO: Fine, parser interpreted valid command AT+CEREG=1 +INFO: Fine, parser interpreted valid command AT+CEREG? +INFO: Fine, parser interpreted valid command AT+CEREG=? +INFO: Fine, parser interpreted valid command AT+CGATT=1 +INFO: Fine, parser interpreted valid command AT+CGATT? +INFO: Fine, parser interpreted valid command AT+CGATT=? +INFO: Fine, parser interpreted valid command AT +INFO: Fine, parser rejected the command AT+CGSN=3,4 +INFO: Fine, parser rejected the command AT+CGSN=?? +INFO: Fine, parser rejected the command AT+CGMI=1,b +INFO: Fine, parser rejected the command AT+CGMI== +INFO: Fine, parser rejected the command AT+CGMM? +INFO: Fine, parser rejected the command AT+CGMM==n +INFO: Fine, parser rejected the command AT+CIMI=4 +INFO: Fine, parser rejected the command AT+CIMI=?t +INFO: Fine, parser rejected the command AT+CFUN=n1,1 +INFO: Fine, parser rejected the command AT+CFUN?? +INFO: Fine, parser rejected the command AT+CFUN=a? +INFO: Fine, parser rejected the command AT+CPIN=1fd4 +INFO: Fine, parser rejected the command AT+CPIN=1sd+,432 +INFO: Fine, parser rejected the command AT+CPIN?4 +INFO: Fine, parser rejected the command AT+CPIN=?,? +INFO: Fine, parser rejected the command AT+CSQ=AT +INFO: Fine, parser rejected the command AT+CSQ=q +INFO: Fine, parser rejected the command AT+COPS=123121123123123123,EURECOMEURECOMEURECOMEURECOM +INFO: Fine, parser rejected the command AT+COPS=2asd3,33ads1 +INFO: Fine, parser rejected the command AT+COPS.=5 +INFO: Fine, parser rejected the command AT+COPS?/r\r +INFO: Fine, parser rejected the command AT+COPS=? + +INFO: Fine, parser rejected the command AT+CGREG=da1243"r +INFO: Fine, parser rejected the command AT+CGREG.? +INFO: Fine, parser rejected the command AT+CGREG1=? +INFO: Fine, parser rejected the command AT+CGDCONT=d31 +INFO: Fine, parser rejected the command AT+CGDCONTxc?\crca +INFO: Fine, parser rejected the command AT+CGDCONcTc=c? +INFO: Fine, parser rejected the command AT+CGA12C3T=11Sr +INFO: Fine, parser rejected the command AT+CGACT';;.,? +INFO: Fine, parser rejected the command AT+CGACT=?]\;e23 +INFO: Fine, parser rejected the command +INFO: Fine, parser rejected the command AT+COP +Note 1: Carriage return will be appended to every command by default +Note 2: Enter 'quit' to exit +AT Command> INFO: Parser interpreted command ATE0Q0V1 + +AT Command> INFO: Parser interpreted command ATE0Q0V1 + +AT Command> ERROR: Parser rejected command ATS0=0 + +AT Command> INFO: Parser interpreted command AT+CMEE=1 + +AT Command> INFO: Parser interpreted command AT+CREG=2 + +AT Command> INFO: Parser interpreted command AT+CGREG=1 + +AT Command> ERROR: Parser rejected command AT+CCWA=1 + +AT Command> ERROR: Parser rejected command AT+CMOD=0 + +AT Command> ERROR: Parser rejected command AT+CSSN=0,1 + +AT Command> ERROR: Parser rejected command AT+COLP=0 + +AT Command> ERROR: Parser rejected command AT+CSCS="HEX" + +AT Command> ERROR: Parser rejected command AT+CUSD=1 + +AT Command> ERROR: Parser rejected command AT+CGEREP=1,0 + +AT Command> ERROR: Parser rejected command AT+CMGF=0 + +AT Command> INFO: Parser interpreted command AT+CFUN? + +AT Command> INFO: Parser interpreted command AT+CPIN? + +AT Command> ERROR: Parser rejected command AT+CSMS=1 + +AT Command> ERROR: Parser rejected command AT+CNMI=1,2,2,1,0 + +AT Command> INFO: Parser interpreted command AT+CFUN=0 + +AT Command> INFO: Parser interpreted command AT+CFUN=1 + +AT Command> INFO: Parser interpreted command AT+CPIN? + +AT Command> ERROR: Parser rejected command AT+CSMS=1 + +AT Command> ERROR: Parser rejected command AT+CNMI=1,2,2,1,0 + +AT Command> INFO: Parser interpreted command AT+CGSN + +AT Command> INFO: Parser interpreted command AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? + +AT Command> INFO: Parser interpreted command AT+CGREG? + +AT Command> INFO: Parser interpreted command AT+CREG? + +AT Command> INFO: Parser interpreted command AT+COPS? + +AT Command> ERROR: Parser rejected command AT+CLCC + +AT Command> INFO: Parser interpreted command AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? + +AT Command> INFO: Parser interpreted command AT+CGREG? + +AT Command> INFO: Parser interpreted command AT+CREG? + +AT Command> INFO: Parser interpreted command AT+COPS? + +AT Command> INFO: Parser interpreted command AT+COPS=0 + +AT Command> INFO: Parser interpreted command AT+COPS=3,0;+COPS?;+COPS=3,1;+COPS?;+COPS=3,2;+COPS? + +AT Command> INFO: Parser interpreted command AT+CGREG? + +AT Command> INFO: Parser interpreted command AT+CREG? + +AT Command> INFO: Parser interpreted command AT+COPS? + +AT Command> INFO: Parser interpreted command AT+CIMI + +AT Command> ERROR: Parser rejected command AT+CRSM=192,12258,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28480,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28617,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28589,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28618,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28433,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28619,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28435,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28486,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28621,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28613,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28472,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28438,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28437,0,0,15 + +AT Command> INFO: Parser interpreted command AT+CPIN? + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28439,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28436,0,0,15 + +AT Command> ERROR: Parser rejected command AT+CRSM=192,28440,0,0,15 + +AT Command> INFO: Parser interpreted command AT+CSQ + +AT Command> Exiting... diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/smartcom.txt b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/smartcom.txt new file mode 100644 index 0000000000..900f319254 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/tst/smartcom.txt @@ -0,0 +1,23 @@ +Fully implemented: +AT Command> INFO: Parser interpreted command AT+CGSN +AT Command> INFO: Parser interpreted command AT+CGMM +AT Command> INFO: Parser interpreted command AT+CGMI +AT Command> INFO: Parser interpreted command AT+CPIN? +AT Command> INFO: Parser interpreted command ATE0Q0V1+CMEE=1 +AT Command> INFO: Parser interpreted command AT+CFUN? +AT Command> INFO: Parser interpreted command AT+CFUN=1 +AT Command> INFO: Parser interpreted command AT+CIMI +AT Command> INFO: Parser interpreted command AT+COPS? +AT Command> ERROR: Parser rejected command AT+CREG +AT Command> INFO: Parser interpreted command AT+CGACT=1,1 +AT Command> INFO: Parser interpreted command AT+CGDCONT? + +Not implemented: +AT Command> ERROR: Parser rejected command AT+CNUM +AT Command> ERROR: Parser rejected command AT+CRSM +AT Command> ERROR: Parser rejected command AT+CGMR +AT Command> ERROR: Parser rejected command AT+CESQ +AT Command> ERROR: Parser rejected command AT+CNTI +AT Command> ERROR: Parser rejected command AT!BAND? +AT Command> ERROR: Parser rejected command AT+PACSP? + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.c new file mode 100644 index 0000000000..e5baac88e4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.c @@ -0,0 +1,799 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_api.c + +Version 0.1 + +Date 2012/02/28 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer running in the UE + to send/receive message to/from the user application layer + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "user_api.h" +#include "nas_log.h" +#include "socket.h" +#include "device.h" + +#include "at_command.h" +#include "at_response.h" +#include "at_error.h" + +#include "user_indication.h" + +#include <string.h> // strerror, memset +#include <netdb.h> // gai_strerror +#include <errno.h> // errno +#include <stdio.h> // sprintf +#include <unistd.h> // gethostname + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * Asynchronous notification procedure handlers + */ +static int _user_api_registration_handler(unsigned char id, const void* data, size_t size); +static int _user_api_location_handler(unsigned char id, const void* data, size_t size); +static int _user_api_network_handler(unsigned char id, const void* data, size_t size); +static int _user_api_pdn_connection_handler(unsigned char id, const void* data, size_t size); + +static int _user_api_send(at_response_t* data); + +/* ------------------- + * Connection endpoint + * ------------------- + * The connection endpoint is used to send/receive data to/from the + * user application layer. Its definition depends on the underlaying + * mechanism chosen to communicate (network socket, I/O terminal device). + * A connection endpoint is handled using an identifier, and functions + * used to retreive the file descriptor actually allocated by the system, + * to receive data, to send data, and to perform clean up when connection + * is shut down. + * Only one single end to end connection with the user is managed at a + * time. + */ +static struct { + /* Connection endpoint reference */ + void* endpoint; + /* Connection endpoint handlers */ + void* (*open) (int, const char*, const char*); + int (*getfd)(const void*); + ssize_t (*recv) (void*, char*, size_t); + ssize_t (*send) (const void*, const char*, size_t); + void (*close)(void*); +} _user_api_id; + +#define USER_API_OPEN(a, b, c) _user_api_id.open(a, b, c) +#define USER_API_GETFD() _user_api_id.getfd(_user_api_id.endpoint) +#define USER_API_RECV(a, b) _user_api_id.recv(_user_api_id.endpoint, a, b) +#define USER_API_SEND(a, b) _user_api_id.send(_user_api_id.endpoint, a, b) +#define USER_API_CLOSE() _user_api_id.close(_user_api_id.endpoint) + +/* + * The buffer used to receive data from the user application layer + */ +#define USER_API_RECV_BUFFER_SIZE 4096 +static char _user_api_recv_buffer[USER_API_RECV_BUFFER_SIZE]; + +/* + * The buffer used to send data to the user application layer + */ +#define USER_API_SEND_BUFFER_SIZE USER_API_RECV_BUFFER_SIZE +static char _user_api_send_buffer[USER_API_SEND_BUFFER_SIZE]; + +/* + * The decoded data received from the user application layer + */ +static struct { + int n_cmd; /* number of user data to be processed */ +#define USER_DATA_MAX 10 + at_command_t cmd[USER_DATA_MAX]; /* user data to be processed */ +} _user_data = {}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: user_api_initialize() ** + ** ** + ** Description: Initializes the user API from which the NAS layer ** + ** will send/receive messages to/from the user application ** + ** layer ** + ** ** + ** Inputs: host: The name of the host from which the user ** + ** application layer will connect ** + ** port: The local port number ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: _user_api_id ** + ** ** + ***************************************************************************/ +int user_api_initialize(const char* host, const char* port, + const char* devname, const char* devparams) +{ + LOG_FUNC_IN; + + gethostname(_user_api_send_buffer, USER_API_SEND_BUFFER_SIZE); + + if (devname != NULL) { + /* Initialize device handlers */ + _user_api_id.open = device_open; + _user_api_id.getfd = device_get_fd; + _user_api_id.recv = device_read; + _user_api_id.send = device_write; + _user_api_id.close = device_close; + + /* Initialize communication channel */ + _user_api_id.endpoint = USER_API_OPEN(DEVICE, devname, devparams); + if (_user_api_id.endpoint == NULL) { + LOG_TRACE(ERROR, "USR-API - Failed to open connection endpoint, " + "%s", strerror(errno)); + LOG_FUNC_RETURN (RETURNerror); + } + + LOG_TRACE(INFO, "USR-API - User's communication device %d is OPENED " + "on %s/%s", user_api_get_fd(), _user_api_send_buffer, devname); + } + else { + /* Initialize network socket handlers */ + _user_api_id.open = socket_udp_open; + _user_api_id.getfd = socket_get_fd; + _user_api_id.recv = socket_recv; + _user_api_id.send = socket_send; + _user_api_id.close = socket_close; + + /* Initialize communication channel */ + _user_api_id.endpoint = USER_API_OPEN(SOCKET_SERVER, host, port); + if (_user_api_id.endpoint == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + LOG_TRACE(ERROR, "USR-API - Failed to open connection endpoint, " + "%s", error); + LOG_FUNC_RETURN (RETURNerror); + } + + LOG_TRACE(INFO, "USR-API - User's UDP socket %d is BOUND to %s/%s", + user_api_get_fd(), _user_api_send_buffer, port); + } + + /* Register the asynchronous notification handlers */ + if (user_ind_register(USER_IND_REG, 0, _user_api_registration_handler) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - " + "Failed to register registration notification"); + } + else if (user_ind_register(USER_IND_LOC, 0, _user_api_location_handler) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - " + "Failed to register location notification"); + } + else if (user_ind_register(USER_IND_PLMN, 0, _user_api_network_handler) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - " + "Failed to register network notification"); + } + else if (user_ind_register(USER_IND_PLMN, 0, NULL) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - Failed to enable network notification"); + } + else if (user_ind_register(USER_IND_PDN, 0, _user_api_pdn_connection_handler) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - " + "Failed to register PDN connection notification"); + } + else if (user_ind_register(USER_IND_PDN, AT_CGACT, NULL) != RETURNok) { + LOG_TRACE(WARNING, "USR-API - " + "Failed to enable PDN connection notification"); + } + else { + LOG_TRACE(INFO, "USR-API - " + "Notification handlers successfully registered"); + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: user_api_get_fd() ** + ** ** + ** Description: Get the file descriptor of the connection endpoint used ** + ** to send/receive messages to/from the user application ** + ** layer ** + ** ** + ** Inputs: None ** + ** Others: _user_api_id ** + ** ** + ** Outputs: Return: The file descriptor of the connection end- ** + ** point used by the user application layer ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_api_get_fd(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (USER_API_GETFD()); +} + +/**************************************************************************** + ** ** + ** Name: user_api_get_data() ** + ** ** + ** Description: Get a generic pointer to the user data structure at the ** + ** given index. Casting to the proper type is necessary ** + ** before its usage. ** + ** ** + ** Inputs: index: Index of the user data structure to get ** + ** Others: _user_data ** + ** ** + ** Outputs: Return: A generic pointer to the user data ** + ** structure ** + ** Others: None ** + ** ** + ***************************************************************************/ +const void* user_api_get_data(int index) +{ + LOG_FUNC_IN; + if (index < _user_data.n_cmd) { + LOG_FUNC_RETURN ((void*)(&_user_data.cmd[index])); + } + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: user_api_read_data() ** + ** ** + ** Description: Read data received from the user application layer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** from which data have been received ** + ** Others: _user_api_id ** + ** ** + ** Outputs: Return: The number of bytes read when success; ** + ** RETURNerror Otherwise ** + ** Others: _user_api_recv_buffer, _user_api_id ** + ** ** + ***************************************************************************/ +int user_api_read_data(int fd) +{ + LOG_FUNC_IN; + + int rbytes; + + /* Sanity check */ + int sfd = user_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "USR-API - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd); + LOG_FUNC_RETURN (RETURNerror); + } + + memset(_user_api_recv_buffer, 0, USER_API_RECV_BUFFER_SIZE); + + /* Receive data from the user application layer */ + rbytes = USER_API_RECV(_user_api_recv_buffer, USER_API_RECV_BUFFER_SIZE); + if (rbytes == RETURNerror) { + LOG_TRACE(ERROR, "USR-API - recv() failed, %s", strerror(errno)); + LOG_FUNC_RETURN (RETURNerror); + } + else if (rbytes == 0) { + //LOG_TRACE(WARNING, "USR-API - A signal was caught"); + } + else { + LOG_TRACE(INFO, "USR-API - %d bytes received " + "from the user application layer", rbytes); + LOG_DUMP(_user_api_recv_buffer, rbytes); + } + + LOG_FUNC_RETURN (rbytes); +} + +/**************************************************************************** + ** ** + ** Name: user_api_send_data() ** + ** ** + ** Description: Send data to the user application layer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** to which data have to be sent ** + ** length: Number of bytes to send ** + ** Others: _user_api_send_buffer, _user_api_id ** + ** ** + ** Outputs: Return: The number of bytes sent when success; ** + ** RETURNerror Otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_send_data(int length) +{ + int sbytes = USER_API_SEND(_user_api_send_buffer, length); + if (sbytes == RETURNerror) { + LOG_TRACE(ERROR, "USR-API - send() failed, %s", strerror(errno)); + return RETURNerror; + } + else if (sbytes == 0) { + LOG_TRACE(WARNING, "USR-API - A signal was caught"); + } + else { + LOG_TRACE(INFO, "USR-API - %d bytes sent " + "to the user application layer", sbytes); + LOG_DUMP(_user_api_send_buffer, sbytes); + } + + return sbytes; +} +int user_api_send_data(int fd, int length) +{ + LOG_FUNC_IN; + + /* Sanity check */ + int sfd = user_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "USR-API - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Send data to the user application layer */ + int sbytes = 0; + if (length > 0) { + sbytes = _user_api_send_data(length); + } + LOG_FUNC_RETURN (sbytes); +} + +/**************************************************************************** + ** ** + ** Name: user_api_close() ** + ** ** + ** Description: Close the user API from which the NAS layer sent/received ** + ** messages to/from the user application layer ** + ** ** + ** Inputs: fd: File descriptor of the connection endpoint ** + ** allocated by the system to communicate ** + ** with the user application layer ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: _user_api_id ** + ** ** + ***************************************************************************/ +void user_api_close(int fd) +{ + LOG_FUNC_IN; + + /* Sanity check */ + int sfd = user_api_get_fd(); + if (fd != sfd) { + LOG_TRACE(ERROR, "USR-API - Endpoint %d is not the one created for communication with the user application layer (%d)", fd, sfd); + LOG_FUNC_OUT; + return; + } + + /* Cleanup the connection endpoint */ + USER_API_CLOSE(); + _user_api_id.endpoint = NULL; + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: user_api_decode_data() ** + ** ** + ** Description: Parses the message received from the user application ** + ** (mainly AT commands) and fills the user data structure. ** + ** Returns an AT syntax error code to the user application ** + ** layer when the AT command failed to be decoded. ** + ** ** + ** Inputs: length: Number of bytes to decode ** + ** Others: _user_api_recv_buffer ** + ** ** + ** Outputs: Return: The number of AT commands succeessfully ** + ** decoded ** + ** Others: _user_api_send_buffer, _user_data ** + ** ** + ***************************************************************************/ +int user_api_decode_data(int length) +{ + LOG_FUNC_IN; + + /* Parse the AT command line */ + LOG_TRACE(INFO, "USR-API - Decode user data: %s", _user_api_recv_buffer); + _user_data.n_cmd = at_command_decode(_user_api_recv_buffer, length, + _user_data.cmd); + + if (_user_data.n_cmd > 0) { + /* AT command data received from the user application layer + * has been successfully decoded */ + LOG_TRACE(INFO, "USR-API - %d AT command%s ha%s been successfully " + "decoded", _user_data.n_cmd, + (_user_data.n_cmd > 1) ? "s" : "", + (_user_data.n_cmd > 1) ? "ve" : "s"); + } + else + { + int bytes; + + /* Failed to decode AT command data received from the user + * application layer; Return syntax error code message */ + LOG_TRACE(ERROR, "USR-API - Syntax error: Failed to decode " + "AT command data %s", _user_api_recv_buffer); + + /* Encode the syntax error code message */ + bytes = at_error_encode(_user_api_send_buffer, AT_ERROR_SYNTAX, + AT_ERROR_OPERATION_NOT_SUPPORTED); + + /* Send the syntax error code message */ + (void) _user_api_send_data(bytes); + } + + LOG_FUNC_RETURN (_user_data.n_cmd); +} + +/**************************************************************************** + ** ** + ** Name: user_api_encode_data() ** + ** ** + ** Description: Encodes AT command response message ** + ** ** + ** Inputs data: Generic pointer to the data to encode ** + ** success_code: Indicates whether success code has to be ** + ** displayed or not (covers the case where ** + ** more than one AT command is executed in ** + ** the same user command line). ** + ** Others: None ** + ** ** + ** Outputs: Return: The number of characters that have been ** + ** successfully encoded; ** + ** RETURNerror otherwise. ** + ** Others: _user_api_send_buffer ** + ** ** + ***************************************************************************/ +int user_api_encode_data(const void* data, int success_code) +{ + LOG_FUNC_IN; + + const at_response_t* user_data = (at_response_t*)(data); + int bytes; + + /* Encode AT command error message */ + if (user_data->cause_code != AT_ERROR_SUCCESS) + { + bytes = at_error_encode(_user_api_send_buffer, AT_ERROR_CME, + user_data->cause_code); + } + /* Encode AT command response message */ + else + { + bytes = at_response_encode(_user_api_send_buffer, user_data); + + /* Add success result code */ + if ( (success_code) && (bytes != RETURNerror) ) { + bytes += at_error_encode(&_user_api_send_buffer[bytes], + AT_ERROR_OK, 0); + } + } + + if (bytes != RETURNerror) { + LOG_TRACE(INFO, "USR-API - %d bytes encoded", bytes); + } + else { + LOG_TRACE(ERROR, "USR-API - Syntax error: Failed to encode AT " + "response data (%d)", user_data->id); + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: user_api_callback() ** + ** ** + ** Description: Notifies the user application that asynchronous notifica- ** + ** tion has been received from the EPS Mobility Management ** + ** sublayer. ** + ** ** + ** Inputs: stat: Network registration status ** + ** tac: Location/Tracking Area Code ** + ** ci: Indentifier of the serving cell ** + ** AcT: Access Technology supported by the cell ** + ** data: Data string to display to the user ** + ** size: Size of the notification data (only used ** + ** to display string information to the user ** + ** application) ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT, + const char* data, size_t size) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if (size > 1) { + /* + * The list of available operators present in the network has to be + * displayed to the user application + */ + rc = user_ind_notify(USER_IND_PLMN, (void*)data, size); + } + else { + user_indication_t ind; + ind.notification.reg.status = stat; + if (size > 0) { + /* The UE's network registration status has changed */ + rc = user_ind_notify(USER_IND_REG, (void*)&ind, 0); + } + if (rc != RETURNerror) { + /* The UE's location area has changed or, + * the UE's network registration status has changed and + * only location information notification is enabled */ + ind.notification.loc.tac = tac; + ind.notification.loc.ci = ci; + ind.notification.loc.AcT = AcT; + rc = user_ind_notify(USER_IND_LOC, (void*)&ind, 0); + } + } + + if (rc != RETURNerror) { + LOG_FUNC_RETURN (RETURNok); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: user_api_esm_callback() ** + ** ** + ** Description: Notifies the user application that asynchronous notifica- ** + ** tion has been received from the EPS Session Management ** + ** sublayer. ** + ** ** + ** Inputs: cid: PDN connection identifier ** + ** state: PDN connection status ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_api_esm_callback(int cid, network_pdn_state_t state) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + user_indication_t ind; + ind.notification.pdn.cid = cid; + ind.notification.pdn.status = state; + /* The status of the specified PDN connection has changed */ + rc = user_ind_notify(USER_IND_PDN, (void*)&ind, 0); + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _user_api_send() ** + ** ** + ** Description: Encodes and sends data to the user application layer ** + ** ** + ** Inputs: data: The data to send ** + ** Others: _user_api_send_buffer, _user_api_id ** + ** ** + ** Outputs: Return: The number of bytes sent when success; ** + ** RETURNerror Otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_send(at_response_t* data) +{ + LOG_FUNC_IN; + + /* Encode AT command response message */ + int bytes = at_response_encode(_user_api_send_buffer, data); + + /* Send the AT command response message to the user application */ + if (bytes != RETURNerror) { + bytes = _user_api_send_data(bytes); + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _user_api_registration_handler() ** + ** ** + ** Description: Procedure executed upon receiving registration notifica- ** + ** tion whenever there is a change in the UE's network re- ** + ** gistration status in GERAN/UTRAN/E-UTRAN. ** + ** The network registration data are then displayed to the ** + ** user. ** + ** ** + ** Inputs: id: Network registration AT command identifier ** + ** data: Generic pointer to the registration data ** + ** size: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes actually sent to the ** + ** user application ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_registration_handler(unsigned char id, const void* data, + size_t size) +{ + LOG_FUNC_IN; + + /* Get registration notification data */ + user_ind_reg_t* reg = (user_ind_reg_t*)data; + + /* Setup AT command response message for AT+CEREG? read command */ + at_response_t at_response; + at_response.id = id; // may be +CREG, +CGREG, +CEREG + at_response.type = AT_COMMAND_GET; + at_response.mask = AT_RESPONSE_NO_PARAM; + at_response.response.cereg.n = AT_CEREG_ON; + at_response.response.cereg.stat = reg->status; + + /* Encode and send the AT command response message to the user */ + int bytes = _user_api_send(&at_response); + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _user_api_location_handler() ** + ** ** + ** Description: Procedure executed upon receiving location notification ** + ** whenever there is a change in the network serving cell ** + ** in GERAN/UTRAN/E-UTRAN. ** + ** The location data are then displayed to the user. ** + ** ** + ** Inputs: id: Network registration AT command identifier ** + ** data: Generic pointer to the registration data ** + ** size: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes actually sent to the ** + ** user application ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_location_handler(unsigned char id, const void* data, + size_t size) +{ + LOG_FUNC_IN; + + /* Get location notification data */ + user_ind_loc_t* loc = (user_ind_loc_t*)data; + + /* Setup AT command response message for AT+CEREG? read command */ + at_response_t at_response; + at_response.id = id; // may be +CREG, +CGREG, +CEREG + at_response.type = AT_COMMAND_GET; + at_response.mask = (AT_CEREG_RESP_TAC_MASK | AT_CEREG_RESP_CI_MASK); + at_response.response.cereg.n = AT_CEREG_BOTH; + at_response.response.cereg.stat = loc->status; + sprintf(at_response.response.cereg.tac, "%.4x", loc->tac); // two byte + sprintf(at_response.response.cereg.ci, "%.8x", loc->ci); // four byte + if (at_response.response.cereg.AcT != NET_ACCESS_UNAVAILABLE) { + at_response.response.cereg.AcT = loc->AcT; + at_response.mask |= AT_CEREG_RESP_ACT_MASK; + } + + /* Encode and send the AT command response message to the user */ + int bytes = _user_api_send(&at_response); + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _user_api_network_handler() ** + ** ** + ** Description: Procedure executed whenever the list of operators present ** + ** in the network has to be displayed to the user. ** + ** ** + ** Inputs: id: Not used ** + ** data: Generic pointer to the list of operators ** + ** size: The size of the data to display ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes actually sent to the ** + ** user application ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_network_handler(unsigned char id, const void* data, + size_t size) +{ + LOG_FUNC_IN; + + /* Setup AT command response message for AT+COPS=? test command */ + at_response_t at_response; + at_response.id = AT_COPS; + at_response.type = AT_COMMAND_TST; + at_response.response.cops.tst.data = (char*)data; + at_response.response.cops.tst.size = size; + + /* Encode and send the AT command response message to the user */ + int bytes = _user_api_send(&at_response); + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _user_api_pdn_connection_handler() ** + ** ** + ** Description: Procedure executed upon receiving PDN connection notifi- ** + ** cation whenever the user or the network has activated or ** + ** desactivated a PDN connection. ** + ** The PDN connection data are then displayed to the user. ** + ** ** + ** Inputs: id: Not used ** + ** data: Generic pointer to the PDN connection data ** + ** size: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes actually sent to the ** + ** user application ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _user_api_pdn_connection_handler(unsigned char id, const void* data, + size_t size) +{ + LOG_FUNC_IN; + + /* Get PDN connection notification data */ + user_ind_pdn_t* pdn = (user_ind_pdn_t*)data; + + /* Setup AT command unsolicited result response message for +CGEV */ + at_response_t at_response; + at_response.id = AT_CGEV; + at_response.type = AT_COMMAND_GET; + at_response.mask = AT_RESPONSE_CGEV_MASK; + at_response.response.cgev.cid = pdn->cid; + at_response.response.cgev.code = pdn->status; + + /* Encode and send the AT command response message to the user */ + int bytes = _user_api_send(&at_response); + + LOG_FUNC_RETURN (bytes); +} + +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.h b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.h new file mode 100644 index 0000000000..b1d83cc043 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_api.h @@ -0,0 +1,58 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_api.h + +Version 0.1 + +Date 2012/02/28 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer running in the UE + to send/receive message to/from the user application layer + +*****************************************************************************/ +#ifndef __USER_API_H__ +#define __USER_API_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int user_api_initialize(const char* host, const char* port, const char* devname, const char* devparams); + +int user_api_emm_callback(Stat_t stat, tac_t tac, ci_t ci, AcT_t AcT, const char* data, size_t size); +int user_api_esm_callback(int cid, network_pdn_state_t state); + +int user_api_get_fd(void); +const void* user_api_get_data(int index); + +int user_api_read_data(int fd); +int user_api_send_data(int fd, int length); +void user_api_close(int fd); + +int user_api_decode_data(int length); +int user_api_encode_data(const void* data, int add_success_code); + +#endif /* __USER_API_H__ */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.c b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.c new file mode 100644 index 0000000000..2deb65dd68 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.c @@ -0,0 +1,156 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_indication.c + +Version 0.1 + +Date 2012/10/25 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines functions which allow the user application to register + procedures to be executed upon receiving asynchronous notifi- + cation. + +*****************************************************************************/ + +#include "user_indication.h" +#include "nas_log.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Notification handler */ +static struct { + unsigned char id; + unsigned char mask; + user_ind_callback_t callback[USER_IND_MAX]; +} _user_ind_handler = {}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: user_ind_register() ** + ** ** + ** Description: Register the specified procedure to be executed upon ** + ** receiving the given asynchronous notification ** + ** ** + ** Inputs: ind: The notification type ** + ** id: The notification identifier ** + ** cb: The procedure to register ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _user_ind_handler ** + ** ** + ***************************************************************************/ +int user_ind_register(user_ind_t ind, unsigned char id, user_ind_callback_t cb) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (ind < USER_IND_MAX) { + /* Register the notification callback */ + if (cb != NULL) { + _user_ind_handler.callback[ind] = cb; + } + else { + _user_ind_handler.id = id; + _user_ind_handler.mask |= (1 << ind); + } + rc = RETURNok; + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: user_ind_deregister() ** + ** ** + ** Description: Prevent a registered procedure from being executed upon ** + ** receiving the given asynchronous notification ** + ** ** + ** Inputs: ind: The notification identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _user_ind_handler ** + ** ** + ***************************************************************************/ +int user_ind_deregister(user_ind_t ind) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (ind < USER_IND_MAX) { + _user_ind_handler.mask &= ~(1 << ind); + rc = RETURNok; + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: user_ind_notify() ** + ** ** + ** Description: Execute the procedure if registered for the received ** + ** notification identifier ** + ** ** + ** Inputs: ind: The notification identifier ** + ** data: Generic pointer to the notification data ** + ** size: The size parameter of the registered call- ** + ** back procedure to execute ** + ** Others: _user_ind_handler ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_ind_notify(user_ind_t ind, const void* data, size_t size) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (ind < USER_IND_MAX) { + if (_user_ind_handler.mask & (1 << ind)) { + /* Execute the notification callback */ + user_ind_callback_t notify = _user_ind_handler.callback[ind]; + if (notify != NULL) { + rc = (*notify)(_user_ind_handler.id, data, size); + } + } + else { + /* Silently discard not registered notification */ + rc = RETURNok; + } + } + + LOG_FUNC_RETURN(rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.h b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.h new file mode 100644 index 0000000000..9f04d60821 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/user/user_indication.h @@ -0,0 +1,103 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_indication.h + +Version 0.1 + +Date 2012/10/25 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Defines functions which allow the user application to register + procedures to be executed upon receiving asynchronous notifi- + cation. + +*****************************************************************************/ +#ifndef __USER_IND_H__ +#define __USER_IND_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Type of notification that may be asynchronously received by the user + */ +typedef enum { + USER_IND_REG = 0, /* Registration notification */ + USER_IND_LOC, /* Location notification */ + USER_IND_PLMN, /* Network notification */ + USER_IND_PDN, /* PDN connection notification */ + USER_IND_MAX +} user_ind_t; + +/* + * Registration notification are received whenever there is a change in the + * UE's network registration status in GERAN/UTRAN/E-UTRAN + */ +typedef struct { + Stat_t status; /* network registration status */ +} user_ind_reg_t; + +/* + * Location notification are received whenever there is a change in the + * network serving cell in GERAN/UTRAN/E-UTRAN + */ +typedef struct { + Stat_t status; /* network registration status */ + tac_t tac; /* Location/Tracking area code */ + ci_t ci; /* GERAN/UTRAN/E-UTRAN cell ID */ + AcT_t AcT; /* Supported Access Technology */ +} user_ind_loc_t; + +/* + * PDN connection notification are received whenever the user or the network + * has activated or desactivated a PDN connection + */ +typedef struct { + UInt8_t cid; /* PDN connection identifier */ + network_pdn_state_t status; /* PDN connection status */ +} user_ind_pdn_t; + +/* + * Structure of asynchronous notification received by the user + */ +typedef struct { + union { + user_ind_reg_t reg; /* Registration notification */ + user_ind_loc_t loc; /* Location notification */ + user_ind_pdn_t pdn; /* PDN connection notification */ + } notification; +} user_indication_t; + +/* + * Type of procedure executed upon receiving registered notification + */ +typedef int (*user_ind_callback_t) (unsigned char, const void*, size_t); + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int user_ind_register(user_ind_t ind, unsigned char id, user_ind_callback_t cb); +int user_ind_deregister(user_ind_t ind); +int user_ind_notify(user_ind_t ind, const void* data, size_t size); + +#endif /* __USER_IND_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/usim/Makefile b/openair-cn/NAS/EURECOM-NAS/src/api/usim/Makefile new file mode 100644 index 0000000000..17da9df138 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/usim/Makefile @@ -0,0 +1,21 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(EMMMSGDIR) -I$(ESMMSGDIR) +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +all: $(OBJS) + +%.o: %.c Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +clean: + $(RM) $(OBJS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.c b/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.c new file mode 100644 index 0000000000..156e5abffd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.c @@ -0,0 +1,399 @@ +/*------------------------------------------------------------------- + * Example algorithms f1, f1*, f2, f3, f4, f5, f5* + *------------------------------------------------------------------- + * + * A sample implementation of the example 3GPP authentication and + * key agreement functions f1, f1*, f2, f3, f4, f5 and f5*. This is + * a byte-oriented implementation of the functions, and of the block + * cipher kernel function Rijndael. + * + * This has been coded for clarity, not necessarily for efficiency. + * + * The functions f2, f3, f4 and f5 share the same inputs and have + * been coded together as a single function. f1, f1* and f5* are + * all coded separately. + * + *-----------------------------------------------------------------*/ + +#include "aka_functions.h" + +/*--------- Operator Variant Algorithm Configuration Field --------*/ + /*------- Insert your value of OP here -------*/ +u8 OP[16] = {0x63, 0xbf, 0xa5, 0x0e, 0xe6, 0x52, 0x33, 0x65, + 0xff, 0x14, 0xc1, 0xf4, 0x5f, 0x88, 0x73, 0x7d}; + /*------- Insert your value of OP here -------*/ + +/*------------------------------------------------------------------- + * Algorithm f1 + *------------------------------------------------------------------- + * + * Computes network authentication code MAC-A from key K, random + * challenge RAND, sequence number SQN and authentication management + * field AMF. + * + *-----------------------------------------------------------------*/ +void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], + u8 mac_a[8] ) +{ + u8 op_c[16]; + u8 temp[16]; + u8 in1[16]; + u8 out1[16]; + u8 rijndaelInput[16]; + u8 i; + RijndaelKeySchedule( k ); + ComputeOPc( op_c ); + for (i=0; i<16; i++) + rijndaelInput[i] = rand[i] ^ op_c[i]; + RijndaelEncrypt( rijndaelInput, temp ); + for (i=0; i<6; i++) + { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } + for (i=0; i<2; i++) + { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } + /* XOR op_c and in1, rotate by r1=64, and XOR * + * on the constant c1 (which is all zeroes) */ + for (i=0; i<16; i++) + rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; + /* XOR on the value temp computed before */ + for (i=0; i<16; i++) + rijndaelInput[i] ^= temp[i]; + RijndaelEncrypt( rijndaelInput, out1 ); + for (i=0; i<16; i++) + out1[i] ^= op_c[i]; + for (i=0; i<8; i++) + mac_a[i] = out1[i]; + return; +} /* end of function f1 */ + +/*------------------------------------------------------------------- + * Algorithms f2-f5 + *------------------------------------------------------------------- + * + * Takes key K and random challenge RAND, and returns response RES, + * confidentiality key CK, integrity key IK and anonymity key AK. + * + *-----------------------------------------------------------------*/ +void f2345 ( u8 k[16], u8 rand[16], + u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ) +{ + u8 op_c[16]; + u8 temp[16]; + u8 out[16]; + u8 rijndaelInput[16]; + u8 i; + RijndaelKeySchedule( k ); + ComputeOPc( op_c ); + for (i=0; i<16; i++) + rijndaelInput[i] = rand[i] ^ op_c[i]; + RijndaelEncrypt( rijndaelInput, temp ); + /* To obtain output block OUT2: XOR OPc and TEMP, * + * rotate by r2=0, and XOR on the constant c2 (which * + * is all zeroes except that the last bit is 1). */ + for (i=0; i<16; i++) + rijndaelInput[i] = temp[i] ^ op_c[i]; + rijndaelInput[15] ^= 1; + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) + out[i] ^= op_c[i]; + for (i=0; i<8; i++) + res[i] = out[i+8]; + for (i=0; i<6; i++) + ak[i] = out[i]; + +/* To obtain output block OUT3: XOR OPc and TEMP, * + * rotate by r3=32, and XOR on the constant c3 (which * + * is all zeroes except that the next to last bit is 1). */ + for (i=0; i<16; i++) + rijndaelInput[(i+12) % 16] = temp[i] ^ op_c[i]; + rijndaelInput[15] ^= 2; + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) + out[i] ^= op_c[i]; + for (i=0; i<16; i++) + ck[i] = out[i]; + /* To obtain output block OUT4: XOR OPc and TEMP, * + * rotate by r4=64, and XOR on the constant c4 (which * + * is all zeroes except that the 2nd from last bit is 1). */ + for (i=0; i<16; i++) + rijndaelInput[(i+8) % 16] = temp[i] ^ op_c[i]; + rijndaelInput[15] ^= 4; + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) + out[i] ^= op_c[i]; + for (i=0; i<16; i++) + ik[i] = out[i]; + return; +} /* end of function f2345 */ + +/*------------------------------------------------------------------- + * Algorithm f1* + *------------------------------------------------------------------- + * + * Computes resynch authentication code MAC-S from key K, random + * challenge RAND, sequence number SQN and authentication management + * field AMF. + * + *-----------------------------------------------------------------*/ +void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], + u8 mac_s[8] ) +{ + u8 op_c[16]; + u8 temp[16]; + u8 in1[16]; + u8 out1[16]; + u8 rijndaelInput[16]; + u8 i; + RijndaelKeySchedule( k ); + ComputeOPc( op_c ); + for (i=0; i<16; i++) + rijndaelInput[i] = rand[i] ^ op_c[i]; + RijndaelEncrypt( rijndaelInput, temp ); + for (i=0; i<6; i++) + { + in1[i] = sqn[i]; + in1[i+8] = sqn[i]; + } + for (i=0; i<2; i++) + { + in1[i+6] = amf[i]; + in1[i+14] = amf[i]; + } + /* XOR op_c and in1, rotate by r1=64, and XOR * + * on the constant c1 (which is all zeroes) */ + for (i=0; i<16; i++) + rijndaelInput[(i+8) % 16] = in1[i] ^ op_c[i]; + /* XOR on the value temp computed before */ + for (i=0; i<16; i++) + rijndaelInput[i] ^= temp[i]; + RijndaelEncrypt( rijndaelInput, out1 ); + for (i=0; i<16; i++) + out1[i] ^= op_c[i]; + for (i=0; i<8; i++) + mac_s[i] = out1[i+8]; + return; +} /* end of function f1star */ + +/*------------------------------------------------------------------- + * Algorithm f5* + *------------------------------------------------------------------- + * + * Takes key K and random challenge RAND, and returns resynch + * anonymity key AK. + * + *-----------------------------------------------------------------*/ +void f5star( u8 k[16], u8 rand[16], + u8 ak[6] ) +{ + u8 op_c[16]; + u8 temp[16]; + u8 out[16]; + u8 rijndaelInput[16]; + u8 i; + RijndaelKeySchedule( k ); + ComputeOPc( op_c ); + for (i=0; i<16; i++) + rijndaelInput[i] = rand[i] ^ op_c[i]; + RijndaelEncrypt( rijndaelInput, temp ); + /* To obtain output block OUT5: XOR OPc and TEMP, * + * rotate by r5=96, and XOR on the constant c5 (which * + * is all zeroes except that the 3rd from last bit is 1). */ + for (i=0; i<16; i++) + rijndaelInput[(i+4) % 16] = temp[i] ^ op_c[i]; + rijndaelInput[15] ^= 8; + RijndaelEncrypt( rijndaelInput, out ); + for (i=0; i<16; i++) + out[i] ^= op_c[i]; + for (i=0; i<6; i++) + ak[i] = out[i]; + return; +} /* end of function f5star */ +/*------------------------------------------------------------------- + * Function to compute OPc from OP and K. Assumes key schedule has + already been performed. + *-----------------------------------------------------------------*/ +void ComputeOPc( u8 op_c[16] ) +{ + u8 i; + RijndaelEncrypt( OP, op_c ); + for (i=0; i<16; i++) + op_c[i] ^= OP[i]; + return; +} /* end of function ComputeOPc */ +/*-------------------- Rijndael round subkeys ---------------------*/ +u8 roundKeys[11][4][4]; +/*--------------------- Rijndael S box table ----------------------*/ +u8 S[256] = { + 99,124,119,123,242,107,111,197, 48, 1,103, 43,254,215,171,118, +202,130,201,125,250, 89, 71,240,173,212,162,175,156,164,114,192, +183,253,147, 38, 54, 63,247,204, 52,165,229,241,113,216, 49, 21, + 4,199, 35,195, 24,150, 5,154, 7, 18,128,226,235, 39,178,117, + 9,131, 44, 26, 27,110, 90,160, 82, 59,214,179, 41,227, 47,132, + 83,209, 0,237, 32,252,177, 91,106,203,190, 57, 74, 76, 88,207, +208,239,170,251, 67, 77, 51,133, 69,249, 2,127, 80, 60,159,168, + 81,163, 64,143,146,157, 56,245,188,182,218, 33, 16,255,243,210, +205, 12, 19,236, 95,151, 68, 23,196,167,126, 61,100, 93, 25,115, + 96,129, 79,220, 34, 42,144,136, 70,238,184, 20,222, 94, 11,219, +224, 50, 58, 10, 73, 6, 36, 92,194,211,172, 98,145,149,228,121, +231,200, 55,109,141,213, 78,169,108, 86,244,234,101,122,174, 8, +186,120, 37, 46, 28,166,180,198,232,221,116, 31, 75,189,139,138, +112, 62,181,102, 72, 3,246, 14, 97, 53, 87,185,134,193, 29,158, +225,248,152, 17,105,217,142,148,155, 30,135,233,206, 85, 40,223, +140,161,137, 13,191,230, 66,104, 65,153, 45, 15,176, 84,187, 22, +}; +/*------- This array does the multiplication by x in GF(2^8) ------*/ +u8 Xtime[256] = { + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, + 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, + 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, + 96, 98,100,102,104,106,108,110,112,114,116,118,120,122,124,126, +128,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158, +160,162,164,166,168,170,172,174,176,178,180,182,184,186,188,190, +192,194,196,198,200,202,204,206,208,210,212,214,216,218,220,222, +224,226,228,230,232,234,236,238,240,242,244,246,248,250,252,254, + 27, 25, 31, 29, 19, 17, 23, 21, 11, 9, 15, 13, 3, 1, 7, 5, + 59, 57, 63, 61, 51, 49, 55, 53, 43, 41, 47, 45, 35, 33, 39, 37, + 91, 89, 95, 93, 83, 81, 87, 85, 75, 73, 79, 77, 67, 65, 71, 69, +123,121,127,125,115,113,119,117,107,105,111,109, 99, 97,103,101, +155,153,159,157,147,145,151,149,139,137,143,141,131,129,135,133, +187,185,191,189,179,177,183,181,171,169,175,173,163,161,167,165, +219,217,223,221,211,209,215,213,203,201,207,205,195,193,199,197, +251,249,255,253,243,241,247,245,235,233,239,237,227,225,231,229 +}; +/*------------------------------------------------------------------- + * Rijndael key schedule function. Takes 16-byte key and creates + * all Rijndael's internal subkeys ready for encryption. + *-----------------------------------------------------------------*/ +void RijndaelKeySchedule( u8 key[16] ) +{ + u8 roundConst; + int i, j; + /* first round key equals key */ + for (i=0; i<16; i++) + roundKeys[0][i & 0x03][i>>2] = key[i]; + roundConst = 1; + /* now calculate round keys */ + for (i=1; i<11; i++) + { + roundKeys[i][0][0] = S[roundKeys[i-1][1][3]] + ^ roundKeys[i-1][0][0] ^ roundConst; + roundKeys[i][1][0] = S[roundKeys[i-1][2][3]] + ^ roundKeys[i-1][1][0]; + roundKeys[i][2][0] = S[roundKeys[i-1][3][3]] + ^ roundKeys[i-1][2][0]; + roundKeys[i][3][0] = S[roundKeys[i-1][0][3]] + ^ roundKeys[i-1][3][0]; + for (j=0; j<4; j++) + { + roundKeys[i][j][1] = roundKeys[i-1][j][1] ^ roundKeys[i][j][0]; + roundKeys[i][j][2] = roundKeys[i-1][j][2] ^ roundKeys[i][j][1]; + roundKeys[i][j][3] = roundKeys[i-1][j][3] ^ roundKeys[i][j][2]; + } + /* update round constant */ + roundConst = Xtime[roundConst]; + } + return; +} /* end of function RijndaelKeySchedule */ +/* Round key addition function */ +void KeyAdd(u8 state[4][4], u8 roundKeys[11][4][4], int round) +{ + int i, j; + for (i=0; i<4; i++) + for (j=0; j<4; j++) + state[i][j] ^= roundKeys[round][i][j]; + return; +} +/* Byte substitution transformation */ +int ByteSub(u8 state[4][4]) +{ + int i, j; + for (i=0; i<4; i++) + for (j=0; j<4; j++) + state[i][j] = S[state[i][j]]; + return 0; +} +/* Row shift transformation */ +void ShiftRow(u8 state[4][4]) +{ + u8 temp; + /* left rotate row 1 by 1 */ + temp = state[1][0]; + state[1][0] = state[1][1]; + state[1][1] = state[1][2]; + state[1][2] = state[1][3]; + state[1][3] = temp; + /* left rotate row 2 by 2 */ + temp = state[2][0]; + state[2][0] = state[2][2]; + state[2][2] = temp; + temp = state[2][1]; + state[2][1] = state[2][3]; + state[2][3] = temp; + /* left rotate row 3 by 3 */ + temp = state[3][0]; + state[3][0] = state[3][3]; + state[3][3] = state[3][2]; + state[3][2] = state[3][1]; + state[3][1] = temp; + return; +} +/* MixColumn transformation*/ +void MixColumn(u8 state[4][4]) +{ + u8 temp, tmp, tmp0; + int i; + /* do one column at a time */ + for (i=0; i<4;i++) + { + temp = state[0][i] ^ state[1][i] ^ state[2][i] ^ state[3][i]; + tmp0 = state[0][i]; + /* Xtime array does multiply by x in GF2^8 */ + tmp = Xtime[state[0][i] ^ state[1][i]]; + state[0][i] ^= temp ^ tmp; + tmp = Xtime[state[1][i] ^ state[2][i]]; + state[1][i] ^= temp ^ tmp; + tmp = Xtime[state[2][i] ^ state[3][i]]; + state[2][i] ^= temp ^ tmp; + tmp = Xtime[state[3][i] ^ tmp0]; + state[3][i] ^= temp ^ tmp; + } + return; +} +/*------------------------------------------------------------------- + * Rijndael encryption function. Takes 16-byte input and creates + * 16-byte output (using round keys already derived from 16-byte + * key). + *-----------------------------------------------------------------*/ +void RijndaelEncrypt( u8 input[16], u8 output[16] ) +{ + u8 state[4][4]; + int i, r; + /* initialise state array from input byte string */ + for (i=0; i<16; i++) + state[i & 0x3][i>>2] = input[i]; + /* add first round_key */ + KeyAdd(state, roundKeys, 0); + /* do lots of full rounds */ + for (r=1; r<=9; r++) + { + ByteSub(state); + ShiftRow(state); + MixColumn(state); + KeyAdd(state, roundKeys, r); + } + /* final round */ + ByteSub(state); + ShiftRow(state); + KeyAdd(state, roundKeys, r); + /* produce output byte string from state array */ + for (i=0; i<16; i++) + { + output[i] = state[i & 0x3][i>>2]; + } + return; +} /* end of function RijndaelEncrypt */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.h b/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.h new file mode 100644 index 0000000000..7738acdc3a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/usim/aka_functions.h @@ -0,0 +1,14 @@ +typedef unsigned char u8; + +/*--------------------------- prototypes --------------------------*/ +void f1 ( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], + u8 mac_a[8] ); +void f2345 ( u8 k[16], u8 rand[16], + u8 res[8], u8 ck[16], u8 ik[16], u8 ak[6] ); +void f1star( u8 k[16], u8 rand[16], u8 sqn[6], u8 amf[2], + u8 mac_s[8] ); +void f5star( u8 k[16], u8 rand[16], + u8 ak[6] ); +void ComputeOPc( u8 op_c[16] ); +void RijndaelKeySchedule( u8 key[16] ); +void RijndaelEncrypt( u8 input[16], u8 output[16] ); diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.c b/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.c new file mode 100644 index 0000000000..11399074a4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.c @@ -0,0 +1,292 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source usim_api.h + +Version 0.1 + +Date 2012/10/09 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer to read/write + data to/from the USIM application + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "usim_api.h" +#include "nas_log.h" +#include "memory.h" + +#include "aka_functions.h" +#include <string.h> // memcpy, memset +#include <stdlib.h> // malloc, free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * The name of the file where are stored data of the USIM application + */ +#define USIM_API_NVRAM_FILENAME ".usim.nvram" + +/* + * The name of the environment variable which defines the directory + * where the USIM application file is located + */ +#define USIM_API_NVRAM_DIRNAME "USIM_DIR" + +/* + * Subscriber authentication security key + */ +#define USIM_API_K_SIZE 16 +#define USIM_API_K_VALUE "8BAF473F2F8FD09487CCCBD7097C6862" +static UInt8_t _usim_api_k[USIM_API_K_SIZE]; + +/* + * List of last used Sequence Numbers SQN + */ +static struct { + /* Highest sequence number the USIM has ever accepted */ + UInt32_t sqn_ms; + /* List of the last used sequence numbers */ +#define USIM_API_SQN_LIST_SIZE 32 + UInt8_t n_sqns; + UInt32_t sqn[USIM_API_SQN_LIST_SIZE]; +} _usim_api_data; + +static int _usim_api_check_sqn(UInt32_t seq, UInt8_t ind); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: usim_api_read() ** + ** ** + ** Description: Reads data from the USIM application ** + ** ** + ** Inputs: None ** + ** Others: File where are stored USIM data ** + ** ** + ** Outputs: data: Pointer to the USIM application data ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int usim_api_read(usim_data_t* data) +{ + LOG_FUNC_IN; + + /* Get USIM application pathname */ + char* path = memory_get_path(USIM_API_NVRAM_DIRNAME, + USIM_API_NVRAM_FILENAME); + if (path == NULL) { + LOG_TRACE(ERROR, "USIM-API - Failed to get USIM pathname"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Read USIM application data */ + if (memory_read(path, data, sizeof(usim_data_t)) != RETURNok) { + LOG_TRACE(ERROR, "USIM-API - %s file is either not valid " + "or not present", path); + free(path); + LOG_FUNC_RETURN (RETURNerror); + } + + /* initialize the subscriber authentication security key */ + memcpy(_usim_api_k, USIM_API_K_VALUE, USIM_API_K_SIZE); + + free(path); + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: usim_api_write() ** + ** ** + ** Description: Writes data to the USIM application ** + ** ** + ** Inputs: data: Pointer to the USIM application data ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int usim_api_write(const usim_data_t* data) +{ + LOG_FUNC_IN; + + /* Get USIM application pathname */ + char* path = memory_get_path(USIM_API_NVRAM_DIRNAME, + USIM_API_NVRAM_FILENAME); + if (path == NULL) { + LOG_TRACE(ERROR, "USIM-API - Failed to get USIM pathname"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Write USIM application data */ + if (memory_write(path, data, sizeof(usim_data_t)) != RETURNok) { + + LOG_TRACE(ERROR, "USIM-API - Unable to write USIM file %s", path); + free(path); + LOG_FUNC_RETURN (RETURNerror); + } + + free(path); + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: usim_api_authenticate() ** + ** ** + ** Description: Performs mutual authentication of the USIM to the network,** + ** checking whether authentication token AUTN can be accep- ** + ** ted. If so, returns an authentication response RES and ** + ** the ciphering and integrity keys. ** + ** In case of synch failure, returns a re-synchronization ** + ** token AUTS. ** + ** ** + ** 3GPP TS 31.102, section 7.1.1.1 ** + ** ** + ** Authentication and key generating function algorithms are ** + ** specified in 3GPP TS 35.206. ** + ** ** + ** Inputs: rand: Random challenge number ** + ** autn: Authentication token ** + ** AUTN = (SQN xor AK) || AMF || MAC ** + ** 48 16 64 bits ** + ** Others: Security key ** + ** ** + ** Outputs: auts: Re-synchronization token ** + ** res: Authentication response ** + ** ck: Cipherig key ** + ** ik: Integrity key ** + ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int usim_api_authenticate(const OctetString* rand, const OctetString* autn, + OctetString* auts, OctetString* res, + OctetString* ck, OctetString* ik) +{ + LOG_FUNC_IN; + + int rc; + + /* Compute the authentication response RES = f2K (RAND) */ + /* Compute the cipher key CK = f3K (RAND) */ + /* Compute the integrity key IK = f4K (RAND) */ + /* Compute the anonymity key AK = f5K (RAND) */ +#define USIM_API_AK_SIZE 6 + u8 ak[USIM_API_AK_SIZE]; + f2345(_usim_api_k, rand->value, + res->value, ck->value, ik->value, ak); + + /* Retrieve the sequence number SQN = (SQN ⊕ AK) ⊕ AK */ +#define USIM_API_SQN_SIZE USIM_API_AK_SIZE + u8 sqn[USIM_API_SQN_SIZE]; + for (int i = 0; i < USIM_API_SQN_SIZE; i++) { + sqn[i] = rand->value[i] ^ ak[i]; + } + + /* Compute XMAC = f1K (SQN || RAND || AMF) */ +#define USIM_API_XMAC_SIZE 8 + u8 xmac[USIM_API_XMAC_SIZE]; + f1(_usim_api_k, rand->value, sqn, &rand->value[USIM_API_SQN_SIZE], xmac); + + /* Compare the XMAC with the MAC included in AUTN */ +#if 0 // TODO !!! TO BE REMOVED +#define USIM_API_AMF_SIZE 2 + if ( memcmp(xmac, &rand->value[USIM_API_SQN_SIZE + USIM_API_AMF_SIZE], + USIM_API_XMAC_SIZE) != 0 ) { + LOG_FUNC_RETURN (RETURNerror); + } +#endif // TODO !!! TO BE REMOVED + + /* Verify that the received sequence number SQN is in the correct range */ + rc = _usim_api_check_sqn(*(UInt32_t*)(sqn), sqn[USIM_API_SQN_SIZE - 1]); + if (rc != RETURNok) { + /* Synchronisation failure; compute the AUTS parameter */ + + /* Concealed value of the counter SQNms in the USIM: + * Conc(SQNMS) = SQNMS ⊕ f5*K(RAND) */ + f5star(_usim_api_k, rand->value, ak); + +#define USIM_API_SQNMS_SIZE USIM_API_SQN_SIZE + u8 sqn_ms[USIM_API_SQNMS_SIZE]; + memset(sqn_ms, 0, USIM_API_SQNMS_SIZE); +#define USIM_API_SQN_MS_SIZE 3 + for (int i = 0; i < USIM_API_SQN_MS_SIZE; i++) { + sqn_ms[USIM_API_SQNMS_SIZE - i] = + ((UInt8_t*)(_usim_api_data.sqn_ms))[USIM_API_SQN_MS_SIZE - i]; + } + + u8 sqnms[USIM_API_SQNMS_SIZE]; + for (int i = 0; i < USIM_API_SQNMS_SIZE; i++) { + sqnms[i] = sqn_ms[i] ^ ak[i]; + } + + /* Synchronisation message authentication code: + * MACS = f1*K(SQNMS || RAND || AMF) */ +#define USIM_API_MACS_SIZE USIM_API_XMAC_SIZE + u8 macs[USIM_API_MACS_SIZE]; + f1star(_usim_api_k, rand->value, sqn_ms, + &rand->value[USIM_API_SQN_SIZE], macs); + + /* Synchronisation authentication token: + * AUTS = Conc(SQNMS) || MACS */ + memcpy(&auts->value[0], sqnms, USIM_API_SQNMS_SIZE); + memcpy(&auts->value[USIM_API_SQNMS_SIZE], macs, USIM_API_MACS_SIZE); + } + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _usim_api_check_sqn() ** + ** ** + ** Description: Verifies the freshness of sequence numbers to determine ** + ** whether the specified sequence number is in the correct ** + ** range and acceptabled by the USIM. ** + ** ** + ** 3GPP TS 31.102, Annex C.2 ** + ** ** + ** Inputs: seq: Sequence number value ** + ** ind: Index value ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _usim_api_check_sqn(UInt32_t seq, UInt8_t ind) +{ + /* TODO */ + return (RETURNok); +} + +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.h b/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.h new file mode 100644 index 0000000000..d81e60cfb7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/api/usim/usim_api.h @@ -0,0 +1,329 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source usim_api.h + +Version 0.1 + +Date 2012/10/09 + +Product NAS stack + +Subsystem Application Programming Interface + +Author Frederic Maurel + +Description Implements the API used by the NAS layer to read/write + data to/from the USIM application + +*****************************************************************************/ +#ifndef __USIM_API_H__ +#define __USIM_API_H__ + +#include "commonDef.h" +#include "networkDef.h" +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * USIM TLV parameter structure + * ---------------------------- + */ +#define USIM_TLV_T(SIZE) struct {UInt8_t type; UInt8_t length; Byte_t value[SIZE];} + +/* + * Non Access Stratum Configuration + * -------------------------------- + * TODO: To be encoded as BER-TLV + */ +typedef struct { + /* Determines the NAS signalling priority included in NAS + * messages */ +#define USIM_NAS_SIGNALLING_PRIORITY_TAG 0x80U + USIM_TLV_T(1) NAS_SignallingPriority; + /* Indicates whether the "NMO I, Network Mode of Operation I" + * indication is applied by the UE */ +#define USIM_NMO_I_BEHAVIOUR_TAG 0x81U + USIM_TLV_T(1) NMO_I_Behaviour; + /* Indicates whether attach with IMSI is performed when moving + * to a non-equivalent PLMN */ +#define USIM_ATTACH_WITH_IMSI_TAG 0x82U + USIM_TLV_T(1) AttachWithImsi; + /* Minimum value in minutes for the timer T controlling the + * periodic search for higher prioritized PLMNs */ +#define USIM_MINIMUM_PERIODIC_SEARCH_TIMER_TAG 0x83U + USIM_TLV_T(1) MinimumPeriodicSearchTimer; + /* Indicates whether the extended access barring is applicable + * for the UE */ +#define USIM_EXTENDED_ACCESS_BARRING_TAG 0x84U + USIM_TLV_T(1) ExtendedAccessBarring; + /* Indicates whether the timer T3245 and the related + * functionality is used by the UE */ +#define USIM_TIMER_T3245_BEHAVIOUR_TAG 0x85U + USIM_TLV_T(1) Timer_T3245_Behaviour; +} usim_nasconfig_t; + +/* + * Ciphering and Integrity Keys + * ---------------------------- + */ +typedef struct { + /* Key set identifier */ +#define USIM_KSI_MIN 0b000 +#define USIM_KSI_MAX 0b110 +#define USIM_KSI_NOT_AVAILABLE 0b111 + Byte_t ksi; + /* Cyphering key */ +#define USIM_CK_SIZE 16 + Byte_t ck[USIM_CK_SIZE]; + /* Integrity key */ +#define USIM_IK_SIZE 16 + Byte_t ik[USIM_IK_SIZE]; +} usim_keys_t; + +/* + * EPS NAS Security Context + * ------------------------ + * TODO: To be encoded as BER-TLV + */ +typedef struct { + /* Length of all subsequent data */ +#define USIM_EPS_NAS_SECURITY_CONTEXT_TAG 0xA0U + UInt8_t length; + /* Key set identifier KSI_ASME */ +#define USIM_KSI_ASME_TAG 0x80U + USIM_TLV_T(1) KSIasme; + /* ASME key (K_ASME) */ +#define USIM_K_ASME_TAG 0x81U +#define USIM_K_ASME_SIZE 32 + USIM_TLV_T(USIM_K_ASME_SIZE) Kasme; + /* Uplink NAS count */ +#define USIM_UL_NAS_COUNT_TAG 0x82U +#define USIM_UL_NAS_COUNT_SIZE 4 + USIM_TLV_T(USIM_UL_NAS_COUNT_SIZE) ulNAScount; + /* Downlink NAS count */ +#define USIM_DL_NAS_COUNT_TAG 0x83U +#define USIM_DL_NAS_COUNT_SIZE 4 + USIM_TLV_T(USIM_DL_NAS_COUNT_SIZE) dlNAScount; + /* Identifiers of selected NAS integrity and encryption + * algorithms */ +#define USIM_INT_ENC_ALGORITHMS_TAG 0x84U +#define USIM_INT_EIA0 0x00 +#define USIM_INT_EIA1 0x01 +#define USIM_INT_EIA2 0x02 +#define USIM_INT_EIA3 0x03 +#define USIM_INT_EIA4 0x04 +#define USIM_INT_EIA5 0x05 +#define USIM_INT_EIA6 0x06 +#define USIM_INT_EIA7 0x07 +#define USIM_ENC_EEA0 0x00 +#define USIM_ENC_EEA1 0x10 +#define USIM_ENC_EEA2 0x20 +#define USIM_ENC_EEA3 0x30 +#define USIM_ENC_EEA4 0x40 +#define USIM_ENC_EEA5 0x50 +#define USIM_ENC_EEA6 0x60 +#define USIM_ENC_EEA7 0x70 + USIM_TLV_T(1) algorithmID; +} usim_securityctx_t; + +/* + * Subcriber's Number structure + * ---------------------------- + */ +typedef struct { + Byte_t length; /* Length of BCD number/SSC contents */ + msisdn_t number; /* Mobile subscriber dialing number */ + Byte_t conf1_record_id; /* Configuration1 Record Identifier */ + Byte_t ext1_record_id; /* Extension1 Record Identifier */ +} usim_msisdn_t; + +/* + * PLMN Network Name structure + * --------------------------- + */ +typedef struct { + /* PLMN Full Name */ +#define USIM_PNN_FULLNAME_TAG 0x43U +#define USIM_PNN_FULLNAME_SIZE NET_FORMAT_LONG_SIZE + USIM_TLV_T(USIM_PNN_FULLNAME_SIZE) fullname; + /* PLMN Short Name */ +#define USIM_PNN_SHORTNAME_TAG 0x45U +#define USIM_PNN_SHORTNAME_SIZE NET_FORMAT_SHORT_SIZE + USIM_TLV_T(USIM_PNN_SHORTNAME_SIZE) shortname; +} usim_pnn_t; + +/* + * Operator PLMN List structure + * ---------------------------- + */ +typedef struct { + /* Tracking Area Identity range */ + plmn_t plmn; + tac_t start; + tac_t end; + /* PLMN Network Name Record Identifier */ + UInt8_t record_id; +} usim_opl_t; + +/* + * PLMN with Access Technology structure + * ------------------------------------- + */ +typedef struct { + plmn_t plmn; +#define USIM_ACT_GSM 0x8000 +#define USIM_ACT_COMPACT 0x4000 +#define USIM_ACT_CDMA_HRPD 0x2000 +#define USIM_ACT_CDMA_1xRTT 0x1000 +#define USIM_ACT_UTRAN 0x0080 +#define USIM_ACT_EUTRAN 0x0040 + UInt16_t AcT; +} usim_plmn_act_t; + +/* + * Location information structure + * ------------------------------ + */ +typedef struct { + UInt32_t tmsi; /* Temporary Mobile Subscriber Identity */ + lai_t lai; /* Location Area Identity */ + Byte_t reserved; /* Reserved for future use */ +#define USIM_LOCI_UPDATED 0x00 +#define USIM_LOCI_NOT_UPDATED 0x01 +#define USIM_LOCI_PLMN_NOT_ALLOWED 0x02 +#define USIM_LOCI_LA_NOT_ALLOWED 0x03 + Byte_t status; /* Location update status */ +} usim_loci_t; + +/* + * Packet Switched location information structure + * ---------------------------------------------- + */ +typedef struct { + UInt32_t p_tmsi; /* Packet Temporary Mobile Subscriber Identity */ + Byte_t signature[3]; /* P-TMSI signature value */ + RAI_t rai; /* Routing Area Identity */ +#define USIM_PSLOCI_UPDATED 0x00 +#define USIM_PSLOCI_NOT_UPDATED 0x01 +#define USIM_PSLOCI_PLMN_NOT_ALLOWED 0x02 +#define USIM_PSLOCI_LA_NOT_ALLOWED 0x03 + Byte_t status; /* Routing Area update status */ +} usim_psloci_t; + +/* + * EPS location information structure + * ---------------------------------- + */ +typedef struct { + GUTI_t guti; /* Globally Unique Temporary UE Identity */ + tai_t tai; /* Last visited registered Tracking Area Id */ +#define USIM_EPSLOCI_UPDATED 0x00 +#define USIM_EPSLOCI_NOT_UPDATED 0x01 +#define USIM_EPSLOCI_ROAMING_NOT_ALLOWED 0x02 + Byte_t status; /* EPS update status */ +} usim_epsloci_t; + +/* + * Administrative Data + * ------------------- + * Defines information concerning the mode of operation according to the + * type of USIM, such as normal (to be used by PLMN subscribers for 3G + * operations), type approval (to allow specific use of the ME during + * type approval procedures of e.g. the radio equipment), cell testing + * (to allow testing of a cell before commercial use of this cell), + * manufacturer specific (to allow the ME manufacturer to perform specific + * proprietary auto-test in its ME during e.g. maintenance phases). + * It also provides an indication about how some ME features shall work + * during normal operation as well as information about the length of the + * MNC, which is part of the International Mobile Subscriber Identity (IMSI). + */ +typedef struct { +#define USIM_NORMAL_MODE 0x00U +#define USIM_TYPE_APPROVAL_MODE 0x80U +#define USIM_NORMAL_SPECIFIC_MODE 0x01U +#define USIM_TYPE_APPROVAL_SPECIFIC_MODE 0x81U +#define USIM_MAINTENANCE_MODE 0x02U +#define USIM_CELL_TEST_MODE 0x04U + Byte_t UE_Operation_Mode; /* Mode of operation for the UE */ + UInt16_t Additional_Info; /* Additional information depending on + * the UE operation mode */ + Byte_t MNC_Length; /* Number of digits used for extracting + * the MNC from the IMSI */ +} usim_ad_t; + +/* + *--------------------------------------------------------------------------- + * Structure of the data handled by the USIM application + *--------------------------------------------------------------------------- + */ + +typedef struct { + /* + * Mandatory USIM configuration parameters + * --------------------------------------- + */ + imsi_t imsi; /* International Mobile Subscriber Identity */ + usim_keys_t keys; /* Ciphering and Integrity Keys */ + Byte_t hpplmn; /* Higher Priority PLMN search period */ + #define USIM_FPLMN_MAX 4 + plmn_t fplmn[USIM_FPLMN_MAX]; /* List of Forbidden PLMNs */ + usim_loci_t loci; /* Location Information */ + usim_psloci_t psloci; /* PS Location Information */ + usim_ad_t ad; /* Administrative Data */ + /* + * Optional USIM configuration parameters + * -------------------------------------- + */ + /* EPS NAS security context */ + usim_securityctx_t securityctx; + /* Subcriber's Number */ + usim_msisdn_t msisdn; + /* PLMN Network Name */ +#define USIM_PNN_MAX 8 + usim_pnn_t pnn[USIM_PNN_MAX]; + /* Operator PLMN List */ +#define USIM_OPL_MAX USIM_PNN_MAX + usim_opl_t opl[USIM_OPL_MAX]; + /* List of Equivalent HPLMNs */ +#define USIM_EHPLMN_MAX 2 + plmn_t ehplmn[USIM_EHPLMN_MAX]; + /* Home PLMN Selector with Access Technology */ + usim_plmn_act_t hplmn; + /* User controlled PLMN Selector with Access Technology */ +#define USIM_PLMN_MAX 8 + usim_plmn_act_t plmn[USIM_PLMN_MAX]; + /* Operator controlled PLMN Selector with Access Technology */ +#define USIM_OPLMN_MAX 8 + usim_plmn_act_t oplmn[USIM_OPLMN_MAX]; + /* EPS Location Information */ + usim_epsloci_t epsloci; + /* Non-Access Stratum configuration */ + usim_nasconfig_t nasconfig; +} usim_data_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int usim_api_read(usim_data_t* data); + +int usim_api_write(const usim_data_t* data); + +int usim_api_authenticate(const OctetString* rand, const OctetString* autn, + OctetString* auts, OctetString* res, + OctetString* ck, OctetString* ik); + +#endif /* __USIM_API_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/Attach.c b/openair-cn/NAS/EURECOM-NAS/src/emm/Attach.c new file mode 100644 index 0000000000..23c8ba5741 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/Attach.c @@ -0,0 +1,2388 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source Attach.c + +Version 0.1 + +Date 2012/12/04 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the attach related EMM procedure executed by the + Non-Access Stratum. + + To get internet connectivity from the network, the network + have to know about the UE. When the UE is switched on, it + has to initiate the attach procedure to get initial access + to the network and register its presence to the Evolved + Packet Core (EPC) network in order to receive EPS services. + + As a result of a successful attach procedure, a context is + created for the UE in the MME, and a default bearer is esta- + blished between the UE and the PDN-GW. The UE gets the home + agent IPv4 and IPv6 addresses and full connectivity to the + IP network. + + The network may also initiate the activation of additional + dedicated bearers for the support of a specific service. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "networkDef.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" +#include "esm_sap.h" +#include "emm_cause.h" + +#ifdef NAS_MME +#include "mme_api.h" +#endif + +#include <string.h> // memcmp, memcpy +#include <stdlib.h> // malloc, free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* String representation of the EPS attach type */ +static const char* _emm_attach_type_str[] = { + "EPS", "IMSI", "EMERGENCY", "RESERVED" +}; + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the attach procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Timer handlers + */ +void* _emm_attach_t3410_handler(void*); +static void* _emm_attach_t3411_handler(void*); +static void* _emm_attach_t3402_handler(void*); + +/* + * Abnormal case attach procedure + */ +static void _emm_attach_abnormal_cases_bcd(emm_sap_t*); + +/* + * Internal data used for attach procedure + */ +static struct { +#define EMM_ATTACH_COUNTER_MAX 5 + unsigned int attempt_count; /* Counter used to limit the number of + * subsequently rejected attach attempts */ +} _emm_attach_data = {0}; +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the attach procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _emm_attach_t3450_handler(void*); + +/* + * Functions that may initiate EMM common procedures + */ +static int _emm_attach_identify(void*); +static int _emm_attach_security(void*); +static int _emm_attach(void*); + +/* + * Abnormal case attach procedures + */ +static int _emm_attach_release(void*); +static int _emm_attach_reject(void*); +static int _emm_attach_abort(void*); + +static int _emm_attach_have_changed(const emm_data_context_t* ctx, + emm_proc_attach_type_t type, int ksi, + GUTI_t* guti, imsi_t* imsi, imei_t* imei, + int eea, int eia); +static int _emm_attach_update(emm_data_context_t* ctx, unsigned int ueid, + emm_proc_attach_type_t type, int ksi, + GUTI_t* guti, imsi_t* imsi, imei_t* imei, + int eea, int eia, const OctetString* esm_msg); + +/* + * Internal data used for attach procedure + */ +typedef struct { + unsigned int ueid; /* UE identifier */ +#define ATTACH_COUNTER_MAX 5 + unsigned int retransmission_count; /* Retransmission counter */ + OctetString esm_msg; /* ESM message to be sent within + * the Attach Accept message */ +} attach_data_t; + +static int _emm_attach_accept(emm_data_context_t* emm_ctx, attach_data_t* data); + +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Attach procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_attach() ** + ** ** + ** Description: Initiate EPS attach procedure to register a UE in PS mode ** + ** of operation for EPS services only, or register a UE for ** + ** emergency bearer services. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.2 ** + ** In state EMM-DEREGISTERED, the UE initiates the attach ** + ** procedure by sending an ATTACH REQUEST message to the MME,** + ** starting timer T3410 and entering state EMM-REGISTERED- ** + ** INITIATED. ** + ** ** + ** Inputs: type: Type of the requested attach ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3402, T3410, T3411 ** + ** ** + ***************************************************************************/ +int emm_proc_attach(emm_proc_attach_type_t type) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + emm_as_establish_t *emm_as = &emm_sap.u.emm_as.u.establish; + esm_sap_t esm_sap; + int rc; + + LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach type = %s (%d)", + _emm_attach_type_str[type], type); + + /* Update the emergency bearer service indicator */ + if (type == EMM_ATTACH_TYPE_EMERGENCY) { + _emm_data.is_emergency = TRUE; + } + + /* Setup initial NAS information message to transfer */ + emm_as->NASinfo = EMM_AS_NAS_INFO_ATTACH; + /* Set the attach type */ + emm_as->type = type; + /* Set the RRC connection establishment cause */ + if (_emm_data.is_emergency) { + emm_as->RRCcause = NET_ESTABLISH_CAUSE_EMERGENCY; + emm_as->RRCtype = NET_ESTABLISH_TYPE_EMERGENCY_CALLS; + } else { + emm_as->RRCcause = NET_ESTABLISH_CAUSE_MO_SIGNAL; + emm_as->RRCtype = NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL; + } + /* Set the PLMN identifier of the selected PLMN */ + emm_as->plmnID = &_emm_data.splmn; + /* + * Process the EPS mobile identity + */ + emm_as->UEid.guti = NULL; + emm_as->UEid.tai = NULL; + emm_as->UEid.imsi = NULL; + emm_as->UEid.imei = NULL; + /* Check whether the UE is configured for "AttachWithIMSI" */ + if (_emm_data.AttachWithImsi) { + /* Check whether the selected PLMN is neither the registered PLMN + * nor in the list of equivalent PLMNs */ + if ( (!_emm_data.is_rplmn) && (!_emm_data.is_eplmn) ) { + /* Include the IMSI */ + emm_as->UEid.imsi = _emm_data.imsi; + } + } + else if (_emm_data.guti) { + /* Include a valid GUTI and the last visited registered TAI */ + emm_as->UEid.guti = _emm_data.guti; + emm_as->UEid.tai = _emm_data.tai; + } + else if (!_emm_data.is_emergency) { + /* Include the IMSI if no valid GUTI is available */ + emm_as->UEid.imsi = _emm_data.imsi; + } + else { + /* The UE is attaching for emergency bearer services and + * does not hold a valid GUTI */ + if (_emm_data.imsi) { + /* Include the IMSI if valid (USIM is present) */ + emm_as->UEid.imsi = _emm_data.imsi; + } else { + /* Include the IMEI if the IMSI is not valid */ + emm_as->UEid.imei = _emm_data.imei; + } + } + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_as->sctx, _emm_data.security, FALSE, FALSE); + emm_as->ksi = EMM_AS_NO_KEY_AVAILABLE; + if (_emm_data.security) { + if (_emm_data.security->type != EMM_KSI_NOT_AVAILABLE) { + emm_as->ksi = _emm_data.security->eksi; + } + emm_as->encryption = _emm_data.security->capability.encryption; + emm_as->integrity = _emm_data.security->capability.integrity; + } + /* + * Notify ESM that initiation of a PDN connectivity procedure + * is requested to setup a default EPS bearer + */ + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; + esm_sap.is_standalone = FALSE; + esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.data.pdn_connect.cid = 1; + /* TODO: PDN type should be set according to the IP capability of the UE */ + esm_sap.data.pdn_connect.pdn_type = NET_PDN_TYPE_IPV4V6; + esm_sap.data.pdn_connect.apn = NULL; + esm_sap.data.pdn_connect.is_emergency = _emm_data.is_emergency; + rc = esm_sap_send(&esm_sap); + + if (rc != RETURNerror) { + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(emm_proc_attach_request, + emm_proc_attach_failure, + emm_proc_attach_release, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Start T3410 timer */ + T3410.id = nas_timer_start(T3410.sec, _emm_attach_t3410_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3410 (%d) expires in %ld seconds", + T3410.id, T3410.sec); + /* Stop T3402 and T3411 timers if running */ + T3402.id = nas_timer_stop(T3402.id); + T3411.id = nas_timer_stop(T3411.id); + + /* + * Notify EMM-AS SAP that a RRC connection establishment procedure + * is requested from the Access-Stratum to send initial NAS message + * attach request to the network + */ + emm_sap.primitive = EMMAS_ESTABLISH_REQ; + /* Get the PDN connectivity request to transfer within the ESM + * container of the initial attach request message */ + emm_sap.u.emm_as.u.establish.NASmsg = esm_sap.send; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_request() ** + ** ** + ** Description: Performs the attach procedure upon receipt of indication ** + ** from lower layers that Attach Request message has been ** + ** successfully delivered to the network. ** + ** ** + ** Inputs: args: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_attach_request(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify EMM that Attach Request has been sent to the network + */ + emm_sap.primitive = EMMREG_ATTACH_REQ; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_accept() ** + ** ** + ** Description: Performs the attach procedure accepted by the network. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.4 ** + ** Upon receiving the ATTACH ACCEPT message, the UE shall ** + ** stop timer T3410 and send an ATTACH COMPLETE message to ** + ** the MME. ** + ** ** + ** Inputs: t3412: Value of the T3412 timer in seconds ** + ** t3402: Value of the T3402 timer in seconds ** + ** t3423: Value of the T3423 timer in seconds ** + ** n_tais: Number of tracking area identities contai- ** + ** ned in the TAI list ** + ** tai: The TAI list that identifies the tracking ** + ** areas the UE is registered to ** + ** guti: New UE's temporary identity assigned by ** + ** the MME (GUTI reallocation) ** + ** n_eplmns: Number of equivalent PLMNs ** + ** eplmns: List of equivalent PLMNs ** + ** esm_msg: Activate default EPS bearer context re- ** + ** quest ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, T3412, T3402, T3423 ** + ** ** + ***************************************************************************/ +int emm_proc_attach_accept(long t3412, long t3402, long t3423, + int n_tais, tai_t* tai, GUTI_t* guti, + int n_eplmns, plmn_t* eplmn, + const OctetString* esm_msg) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + esm_sap_t esm_sap; + int rc; + + LOG_TRACE(INFO, "EMM-PROC - EPS attach accepted by the network"); + + /* Stop timer T3410 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + + /* Delete old TAI list and store the received TAI list */ + _emm_data.ltai.n_tais = n_tais; + for (int i = 0; (i < n_tais) && (i < EMM_DATA_TAI_MAX); i++) { + _emm_data.ltai.tai[i] = tai[i]; + } + + /* Update periodic tracking area update timer value */ + T3412.sec = t3412; + /* Update attach failure timer value */ + if ( !(t3402 < 0) ) { + T3402.sec = t3402; + } + /* Update E-UTRAN deactivate ISR timer value */ + if ( !(t3423 < 0) ) { + T3423.sec = t3423; + } + + /* Delete old GUTI and store the new assigned GUTI if provided */ + if (guti) { + *_emm_data.guti = *guti; + } + + /* Update the stored list of equivalent PLMNs */ + _emm_data.nvdata.eplmn.n_plmns = 0; + if (n_eplmns > 0) { + for (int i = 0; (i < n_eplmns) && (i < EMM_DATA_EPLMN_MAX); i++) { + int is_forbidden = FALSE; + if (!_emm_data.is_emergency) { + /* If the attach procedure is not for emergency bearer + * services, the UE shall remove from the list any PLMN + * code that is already in the list of forbidden PLMNs */ + for (int j = 0; j < _emm_data.fplmn.n_plmns; j++) { + if (PLMNS_ARE_EQUAL(eplmn[i], _emm_data.fplmn.plmn[j])) { + is_forbidden = TRUE; + break; + } + } + } + if ( !is_forbidden ) { + _emm_data.nvdata.eplmn.plmn[_emm_data.nvdata.eplmn.n_plmns++] = + eplmn[i]; + } + } + /* Add the PLMN code of the registered PLMN that sent the list */ + if (_emm_data.nvdata.eplmn.n_plmns < EMM_DATA_EPLMN_MAX) { + _emm_data.nvdata.eplmn.plmn[_emm_data.nvdata.eplmn.n_plmns++] = + _emm_data.splmn; + } + } + + /* + * Notify ESM that a default EPS bearer has to be activated + */ + esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REQ; + esm_sap.is_standalone = FALSE; + esm_sap.recv = esm_msg; + rc = esm_sap_send(&esm_sap); + + if ( (rc != RETURNerror) && (esm_sap.err == ESM_SAP_SUCCESS) ) + { + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(emm_proc_attach_complete, + emm_proc_attach_failure, + NULL, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "EMM-PROC - Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Notify EMM-AS SAP that Attach Complete message together with + * an Activate Default EPS Bearer Context Accept message has to + * be sent to the network + */ + emm_sap.primitive = EMMAS_DATA_REQ; + emm_sap.u.emm_as.u.data.guti = _emm_data.guti; + emm_sap.u.emm_as.u.data.ueid = 0; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, + _emm_data.security, FALSE, TRUE); + /* Get the activate default EPS bearer context accept message + * to be transfered within the ESM container of the attach + * complete message */ + emm_sap.u.emm_as.u.data.NASinfo = EMM_AS_NAS_DATA_ATTACH; + emm_sap.u.emm_as.u.data.NASmsg = esm_sap.send; + rc = emm_sap_send(&emm_sap); + } + else if (esm_sap.err != ESM_SAP_DISCARDED) { + /* 3GPP TS 24.301, section 5.5.1.2.6, case j + * If the ACTIVATE DEFAULT BEARER CONTEXT REQUEST message combined + * with the ATTACH ACCEPT is not accepted by the UE due to failure + * in the UE ESM sublayer, then the UE shall initiate the detach + * procedure by sending a DETACH REQUEST message to the network. + */ + emm_sap.primitive = EMMREG_DETACH_INIT; + rc = emm_sap_send(&emm_sap); + } + else { + /* + * ESM procedure failed and, received message has been discarded or + * Status message has been returned; ignore ESM procedure failure + */ + rc = RETURNok; + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_reject() ** + ** ** + ** Description: Performs the attach procedure rejected by the network. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.5 ** + ** Upon receiving the ATTACH REJECT message, the UE shall ** + ** stop timer T3410 and take actions depending on the EMM ** + ** cause value received. ** + ** ** + ** Inputs: emm_cause: EMM cause indicating why the network re- ** + ** jected the attach request ** + ** esm_msg: PDN connectivity reject ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, _emm_attach_data, T3410 ** + ** ** + ***************************************************************************/ +int emm_proc_attach_reject(int emm_cause, const OctetString* esm_msg) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - EPS attach rejected by the network, " + "EMM cause = %d", emm_cause); + + /* Stop timer T3410 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + + /* Update the EPS update status, the GUTI, the visited registered TAI and + * the eKSI */ + switch (emm_cause) + { + case EMM_CAUSE_ILLEGAL_UE: + case EMM_CAUSE_ILLEGAL_ME: + case EMM_CAUSE_EPS_NOT_ALLOWED: + case EMM_CAUSE_BOTH_NOT_ALLOWED: + case EMM_CAUSE_PLMN_NOT_ALLOWED: + case EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN: + case EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN: + case EMM_CAUSE_TA_NOT_ALLOWED: + case EMM_CAUSE_ROAMING_NOT_ALLOWED: + case EMM_CAUSE_NO_SUITABLE_CELLS: + /* Set the EPS update status to EU3 ROAMING NOT ALLOWED */ + _emm_data.status = EU3_ROAMING_NOT_ALLOWED; + /* Delete the GUTI */ + _emm_data.guti = NULL; + /* Delete the last visited registered TAI */ + _emm_data.tai = NULL; + /* Delete the eKSI */ + if (_emm_data.security) { + _emm_data.security->type = EMM_KSI_NOT_AVAILABLE; + } + break; + + default : + break; + } + + /* Update list of equivalents PLMNs and attach attempt counter */ + switch (emm_cause) + { + case EMM_CAUSE_ILLEGAL_UE: + case EMM_CAUSE_ILLEGAL_ME: + case EMM_CAUSE_EPS_NOT_ALLOWED: + case EMM_CAUSE_BOTH_NOT_ALLOWED: + /* Consider the USIM as invalid for EPS services */ + _emm_data.usim_is_valid = FALSE; + /* Delete the list of equivalent PLMNs */ + _emm_data.nvdata.eplmn.n_plmns = 0; + break; + + case EMM_CAUSE_PLMN_NOT_ALLOWED: + case EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN: + case EMM_CAUSE_ROAMING_NOT_ALLOWED: + /* Delete the list of equivalent PLMNs */ + _emm_data.nvdata.eplmn.n_plmns = 0; + /* Reset the attach attempt counter */ + _emm_attach_data.attempt_count = 0; + break; + + case EMM_CAUSE_TA_NOT_ALLOWED: + case EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN: + case EMM_CAUSE_NO_SUITABLE_CELLS: + /* Reset the attach attempt counter */ + _emm_attach_data.attempt_count = 0; + break; + + case EMM_CAUSE_ESM_FAILURE: + /* 3GPP TS 24.301, section 5.5.1.2.6, case d */ + if (_emm_data.NAS_SignallingPriority != 1) { + /* The UE is not configured for NAS signalling low priority; + * set the attach attempt counter to 5 */ + _emm_attach_data.attempt_count = EMM_ATTACH_COUNTER_MAX; + } + break; + + case EMM_CAUSE_SEMANTICALLY_INCORRECT: + case EMM_CAUSE_INVALID_MANDATORY_INFO: + case EMM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED: + case EMM_CAUSE_IE_NOT_IMPLEMENTED: + case EMM_CAUSE_PROTOCOL_ERROR: + /* 3GPP TS 24.301, section 5.5.1.2.6, case d + * Set the attach attempt counter to 5 */ + _emm_attach_data.attempt_count = EMM_ATTACH_COUNTER_MAX; + break; + + default : + break; + } + + /* Update "forbidden lists" */ + switch (emm_cause) + { + case EMM_CAUSE_PLMN_NOT_ALLOWED: + case EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN: + /* Store the PLMN identity in the "forbidden PLMN list" */ + _emm_data.fplmn.plmn[_emm_data.fplmn.n_plmns++] = _emm_data.splmn; + break; + + case EMM_CAUSE_TA_NOT_ALLOWED: + /* Store the current TAI in the list of "forbidden tracking + * areas for regional provision of service" */ + _emm_data.ftai.tai[_emm_data.ftai.n_tais++] = *_emm_data.tai; + break; + + case EMM_CAUSE_ROAMING_NOT_ALLOWED: + /* Store the current TAI in the list of "forbidden tracking + * areas for roaming" */ + _emm_data.ftai_roaming.tai[_emm_data.ftai_roaming.n_tais++] = *_emm_data.tai; + break; + + case EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN: + /* Store the PLMN identity in the "forbidden PLMNs for GPRS + * service" list */ + _emm_data.fplmn_gprs.plmn[_emm_data.fplmn_gprs.n_plmns++] = _emm_data.splmn; + break; + + default : + break; + } + + /* Update state of EMM sublayer */ + switch (emm_cause) + { + case EMM_CAUSE_ILLEGAL_UE: + case EMM_CAUSE_ILLEGAL_ME: + case EMM_CAUSE_EPS_NOT_ALLOWED: + case EMM_CAUSE_BOTH_NOT_ALLOWED: + /* + * Notify EMM that EPS attach is rejected + */ + emm_sap.primitive = EMMREG_ATTACH_REJ; + break; + + case EMM_CAUSE_PLMN_NOT_ALLOWED: + case EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN: + case EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN: + /* + * Notify EMM that the UE has to perform a PLMN selection because + * it is not allowed to operate in the currently selected PLMN + */ + emm_sap.primitive = EMMREG_REGISTER_REQ; + break; + + case EMM_CAUSE_TA_NOT_ALLOWED: + case EMM_CAUSE_ROAMING_NOT_ALLOWED: + case EMM_CAUSE_NO_SUITABLE_CELLS: + /* + * Notify EMM that the UE failed to register to the network for + * EPS services because it is not allowed to operate in the + * requested tracking area + */ + emm_sap.primitive = EMMREG_REGISTER_REJ; + break; + + case EMM_CAUSE_IMEI_NOT_ACCEPTED: + if (_emm_data.is_emergency) { + /* + * Notify EMM that the UE failed to register to the network + * for emergency bearer services because "IMEI not accepted" + */ + emm_sap.primitive = EMMREG_NO_IMSI; + break; + } + /* break is volontary missing */ + + default : + /* Other values are considered as abnormal cases + * 3GPP TS 24.301, section 5.5.1.2.6, case d */ + _emm_attach_abnormal_cases_bcd(&emm_sap); + break; + } + + rc = emm_sap_send(&emm_sap); + + /* + * Notify ESM that the network rejected connectivity to the PDN + */ + if (esm_msg != NULL) { + esm_sap_t esm_sap; + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; + esm_sap.is_standalone = FALSE; + esm_sap.recv = esm_msg; + rc = esm_sap_send(&esm_sap); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_complete() ** + ** ** + ** Description: Terminates the attach procedure when Attach Complete mes- ** + ** sage has been successfully delivered to the MME. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.4 ** + ** Upon successfully sending the ATTACH COMPLETE message, ** + ** the UE shall reset the attach attempt counter and tra- ** + ** cking area updating attempt counter, enter state EMM- ** + ** REGISTERED and set the EPS update status to EU1-UPDATED. ** + ** ** + ** Inputs: args: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, _emm_attach_data ** + ** ** + ***************************************************************************/ +int emm_proc_attach_complete(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + esm_sap_t esm_sap; + int rc; + + LOG_TRACE(INFO, "EMM-PROC - EPS attach complete"); + + /* Reset EMM procedure handler */ + (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + + /* Reset the attach attempt counter */ + _emm_attach_data.attempt_count = 0; + /* TODO: Reset the tracking area updating attempt counter */ + + /* Set the EPS update status to EU1 UPDATED */ + _emm_data.status = EU1_UPDATED; + _emm_data.is_attached = TRUE; + + /* + * Notify EMM that network attach complete message has been delivered + * to the network + */ + emm_sap.primitive = EMMREG_ATTACH_CNF; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* + * Notify ESM that the Activate Default EPS Bearer Context Accept + * message has been delivered to the network within the Attach + * Complete message + */ + esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF; + esm_sap.is_standalone = FALSE; + rc = esm_sap_send(&esm_sap); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_failure() ** + ** ** + ** Description: Performs the attach procedure abnormal case upon receipt ** + ** of transmission failure of Attach Request message or At- ** + ** tach Complete message. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.6, cases h and i ** + ** The UE shall restart the attach procedure when timer ** + ** T3411 expires. ** + ** ** + ** Inputs: is_initial: TRUE if the NAS message that failed to be ** + ** transfered is an initial NAS message (ESM ** + ** message embedded within an Attach Request ** + ** message) ** + ** args: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3410, T3411 ** + ** ** + ***************************************************************************/ +int emm_proc_attach_failure(int is_initial, void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + esm_sap_t esm_sap; + + LOG_TRACE(WARNING, "EMM-PROC - EPS attach failure"); + + /* Reset EMM procedure handler */ + (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + + /* Stop timer T3410 if still running */ + if (T3410.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + } + + if (is_initial) { + /* + * Notify ESM that the PDN CONNECTIVITY REQUEST message contained + * in the ESM message container IE of the ATTACH REQUEST has failed + * to be transmitted + */ + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; + esm_sap.is_standalone = FALSE; + esm_sap.recv = NULL; + } + else { + /* + * Notify ESM that ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST message + * contained in the ESM message container IE of the ATTACH COMPLETE + * has failed to be transmitted + */ + esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ; + esm_sap.is_standalone = FALSE; + esm_sap.recv = NULL; + } + rc = esm_sap_send(&esm_sap); + + if (rc != RETURNerror) { + /* Start T3411 timer */ + T3411.id = nas_timer_start(T3411.sec, _emm_attach_t3411_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3411 (%d) expires in %ld seconds", + T3411.id, T3411.sec); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_release() ** + ** ** + ** Description: Performs the attach procedure abnormal case upon receipt ** + ** of NAS signalling connection release indication. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.6, case b ** + ** The attach procedure shall be aborted and the UE shall ** + ** execute abnormal case attach procedure. ** + ** ** + ** Inputs: args: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_attach_release(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - NAS signalling connection released"); + + /* Execute abnormal case attach procedure */ + _emm_attach_abnormal_cases_bcd(&emm_sap); + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_restart() ** + ** ** + ** Description: Restarts the attach procedure ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_attach_restart(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(INFO, "EMM-PROC - Restart EPS attach procedure"); + + /* + * Notify EMM that the attach procedure has to be restarted + */ + emm_sap.primitive = EMMREG_ATTACH_INIT; + emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_set_emergency() ** + ** ** + ** Description: Set the emergency bearer services indicator ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_attach_set_emergency(void) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - UE is now attached to the network for " + "emergency bearer services only"); + + _emm_data.is_emergency = TRUE; + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_set_detach() ** + ** ** + ** Description: Reset the network attachment indicator and enter state ** + ** EMM-DEREGISTERED + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_attach_set_detach(void) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, + "EMM-PROC - UE is now locally detached from the network"); + + /* Reset the network attachment indicator */ + _emm_data.is_attached = FALSE; + /* + * Notify that the UE is locally detached from the network + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_DETACH_CNF; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +#endif + +/* + * -------------------------------------------------------------------------- + * Attach procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_request() ** + ** ** + ** Description: Performs the UE requested attach procedure ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.3 ** + ** The network may initiate EMM common procedures, e.g. the ** + ** identification, authentication and security mode control ** + ** procedures during the attach procedure, depending on the ** + ** information received in the ATTACH REQUEST message (e.g. ** + ** IMSI, GUTI and KSI). ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** type: Type of the requested attach ** + ** native_ksi: TRUE if the security context is of type ** + ** native (for KSIASME) ** + ** ksi: The NAS ket sey identifier ** + ** native_guti: TRUE if the provided GUTI is native GUTI ** + ** guti: The GUTI if provided by the UE ** + ** imsi: The IMSI if provided by the UE ** + ** imei: The IMEI if provided by the UE ** + ** tai: Identifies the last visited tracking area ** + ** the UE is registered to ** + ** eea: Supported EPS encryption algorithms ** + ** eia: Supported EPS integrity algorithms ** + ** esm_msg: PDN connectivity request ESM message ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_attach_request(unsigned int ueid, emm_proc_attach_type_t type, + int native_ksi, int ksi, int native_guti, + GUTI_t* guti, imsi_t* imsi, imei_t* imei, + tai_t* tai, int eea, int eia, + const OctetString* esm_msg) +{ + LOG_FUNC_IN; + + int rc; + emm_data_context_t ue_ctx; + + LOG_TRACE(INFO, "EMM-PROC - EPS attach type = %s (%d) requested (ueid=0x%08x)", + _emm_attach_type_str[type], type, ueid); + + /* Initialize the temporary UE context */ + memset(&ue_ctx, 0 , sizeof(emm_data_context_t)); + ue_ctx.is_dynamic = FALSE; + ue_ctx.ueid = ueid; + +#if !defined(EPC_BUILD) + /* UE identifier sanity check */ + if (ueid >= EMM_DATA_NB_UE_MAX) { + ue_ctx.emm_cause = EMM_CAUSE_ILLEGAL_UE; + /* Do not accept UE with invalid identifier */ + rc = _emm_attach_reject(&ue_ctx); + LOG_FUNC_RETURN(rc); + } +#endif + + /* 3GPP TS 24.301, section 5.5.1.1 + * MME not configured to support attach for emergency bearer services + * shall reject any request to attach with an attach type set to "EPS + * emergency attach". + */ + if ( !(_emm_data.conf.features & MME_API_EMERGENCY_ATTACH) && + (type == EMM_ATTACH_TYPE_EMERGENCY) ) + { + ue_ctx.emm_cause = EMM_CAUSE_IMEI_NOT_ACCEPTED; + /* Do not accept the UE to attach for emergency services */ + rc = _emm_attach_reject(&ue_ctx); + LOG_FUNC_RETURN(rc); + } + + /* Get the UE's EMM context if it exists */ + emm_data_context_t** emm_ctx = NULL; + +#if defined(EPC_BUILD) + emm_data_context_t* temp = NULL; + + temp = emm_data_context_get(&_emm_data, ueid); + emm_ctx = &temp; +#else + emm_ctx = &_emm_data.ctx[ueid]; +#endif + + if (*emm_ctx != NULL) { + /* An EMM context already exists for the UE in the network */ + if (_emm_attach_have_changed(*emm_ctx, type, ksi, guti, imsi, imei, + eea, eia)) + { + /* + * 3GPP TS 24.301, section 5.5.1.2.7, abnormal case e + * The attach parameters have changed from the one received within + * the previous Attach Request message; + * the previously initiated attach procedure shall be aborted and + * the new attach procedure shall be executed; + */ + LOG_TRACE(WARNING, "EMM-PROC - Attach parameters have changed"); + /* + * Notify EMM that the attach procedure is aborted + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_PROC_ABORT; + emm_sap.u.emm_reg.ueid = ueid; + emm_sap.u.emm_reg.ctx = *emm_ctx; + + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Process new attach procedure */ + LOG_TRACE(WARNING, "EMM-PROC - Initiate new attach procedure"); + rc = emm_proc_attach_request(ueid, type, native_ksi, ksi, + native_guti, guti, imsi, imei, + tai, eea, eia, esm_msg); + } + LOG_FUNC_RETURN(rc); + } + else { + /* Continue with the previous attach procedure */ + LOG_TRACE(WARNING, "EMM-PROC - Received duplicated Attach Request"); + LOG_FUNC_RETURN(RETURNok); + } + } + else { + /* Create UE's EMM context */ + *emm_ctx = (emm_data_context_t*)malloc(sizeof(emm_data_context_t)); + if (emm_ctx == NULL) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to create EMM context"); + ue_ctx.emm_cause = EMM_CAUSE_ILLEGAL_UE; + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(&ue_ctx); + LOG_FUNC_RETURN(rc); + } + (*emm_ctx)->is_dynamic = TRUE; + (*emm_ctx)->guti = NULL; + (*emm_ctx)->old_guti = NULL; + (*emm_ctx)->imsi = NULL; + (*emm_ctx)->imei = NULL; + (*emm_ctx)->security = NULL; + (*emm_ctx)->esm_msg.length = 0; + (*emm_ctx)->esm_msg.value = NULL; + (*emm_ctx)->emm_cause = EMM_CAUSE_SUCCESS; + + (*emm_ctx)->_emm_fsm_status = EMM_DEREGISTERED; + +#if defined(EPC_BUILD) + emm_data_context_add(&_emm_data, *(emm_ctx)); +#endif + } + + /* Update the EMM context with the current attach procedure parameters */ + rc = _emm_attach_update(*emm_ctx, ueid, type, ksi, guti, imsi, imei, + eea, eia, esm_msg); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to update EMM context"); + /* Do not accept the UE to attach to the network */ + (*emm_ctx)->ueid = ueid; + (*emm_ctx)->emm_cause = EMM_CAUSE_ILLEGAL_UE; + rc = _emm_attach_reject(*emm_ctx); + } + else { + /* + * Performs UE identification + */ + rc = _emm_attach_identify(*emm_ctx); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_reject() ** + ** ** + ** Description: Performs the protocol error abnormal case ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.7, case b ** + ** If the ATTACH REQUEST message is received with a protocol ** + ** error, the network shall return an ATTACH REJECT message. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** emm_cause: EMM cause code to be reported ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_attach_reject(unsigned int ueid, int emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + /* Create temporary UE context */ + emm_data_context_t ue_ctx; + memset(&ue_ctx, 0 , sizeof(emm_data_context_t)); + ue_ctx.is_dynamic = FALSE; + ue_ctx.ueid = ueid; + + /* Update the EMM cause code */ +#if defined(EPC_BUILD) + if (ueid == 0) +#else + if (ueid < EMM_DATA_NB_UE_MAX) +#endif + { + ue_ctx.emm_cause = emm_cause; + } else { + ue_ctx.emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + + /* Do not accept attach request with protocol error */ + rc = _emm_attach_reject(&ue_ctx); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_attach_complete() ** + ** ** + ** Description: Terminates the attach procedure upon receiving Attach ** + ** Complete message from the UE. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.4 ** + ** Upon receiving an ATTACH COMPLETE message, the MME shall ** + ** stop timer T3450, enter state EMM-REGISTERED and consider ** + ** the GUTI sent in the ATTACH ACCEPT message as valid. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** esm_msg: Activate default EPS bearer context accept ** + ** ESM message ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, T3450 ** + ** ** + ***************************************************************************/ +int emm_proc_attach_complete(unsigned int ueid, const OctetString* esm_msg) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + emm_sap_t emm_sap; + esm_sap_t esm_sap; + + LOG_TRACE(INFO, "EMM-PROC - EPS attach complete (ueid=%u)", ueid); + + /* Stop timer T3450 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3450 (%d)", T3450.id); + T3450.id = nas_timer_stop(T3450.id); + + /* Release retransmission timer parameters */ + attach_data_t* data = (attach_data_t*)(emm_proc_common_get_args(ueid)); + if (data) { + if (data->esm_msg.length > 0) { + free(data->esm_msg.value); + } + free(data); + } + + /* Get the UE context */ + emm_data_context_t* emm_ctx = NULL; + +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_ctx) { + /* Delete the old GUTI and consider the GUTI sent in the Attach + * Accept message as valid */ + emm_ctx->guti_is_new = FALSE; + emm_ctx->old_guti = NULL; + /* + * Forward the Activate Default EPS Bearer Context Accept message + * to the EPS session management sublayer + */ + esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF; + esm_sap.is_standalone = FALSE; + esm_sap.ueid = ueid; + esm_sap.recv = esm_msg; + rc = esm_sap_send(&esm_sap); + } + else { + LOG_TRACE(ERROR, "EMM-PROC - No EMM context exists"); + } + + if ( (rc != RETURNerror) && (esm_sap.err == ESM_SAP_SUCCESS) ) { + /* Set the network attachment indicator */ + emm_ctx->is_attached = TRUE; + /* + * Notify EMM that attach procedure has successfully completed + */ + emm_sap.primitive = EMMREG_ATTACH_CNF; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + else if (esm_sap.err != ESM_SAP_DISCARDED) { + /* + * Notify EMM that attach procedure failed + */ + emm_sap.primitive = EMMREG_ATTACH_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + else { + /* + * ESM procedure failed and, received message has been discarded or + * Status message has been returned; ignore ESM procedure failure + */ + rc = RETURNok; + } + + LOG_FUNC_RETURN(rc); +} + +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach_t3410_handler() ** + ** ** + ** Description: T3410 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.6, case c ** + ** Upon T3410 timer expiration, the attach procedure shall ** + ** be aborted and the UE shall execute abnormal case attach ** + ** procedure. ** + ** The NAS signalling connection shall be released locally. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: T3410 ** + ** ** + ***************************************************************************/ +void* _emm_attach_t3410_handler(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - T3410 timer expired"); + + /* Stop T3410 timer */ + T3410.id = nas_timer_stop(T3410.id); + /* Execute abnormal case attach procedure */ + _emm_attach_abnormal_cases_bcd(&emm_sap); + + rc = emm_sap_send(&emm_sap); + if (rc != RETURNerror) { + /* Locally release the NAS signalling connection */ + _emm_data.ecm_status = ECM_IDLE; + } + + LOG_FUNC_RETURN(NULL); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_t3411_handler() ** + ** ** + ** Description: T3411 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.6 ** + ** Upon T3411 timer expiration, the attach procedure shall ** + ** be restarted, if still required by ESM sublayer. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: T3411 ** + ** ** + ***************************************************************************/ +static void* _emm_attach_t3411_handler(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + + LOG_TRACE(WARNING, "EMM-PROC - T3411 timer expired"); + + /* Stop T3411 timer */ + T3411.id = nas_timer_stop(T3411.id); + /* + * Notify EMM that timer T3411 expired and attach procedure has to be + * restarted + */ + emm_sap.primitive = EMMREG_ATTACH_INIT; + emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency; + + (void) emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(NULL); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_t3402_handler() ** + ** ** + ** Description: T3402 timeout handler ** + ** ** + ** Upon T3402 timer expiration: ** + ** 3GPP TS 24.301, section 5.5.1.1 ** + ** the attach attempt counter shall be reset when the UE is ** + ** in substate DEREGISTERED.ATTEMPTING-TO-ATTACH; ** + ** 3GPP TS 24.301, section 5.2.2.3.3 ** + ** the UE shall initiate an attach or combined attach proce- ** + ** dure in substate DEREGISTERED.ATTEMPTING-TO-ATTACH; ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_attach_data, T3402 ** + ** ** + ***************************************************************************/ +static void* _emm_attach_t3402_handler(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + + LOG_TRACE(WARNING, "EMM-PROC - T3402 timer expired"); + + /* Stop T3402 timer */ + T3402.id = nas_timer_stop(T3402.id); + /* Reset the attach attempt counter */ + _emm_attach_data.attempt_count = 0; + /* + * Notify EMM that timer T3402 expired and attach procedure has to be + * restarted + */ + emm_sap.primitive = EMMREG_ATTACH_INIT; + emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency; + + (void) emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(NULL); +} + +/* + * -------------------------------------------------------------------------- + * Abnormal cases in the UE + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach_abnormal_cases_bcd() ** + ** ** + ** Description: Performs the abnormal case attach procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.6, cases b, c and d ** + ** The Timer T3410 shall be stopped if still running, the ** + ** attach attempt counter shall be incremented and the UE ** + ** shall proceed depending on whether the attach attempt ** + ** counter reached its maximum value or not. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: emm_sap: EMM service access point ** + ** Return: None ** + ** Others: _emm_data, _emm_attach_data, T3402, T3410, ** + ** T3411 ** + ** ** + ***************************************************************************/ +static void _emm_attach_abnormal_cases_bcd(emm_sap_t* emm_sap) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - Abnormal case, attach counter = %d", + _emm_attach_data.attempt_count); + + /* Stop timer T3410 */ + if (T3410.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + } + + if (_emm_attach_data.attempt_count < EMM_ATTACH_COUNTER_MAX) { + /* Increment the attach attempt counter */ + _emm_attach_data.attempt_count += 1; + /* Start T3411 timer */ + T3411.id = nas_timer_start(T3411.sec, _emm_attach_t3411_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3411 (%d) expires in %ld seconds", + T3411.id, T3411.sec); + /* + * Notify EMM that the attempt to attach for EPS services failed and + * the attach attempt counter didn't reach its maximum value; network + * attach procedure shall be restarted when timer T3411 expires. + */ + emm_sap->primitive = EMMREG_ATTACH_FAILED; + } + else { + /* Delete the GUTI */ + _emm_data.guti = NULL; + /* Delete the TAI list */ + _emm_data.ltai.n_tais = 0; + /* Delete the last visited registered TAI */ + _emm_data.tai = NULL; + /* Delete the list of equivalent PLMNs */ + _emm_data.nvdata.eplmn.n_plmns = 0; + /* Delete the eKSI */ + if (_emm_data.security) { + _emm_data.security->type = EMM_KSI_NOT_AVAILABLE; + } + /* Set the EPS update status to EU2 NOT UPDATED */ + _emm_data.status = EU2_NOT_UPDATED; + + /* Start T3402 timer */ + T3402.id = nas_timer_start(T3402.sec, _emm_attach_t3402_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3402 (%d) expires in %ld seconds", + T3402.id, T3402.sec); + /* + * Notify EMM that the attempt to attach for EPS services failed and + * the attach attempt counter reached its maximum value. + */ + emm_sap->primitive = EMMREG_ATTACH_EXCEEDED; + } + + LOG_FUNC_OUT; +} +#endif // NAS_UE + +#ifdef NAS_MME +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach_t3450_handler() ** + ** ** + ** Description: T3450 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.7, case c ** + ** On the first expiry of the timer T3450, the network shall ** + ** retransmit the ATTACH ACCEPT message and shall reset and ** + ** restart timer T3450. This retransmission is repeated four ** + ** times, i.e. on the fifth expiry of timer T3450, the at- ** + ** tach procedure shall be aborted and the MME enters state ** + ** EMM-DEREGISTERED. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _emm_attach_t3450_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + attach_data_t* data = (attach_data_t*)(args); + + /* Increment the retransmission counter */ + data->retransmission_count += 1; + + LOG_TRACE(WARNING, "EMM-PROC - T3450 timer expired, retransmission " + "counter = %d", data->retransmission_count); + + /* Get the UE's EMM context */ + emm_data_context_t* emm_ctx = NULL; + +#if defined(EPC_BUILD) + emm_ctx = emm_data_context_get(&_emm_data, data->ueid); +#else + emm_ctx = _emm_data.ctx[data->ueid]; +#endif + + if (data->retransmission_count < ATTACH_COUNTER_MAX) { + /* Send attach accept message to the UE */ + rc = _emm_attach_accept(emm_ctx, data); + } + else { + /* Abort the attach procedure */ + rc = _emm_attach_abort(data); + } + + LOG_FUNC_RETURN(NULL); +} + +/* + * -------------------------------------------------------------------------- + * Abnormal cases in the MME + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach_release() ** + ** ** + ** Description: Releases the UE context data. ** + ** ** + ** Inputs: args: Data to be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_attach_release(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + emm_data_context_t* emm_ctx = (emm_data_context_t*)(args); + + if (emm_ctx) + { + LOG_TRACE(WARNING, "EMM-PROC - Release UE context data (ueid=%u)", + emm_ctx->ueid); + + unsigned int ueid = emm_ctx->ueid; + + if (emm_ctx->guti) free(emm_ctx->guti); + if (emm_ctx->imsi) free(emm_ctx->imsi); + if (emm_ctx->imei) free(emm_ctx->imei); + if (emm_ctx->esm_msg.length > 0) free(emm_ctx->esm_msg.value); + /* Release NAS security context */ + if (emm_ctx->security) { + emm_security_context_t* security = emm_ctx->security; + if (security->kasme.value) free(security->kasme.value); + if (security->knas_enc.value) free(security->knas_enc.value); + if (security->knas_int.value) free(security->knas_int.value); + free(emm_ctx->security); + } + /* Release the EMM context */ +#if defined(EPC_BUILD) + emm_data_context_remove(&_emm_data, emm_ctx); +#else + free(_emm_data.ctx[ueid]); + _emm_data.ctx[ueid] = NULL; +#endif + /* + * Notify EMM that the attach procedure is aborted + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_PROC_ABORT; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_reject() ** + ** ** + ** Description: Performs the attach procedure not accepted by the network.** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.5 ** + ** If the attach request cannot be accepted by the network, ** + ** the MME shall send an ATTACH REJECT message to the UE in- ** + ** including an appropriate EMM cause value. ** + ** ** + ** Inputs: args: UE context data ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_attach_reject(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + emm_data_context_t* emm_ctx = (emm_data_context_t*)(args); + + if (emm_ctx) + { + emm_sap_t emm_sap; + LOG_TRACE(WARNING, "EMM-PROC - EMM attach procedure not accepted " + "by the network (ueid=%08x, cause=%d)", + emm_ctx->ueid, emm_ctx->emm_cause); + /* + * Notify EMM-AS SAP that Attach Reject message has to be sent + * onto the network + */ + emm_sap.primitive = EMMAS_ESTABLISH_REJ; + emm_sap.u.emm_as.u.establish.ueid = emm_ctx->ueid; + emm_sap.u.emm_as.u.establish.UEid.guti = NULL; + if (emm_ctx->emm_cause == EMM_CAUSE_SUCCESS) { + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + emm_sap.u.emm_as.u.establish.emm_cause = emm_ctx->emm_cause; + emm_sap.u.emm_as.u.establish.NASinfo = EMM_AS_NAS_INFO_ATTACH; + if (emm_ctx->emm_cause != EMM_CAUSE_ESM_FAILURE) { + emm_sap.u.emm_as.u.establish.NASmsg.length = 0; + emm_sap.u.emm_as.u.establish.NASmsg.value = NULL; + } else if (emm_ctx->esm_msg.length > 0) { + emm_sap.u.emm_as.u.establish.NASmsg = emm_ctx->esm_msg; + } else { + LOG_TRACE(ERROR, "EMM-PROC - ESM message is missing"); + LOG_FUNC_RETURN(RETURNerror); + } + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.establish.sctx, + emm_ctx->security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + /* Release the UE context, even if the network failed to send the + * ATTACH REJECT message */ + if (emm_ctx->is_dynamic) { + rc = _emm_attach_release(emm_ctx); + } + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_abort() ** + ** ** + ** Description: Aborts the attach procedure ** + ** ** + ** Inputs: args: Attach procedure data to be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3450 ** + ** ** + ***************************************************************************/ +static int _emm_attach_abort(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + attach_data_t* data = (attach_data_t*)(args); + + if (data) + { + unsigned int ueid = data->ueid; + + LOG_TRACE(WARNING, "EMM-PROC - Abort the attach procedure (ueid=%u)", + ueid); + + /* Stop timer T3450 */ + if (T3450.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3450 (%d)", T3450.id); + T3450.id = nas_timer_stop(T3450.id); + } + /* Release retransmission timer parameters */ + if (data->esm_msg.length > 0) { + free(data->esm_msg.value); + } + free(data); + + /* + * Notify ESM that the network locally refused PDN connectivity + * to the UE + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; + esm_sap.ueid = ueid; + esm_sap.recv = NULL; + rc = esm_sap_send(&esm_sap); + if (rc != RETURNerror) { + /* + * Notify EMM that EPS attach procedure failed + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_ATTACH_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + if (rc != RETURNerror) { + struct emm_data_context_s *ctx = NULL; + +#if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +#else + ctx = _emm_data.ctx[ueid]; +#endif + + /* Release the UE context */ + rc = _emm_attach_release(ctx); + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * Functions that may initiate EMM common procedures + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach_identify() ** + ** ** + ** Description: Performs UE's identification. May initiates identifica- ** + ** tion, authentication and security mode control EMM common ** + ** procedures. ** + ** ** + ** Inputs: args: Identification argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +static int _emm_attach_identify(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + emm_data_context_t* emm_ctx = (emm_data_context_t*)(args); + int guti_reallocation = FALSE; + + LOG_TRACE(INFO, "EMM-PROC - Identify incoming UE (ueid=0x%08x) using %s", + emm_ctx->ueid, (emm_ctx->imsi)? "IMSI" : (emm_ctx->guti)? "GUTI" : + (emm_ctx->imei)? "IMEI" : "none"); + + /* + * UE's identification + * ------------------- + */ + if (emm_ctx->imsi) { + /* The UE identifies itself using an IMSI */ + rc = mme_api_identify_imsi(emm_ctx->imsi, &emm_ctx->vector); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to identify the UE using provided IMSI"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + guti_reallocation = TRUE; + } + else if (emm_ctx->guti) { + /* The UE identifies itself using a GUTI */ + rc = mme_api_identify_guti(emm_ctx->guti, &emm_ctx->vector); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to identify the UE using " + "provided GUTI (tmsi=%u)", emm_ctx->guti->m_tmsi); + /* 3GPP TS 24.401, Figure 5.3.2.1-1, point 4 + * The UE was attempting to attach to the network using a GUTI + * that is not known by the network; the MME shall initiate an + * identification procedure to retrieve the IMSI from the UE. + */ + rc = emm_proc_identification(emm_ctx->ueid, + emm_ctx, + EMM_IDENT_TYPE_IMSI, + _emm_attach_identify, + _emm_attach_release, + _emm_attach_release); + if (rc != RETURNok) { + /* Failed to initiate the identification procedure */ + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to initiate identification procedure"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(emm_ctx); + } + /* Relevant callback will be executed when identification + * procedure completes */ + LOG_FUNC_RETURN(rc); + } + } + else if ( (emm_ctx->imei) && (emm_ctx->is_emergency) ) { + /* The UE is attempting to attach to the network for emergency + * services using an IMEI */ + rc = mme_api_identify_imei(emm_ctx->imei, &emm_ctx->vector); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to identify the UE using provided IMEI"); + emm_ctx->emm_cause = EMM_CAUSE_IMEI_NOT_ACCEPTED; + } + } + else { + LOG_TRACE(WARNING, "EMM-PROC - UE's identity is not available"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + + /* + * GUTI reallocation + * ----------------- + */ + if ( (rc != RETURNerror) && guti_reallocation ) { + /* Release the old GUTI */ + if (emm_ctx->old_guti) { + free(emm_ctx->old_guti); + } + /* Save the GUTI previously used by the UE to identify itself */ + emm_ctx->old_guti = emm_ctx->guti; + /* Allocate a new GUTI */ + emm_ctx->guti = (GUTI_t*)malloc(sizeof(GUTI_t)); + /* Request the MME to assign a GUTI to the UE */ + rc = mme_api_new_guti(emm_ctx->imsi, emm_ctx->guti, + &emm_ctx->tac, &emm_ctx->n_tacs); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to assign new GUTI"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + else { + LOG_TRACE(WARNING, "EMM-PROC - New GUTI assigned to the UE " + "(tmsi=%u)", emm_ctx->guti->m_tmsi); + /* Update the GUTI indicator as new */ + emm_ctx->guti_is_new = TRUE; + } + } + + /* + * UE's authentication + * ------------------- + */ + if (rc != RETURNerror) { + if (emm_ctx->security) { + /* A security context exists for the UE in the network; + * proceed with the attach procedure. + */ + rc = _emm_attach(emm_ctx); + } + else if ( (emm_ctx->is_emergency) && + (_emm_data.conf.features & MME_API_UNAUTHENTICATED_IMSI) ) { + /* 3GPP TS 24.301, section 5.5.1.2.3 + * 3GPP TS 24.401, Figure 5.3.2.1-1, point 5a + * MME configured to support Emergency Attach for unauthenticated + * IMSIs may choose to skip the authentication procedure even if + * no EPS security context is available and proceed directly to the + * execution of the security mode control procedure. + */ + rc = _emm_attach_security(emm_ctx); + } + else { + /* 3GPP TS 24.401, Figure 5.3.2.1-1, point 5a + * No EMM context exists for the UE in the network; authentication + * and NAS security setup to activate integrity protection and NAS + * ciphering are mandatory. + */ + auth_vector_t* auth = &emm_ctx->vector; + const OctetString loc_rand = {AUTH_RAND_SIZE, (uint8_t*)auth->rand}; + const OctetString autn = {AUTH_AUTN_SIZE, (uint8_t*)auth->autn}; + rc = emm_proc_authentication(emm_ctx->ueid, 0, // TODO: eksi != 0 + &loc_rand, &autn, + _emm_attach_security, + _emm_attach_release, + _emm_attach_release); + if (rc != RETURNok) { + /* Failed to initiate the authentication procedure */ + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to initiate authentication procedure"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + } + } + + if (rc != RETURNok) { + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(emm_ctx); + } + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_security() ** + ** ** + ** Description: Initiates security mode control EMM common procedure. ** + ** ** + ** Inputs: args: security argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +static int _emm_attach_security(void* args) +{ + LOG_FUNC_IN; + + int rc; + emm_data_context_t* emm_ctx = (emm_data_context_t*)(args); + + LOG_TRACE(INFO, "EMM-PROC - Setup NAS security (ueid=%u)", emm_ctx->ueid); + + /* Create new NAS security context */ + if (emm_ctx->security == NULL) { + emm_ctx->security = + (emm_security_context_t*)malloc(sizeof(emm_security_context_t)); + } + if (emm_ctx->security) { + memset(emm_ctx->security, 0, sizeof(emm_security_context_t)); + emm_ctx->security->type = EMM_KSI_NOT_AVAILABLE; + } + else { + LOG_TRACE(WARNING, "EMM-PROC - Failed to create security context"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(emm_ctx); + LOG_FUNC_RETURN(rc); + } + + /* Initialize the security mode control procedure */ + rc = emm_proc_security_mode_control(emm_ctx->ueid, 0, // TODO: eksi != 0 + emm_ctx->eea, emm_ctx->eia, + _emm_attach, _emm_attach_release, + _emm_attach_release); + if (rc != RETURNok) { + /* Failed to initiate the security mode control procedure */ + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to initiate security mode control procedure"); + emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(emm_ctx); + } + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_attach() ** + ** ** + ** Description: Performs the attach signalling procedure while a context ** + ** exists for the incoming UE in the network. ** + ** ** + ** 3GPP TS 24.301, section 5.5.1.2.4 ** + ** Upon receiving the ATTACH REQUEST message, the MME shall ** + ** send an ATTACH ACCEPT message to the UE and start timer ** + ** T3450. ** + ** ** + ** Inputs: args: attach argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +static int _emm_attach(void* args) +{ + LOG_FUNC_IN; + + esm_sap_t esm_sap; + int rc; + + emm_data_context_t* emm_ctx = (emm_data_context_t*)(args); + + LOG_TRACE(INFO, "EMM-PROC - Attach UE (ueid=%u)", emm_ctx->ueid); + + /* 3GPP TS 24.401, Figure 5.3.2.1-1, point 5a + * At this point, all NAS messages shall be protected by the NAS security + * functions (integrity and ciphering) indicated by the MME unless the UE + * is emergency attached and not successfully authenticated. + */ + + /* + * Notify ESM that PDN connectivity is requested + */ + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; + esm_sap.is_standalone = FALSE; + esm_sap.ueid = emm_ctx->ueid; + esm_sap.recv = &emm_ctx->esm_msg; + rc = esm_sap_send(&esm_sap); + + if ( (rc != RETURNerror) && (esm_sap.err == ESM_SAP_SUCCESS) ) { + /* + * The attach request is accepted by the network + */ + + /* Delete the stored UE radio capability information, if any */ + /* Store the UE network capability */ + /* Assign the TAI list the UE is registered to */ + + /* Allocate parameters of the retransmission timer callback */ + attach_data_t* data = (attach_data_t*)malloc(sizeof(attach_data_t)); + + if (data != NULL) { + /* Setup ongoing EMM procedure callback functions */ + rc = emm_proc_common_initialize(emm_ctx->ueid, NULL, NULL, NULL, + _emm_attach_abort, data); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "Failed to initialize EMM callback functions"); + free(data); + LOG_FUNC_RETURN (RETURNerror); + } + /* Set the UE identifier */ + data->ueid = emm_ctx->ueid; + /* Reset the retransmission counter */ + data->retransmission_count = 0; + /* Setup the ESM message container */ + data->esm_msg.value = (uint8_t*)malloc(esm_sap.send.length); + if (data->esm_msg.value) { + data->esm_msg.length = esm_sap.send.length; + memcpy(data->esm_msg.value, esm_sap.send.value, + esm_sap.send.length); + } else { + data->esm_msg.length = 0; + } + /* Send attach accept message to the UE */ + rc = _emm_attach_accept(emm_ctx, data); + if (rc != RETURNerror) { + if (emm_ctx->guti_is_new && emm_ctx->old_guti) { + /* Implicit GUTI reallocation; + * Notify EMM that common procedure has been initiated + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REQ; + emm_sap.u.emm_reg.ueid = data->ueid; + rc = emm_sap_send(&emm_sap); + } + } + } + } + else if (esm_sap.err != ESM_SAP_DISCARDED) { + /* + * The attach procedure failed due to an ESM procedure failure + */ + emm_ctx->emm_cause = EMM_CAUSE_ESM_FAILURE; + /* Setup the ESM message container to include PDN Connectivity Reject + * message within the Attach Reject message */ + if (emm_ctx->esm_msg.length > 0) { + free(emm_ctx->esm_msg.value); + } + emm_ctx->esm_msg.value = (uint8_t*)malloc(esm_sap.send.length); + if (emm_ctx->esm_msg.value) { + emm_ctx->esm_msg.length = esm_sap.send.length; + memcpy(emm_ctx->esm_msg.value, esm_sap.send.value, + esm_sap.send.length); + /* Send Attach Reject message */ + rc = _emm_attach_reject(emm_ctx); + } else { + emm_ctx->esm_msg.length = 0; + } + } + else { + /* + * ESM procedure failed and, received message has been discarded or + * Status message has been returned; ignore ESM procedure failure + */ + rc = RETURNok; + } + + if (rc != RETURNok) { + /* The attach procedure failed */ + LOG_TRACE(WARNING, "EMM-PROC - Failed to respond to Attach Request"); + emm_ctx->emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + /* Do not accept the UE to attach to the network */ + rc = _emm_attach_reject(emm_ctx); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_accept() ** + ** ** + ** Description: Sends ATTACH ACCEPT message and start timer T3450 ** + ** ** + ** Inputs: data: Attach accept retransmission data ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3450 ** + ** ** + ***************************************************************************/ +static int _emm_attach_accept(emm_data_context_t* emm_ctx, attach_data_t* data) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify EMM-AS SAP that Attach Accept message together with an Activate + * Default EPS Bearer Context Request message has to be sent to the UE + */ + emm_sap.primitive = EMMAS_ESTABLISH_CNF; + emm_sap.u.emm_as.u.establish.ueid = emm_ctx->ueid; + if (emm_ctx->guti_is_new && emm_ctx->old_guti) { + /* Implicit GUTI reallocation; + * include the new assigned GUTI in the Attach Accept message */ + emm_sap.u.emm_as.u.establish.UEid.guti = emm_ctx->old_guti; + emm_sap.u.emm_as.u.establish.new_guti = emm_ctx->guti; + } else { + emm_sap.u.emm_as.u.establish.UEid.guti = emm_ctx->guti; + emm_sap.u.emm_as.u.establish.new_guti = NULL; + } + emm_sap.u.emm_as.u.establish.n_tacs = emm_ctx->n_tacs; + emm_sap.u.emm_as.u.establish.tac = emm_ctx->tac; + emm_sap.u.emm_as.u.establish.NASinfo = EMM_AS_NAS_INFO_ATTACH; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.establish.sctx, + emm_ctx->security, FALSE, TRUE); + /* Get the activate default EPS bearer context request message to + * transfer within the ESM container of the attach accept message */ + emm_sap.u.emm_as.u.establish.NASmsg = data->esm_msg; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + if (T3450.id != NAS_TIMER_INACTIVE_ID) { + /* Re-start T3450 timer */ + T3450.id = nas_timer_restart(T3450.id); + } else { + /* Start T3450 timer */ + T3450.id = nas_timer_start(T3450.sec, _emm_attach_t3450_handler, data); + } + LOG_TRACE(INFO,"EMM-PROC - Timer T3450 (%d) expires in %ld seconds", + T3450.id, T3450.sec); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_have_changed() ** + ** ** + ** Description: Check whether the given attach parameters differs from ** + ** those previously stored when the attach procedure has ** + ** been initiated. ** + ** ** + ** Inputs: ctx: EMM context of the UE in the network ** + ** type: Type of the requested attach ** + ** ksi: Security ket sey identifier ** + ** guti: The GUTI provided by the UE ** + ** imsi: The IMSI provided by the UE ** + ** imei: The IMEI provided by the UE ** + ** eea: Supported EPS encryption algorithms ** + ** eia: Supported EPS integrity algorithms ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE if at least one of the parameters ** + ** differs; FALSE otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_attach_have_changed(const emm_data_context_t* ctx, + emm_proc_attach_type_t type, int ksi, + GUTI_t* guti, imsi_t* imsi, imei_t* imei, + int eea, int eia) +{ + /* Emergency bearer services indicator */ + if ( (type == EMM_ATTACH_TYPE_EMERGENCY) != ctx->is_emergency) + return (TRUE); + /* Security key set identifier */ + if (ksi != ctx->ksi) return (TRUE); + /* Supported EPS encryption algorithms */ + if (eea != ctx->eea) return (TRUE); + /* Supported EPS integrity algorithms */ + if (eia != ctx->eia) return (TRUE); + /* The GUTI if provided by the UE */ + if ( (guti) && (ctx->guti == NULL) ) return (TRUE); + if ( (guti == NULL) && (ctx->guti) ) return (TRUE); + if ( (guti) && (ctx->guti) ) { + if (guti->m_tmsi != ctx->guti->m_tmsi) return (TRUE); + if ( memcmp(&guti->gummei, &ctx->guti->gummei, sizeof(gummei_t)) != 0 ) + return (TRUE); + } + /* The IMSI if provided by the UE */ + if ( (imsi) && (ctx->imsi == NULL) ) return (TRUE); + if ( (imsi == NULL) && (ctx->imsi) ) return (TRUE); + if ( (imsi) && (ctx->imsi) ) { + if ( memcmp(imsi, ctx->imsi, sizeof(imsi_t)) != 0 ) return (TRUE); + } + /* The IMEI if provided by the UE */ + if ( (imei) && (ctx->imei == NULL) ) return (TRUE); + if ( (imei == NULL) && (ctx->imei) ) return (TRUE); + if ( (imei) && (ctx->imei) ) { + if ( memcmp(imei, ctx->imei, sizeof(imei_t)) != 0 ) return (TRUE); + } + return (FALSE); +} + +/**************************************************************************** + ** ** + ** Name: _emm_attach_update() ** + ** ** + ** Description: Update the EMM context with the given attach procedure ** + ** parameters. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** type: Type of the requested attach ** + ** ksi: Security ket sey identifier ** + ** guti: The GUTI provided by the UE ** + ** imsi: The IMSI provided by the UE ** + ** imei: The IMEI provided by the UE ** + ** eea: Supported EPS encryption algorithms ** + ** eia: Supported EPS integrity algorithms ** + ** esm_msg: ESM message contained with the attach re- ** + ** quest ** + ** Others: None ** + ** ** + ** Outputs: ctx: EMM context of the UE in the network ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_attach_update(emm_data_context_t* ctx, unsigned int ueid, + emm_proc_attach_type_t type, int ksi, + GUTI_t* guti, imsi_t* imsi, imei_t* imei, + int eea, int eia, const OctetString* esm_msg) +{ + /* UE identifier */ + ctx->ueid = ueid; + /* Emergency bearer services indicator */ + ctx->is_emergency = (type == EMM_ATTACH_TYPE_EMERGENCY); + /* Security key set identifier */ + ctx->ksi = ksi; + /* Supported EPS encryption algorithms */ + ctx->eea = eea; + /* Supported EPS integrity algorithms */ + ctx->eia = eia; + /* The GUTI if provided by the UE */ + if (guti) { + if (ctx->guti == NULL) + ctx->guti = (GUTI_t*)malloc(sizeof(GUTI_t)); + if (ctx->guti != NULL) + memcpy(ctx->guti, guti, sizeof(GUTI_t)); + else return (RETURNerror); + } + /* The IMSI if provided by the UE */ + if (imsi) { + if (ctx->imsi == NULL) + ctx->imsi = (imsi_t*)malloc(sizeof(imsi_t)); + if (ctx->imsi != NULL) + memcpy(ctx->imsi, imsi, sizeof(imsi_t)); + else return (RETURNerror); + } + /* The IMEI if provided by the UE */ + if (imei) { + if (ctx->imei == NULL) + ctx->imei = (imei_t*)malloc(sizeof(imei_t)); + if (ctx->imei != NULL) + memcpy(ctx->imei, imei, sizeof(imei_t)); + else return (RETURNerror); + } + /* The ESM message contained within the attach request */ + if (esm_msg->length > 0) { + if (ctx->esm_msg.length == 0) { + ctx->esm_msg.value = (uint8_t*)malloc(esm_msg->length); + } + if (ctx->esm_msg.value != NULL) { + strncpy((char*)ctx->esm_msg.value, + (char*)esm_msg->value, esm_msg->length); + } else return (RETURNerror); + } + ctx->esm_msg.length = esm_msg->length; + /* Attachment indicator */ + ctx->is_attached = FALSE; + + return (RETURNok); +} + +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/Authentication.c b/openair-cn/NAS/EURECOM-NAS/src/emm/Authentication.c new file mode 100644 index 0000000000..aebdcb916b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/Authentication.c @@ -0,0 +1,1382 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source Authentication.c + +Version 0.1 + +Date 2013/03/04 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the authentication EMM procedure executed by the + Non-Access Stratum. + + The purpose of the EPS authentication and key agreement (AKA) + procedure is to provide mutual authentication between the user + and the network and to agree on a key KASME. The procedure is + always initiated and controlled by the network. However, the + UE can reject the EPS authentication challenge sent by the + network. + + A partial native EPS security context is established in the + UE and the network when an EPS authentication is successfully + performed. The computed key material KASME is used as the + root for the EPS integrity protection and ciphering key + hierarchy. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" +#include "emm_cause.h" + +#ifdef NAS_UE +#include "usim_api.h" +#endif + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy, memcmp, memset + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * Retransmission timer handlers + */ +extern void* _emm_attach_t3410_handler(void*); +extern void* _emm_service_t3417_handler(void*); +extern void* _emm_detach_t3421_handler(void*); +extern void* _emm_tau_t3430_handler(void*); +#endif // NAS_UE + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the authentication procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Timer handlers + */ +static void* _authentication_t3416_handler(void*); +static void* _authentication_t3418_handler(void*); +static void* _authentication_t3420_handler(void*); + +/* + * Internal data used for authentication procedure + */ +static struct { + uint8_t rand[AUTH_RAND_SIZE]; /* Random challenge number */ + uint8_t res[AUTH_RES_SIZE]; /* Authentication response */ + uint8_t ck[AUTH_CK_SIZE]; /* Ciphering key */ + uint8_t ik[AUTH_IK_SIZE]; /* Integrity key */ +#define AUTHENTICATION_T3410 0x01 +#define AUTHENTICATION_T3417 0x02 +#define AUTHENTICATION_T3421 0x04 +#define AUTHENTICATION_T3430 0x08 + unsigned char timers; /* Timer restart bitmap */ +#define AUTHENTICATION_COUNTER_MAX 3 + unsigned char mac_count:2; /* MAC failure counter (#20) */ + unsigned char umts_count:2; /* UMTS challenge failure counter (#26) */ + unsigned char sync_count:2; /* Sync failure counter (#21) */ +} _authentication_data; + +/* + * Abnormal case authentication procedure + */ +static int _authentication_abnormal_cases_cde(int emm_cause, const OctetString* auts); +static int _authentication_abnormal_case_f(void); + +static int _authentication_stop_timers(void); +static int _authentication_start_timers(void); +static int _authentication_kasme(const OctetString* autn, const OctetString* ck, const OctetString* ik, const plmn_t* plmn, OctetString* kasme); +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the authentication procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _authentication_t3460_handler(void*); + +/* + * Function executed whenever the ongoing EMM procedure that initiated + * the authentication procedure is aborted or the maximum value of the + * retransmission timer counter is exceed + */ +static int _authentication_abort(void*); + +/* + * Internal data used for authentication procedure + */ +typedef struct { + unsigned int ueid; /* UE identifier */ +#define AUTHENTICATION_COUNTER_MAX 5 + unsigned int retransmission_count; /* Retransmission counter */ + int ksi; /* NAS key set identifier */ + OctetString rand; /* Random challenge number */ + OctetString autn; /* Authentication token */ + int notify_failure; /* Indicates whether the authentication + * procedure failure shall be notified + * to the ongoing EMM procedure */ +} authentication_data_t; + +static int _authentication_request(authentication_data_t* data); +static int _authentication_reject(unsigned int ueid); +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Authentication procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_authentication_request() ** + ** ** + ** Description: Performs the MME requested authentication procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.3 ** + ** Upon receiving the AUTHENTICATION REQUEST message, the UE ** + ** shall store the received RAND together with the RES re- ** + ** turned from the USIM in the volatile memory of the ME, to ** + ** avoid a synchronisation failure. The UE shall process the ** + ** authentication challenge data and respond with an AUTHEN- ** + ** TICATION RESPONSE message to the network. ** + ** ** + ** Inputs: native_ksi: TRUE if the security context is of type ** + ** native (for KSIASME) ** + ** ksi: The NAS ket sey identifier ** + ** rand: Authentication parameter RAND ** + ** autn: Authentication parameter AUTN ** + ** Others: _emm_data, _authentication_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, _authentication_data, T3416, ** + ** T3418, T3420 ** + ** ** + ***************************************************************************/ +int emm_proc_authentication_request(int native_ksi, int ksi, + const OctetString* rand, + const OctetString* autn) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMM-PROC - Authentication requested ksi = %d", ksi); + + /* 3GPP TS 24.301, section 5.4.2.1 + * The UE shall proceed with an EPS authentication challenge only if a + * USIM is present + */ + if (!_emm_data.usim_is_valid) { + LOG_TRACE(WARNING, "EMM-PROC - USIM is not present or not valid"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Stop timer T3418, if running */ + if (T3418.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3418 (%d)", T3418.id); + T3418.id = nas_timer_stop(T3418.id); + } + /* Stop timer T3420, if running */ + if (T3420.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3420 (%d)", T3420.id); + T3420.id = nas_timer_stop(T3420.id); + } + + /* Setup security keys */ + OctetString ck = {AUTH_CK_SIZE, _authentication_data.ck}; + OctetString ik = {AUTH_IK_SIZE, _authentication_data.ik}; + OctetString res = {AUTH_RES_SIZE, _authentication_data.res}; + + if (memcmp(_authentication_data.rand, rand->value, AUTH_CK_SIZE) != 0) { + /* + * There is no valid stored RAND in the ME or the stored RAND is + * different from the new received value in the AUTHENTICATION + * REQUEST message + */ + OctetString auts; + auts.length = 0; + auts.value = (uint8_t*)malloc(AUTH_AUTS_SIZE); + if (auts.value == NULL) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to allocate AUTS parameter"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* 3GPP TS 33.401, section 6.1.1 + * Get the "separation bit" of the AMF field of AUTN */ + int sbit = AUTH_AMF_SEPARATION_BIT(autn->value[AUTH_AMF_INDEX]); + if (sbit != 0) { + /* + * Perform EPS authentication challenge to check the authenticity + * of the core network by means of the received AUTN parameter and + * request the USIM to compute RES, CK and IK for given RAND + */ + rc = usim_api_authenticate(rand, autn, &auts, &res, &ck, &ik); + } + if (rc != RETURNok) { + /* + * Network authentication not accepted by the UE + */ + LOG_TRACE(WARNING, "EMM-PROC - Network authentication failed (%s)", + (auts.length > 0) ? "SQN failure" : + (sbit == 0) ? "Non-EPS authentication unacceptable" : + "MAC code failure"); + /* Delete any previously stored RAND and RES and stop timer T3416 */ + (void) emm_proc_authentication_delete(); + /* Proceed authentication abnormal cases procedure */ + if (auts.length > 0) { + /* 3GPP TS 24.301, section 5.4.2.6, case e + * SQN failure */ + rc = _authentication_abnormal_cases_cde( + EMM_CAUSE_SYNCH_FAILURE, &auts); + } else if (sbit == 0) { + /* 3GPP TS 24.301, section 5.4.2.6, case d + * Non-EPS authentication unacceptable */ + rc = _authentication_abnormal_cases_cde( + EMM_CAUSE_NON_EPS_AUTH_UNACCEPTABLE, NULL); + } else { + /* 3GPP TS 24.301, section 5.4.2.6, case c + * MAC code failure */ + rc = _authentication_abnormal_cases_cde( + EMM_CAUSE_MAC_FAILURE, NULL); + } + /* Free the AUTS parameter */ + free(auts.value); + LOG_FUNC_RETURN (rc); + } + + /* Free the AUTS parameter */ + free(auts.value); + /* Store the new RAND in the volatile memory */ + if (rand->length <= AUTH_RAND_SIZE) { + memcpy(_authentication_data.rand, rand->value, rand->length); + } + /* Start, or reset and restart timer T3416 */ + if (T3416.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3416 (%d)", T3416.id); + T3416.id = nas_timer_stop(T3416.id); + } + T3416.id = nas_timer_start(T3416.sec, _authentication_t3416_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3416 (%d) expires in %ld seconds", + T3416.id, T3416.sec); + } + + /* + * The stored RAND value is equal to the new received value in the + * AUTHENTICATION REQUEST message, or the UE has successfully checked + * the authenticity of the core network + */ + /* Start any retransmission timers */ + rc = _authentication_start_timers(); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to start retransmission timers"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "EMM-PROC - Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Notify EMM-AS SAP that Authentication Response message has to be sent + * to the network + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMAS_SECURITY_RES; + emm_sap.u.emm_as.u.security.guti = _emm_data.guti; + emm_sap.u.emm_as.u.security.ueid = 0; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH; + emm_sap.u.emm_as.u.security.emm_cause = EMM_CAUSE_SUCCESS; + emm_sap.u.emm_as.u.security.res = &res; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + _emm_data.security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Reset the authentication failure counters */ + _authentication_data.mac_count = 0; + _authentication_data.umts_count = 0; + _authentication_data.sync_count = 0; + /* Create non-current EPS security context */ + if (_emm_data.non_current == NULL) { + _emm_data.non_current = + (emm_security_context_t*)malloc(sizeof(emm_security_context_t)); + } + if (_emm_data.non_current) { + memset(_emm_data.non_current, 0, sizeof(emm_security_context_t)); + /* Set the security context type */ + if (native_ksi) { + _emm_data.non_current->type = EMM_KSI_NATIVE; + } else { + _emm_data.non_current->type = EMM_KSI_MAPPED; + } + /* Set the EPS key set identifier */ + _emm_data.non_current->eksi = ksi; + /* Derive the Kasme from the authentication challenge using + * the PLMN identity of the selected PLMN */ + _emm_data.non_current->kasme.length = AUTH_KASME_SIZE; + _emm_data.non_current->kasme.value = + (uint8_t*)malloc(sizeof(AUTH_KASME_SIZE)); + _authentication_kasme(autn, &ck, &ik, &_emm_data.splmn, + &_emm_data.non_current->kasme); + /* NAS integrity and cyphering keys are not yet available */ + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_authentication_reject() ** + ** ** + ** Description: Performs the authentication procedure not accepted by the ** + ** network. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.5 ** + ** Upon receiving an AUTHENTICATION REJECT message, the UE ** + ** shall abort any EMM signalling procedure, stop any of the ** + ** timers T3410, T3417 or T3430 (if running) and enter state ** + ** EMM-DEREGISTERED. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, _authentication_data, T3410, ** + ** T3417, T3430 ** + ** ** + ***************************************************************************/ +int emm_proc_authentication_reject(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - Authentication not accepted by the network"); + + /* Delete any previously stored RAND and RES and stop timer T3416 */ + (void) emm_proc_authentication_delete(); + + /* Set the EPS update status to EU3 ROAMING NOT ALLOWED */ + _emm_data.status = EU3_ROAMING_NOT_ALLOWED; + /* Delete the stored GUTI */ + _emm_data.guti = NULL; + /* Delete the TAI list */ + _emm_data.ltai.n_tais = 0; + /* Delete the last visited registered TAI */ + _emm_data.tai = NULL; + /* Delete the eKSI */ + if (_emm_data.security) { + _emm_data.security->type = EMM_KSI_NOT_AVAILABLE; + } + /* Consider the USIM invalid */ + _emm_data.usim_is_valid = FALSE; + + /* Stop timer T3410 */ + if (T3410.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + } + /* Stop timer T3417 */ + if (T3417.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3417 (%d)", T3417.id); + T3417.id = nas_timer_stop(T3417.id); + } + /* Stop timer T3430 */ + if (T3430.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3430 (%d)", T3430.id); + T3430.id = nas_timer_stop(T3430.id); + } + + /* Abort any EMM signalling procedure (prevent the retransmission timers to + * be restarted) */ + _authentication_data.timers = 0x00; + + /* + * Notify EMM that authentication is not accepted by the network + */ + emm_sap.primitive = EMMREG_AUTH_REJ; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_authentication_delete() ** + ** ** + ** Description: Deletes the RAND and RES values stored into the volatile ** + ** memory of the Mobile Equipment and stop timer T3416, if ** + ** running, upon receipt of a SECURITY MODE COMMAND, SERVICE ** + ** REJECT, TRACKING AREA UPDATE REJECT, TRACKING AREA UPDATE ** + ** ACCEPT or AUTHENTICATION REJECT message; upon expiry of ** + ** timer T3416; or if the UE enters the EMM state EMM- ** + ** DEREGISTERED or EMM-NULL. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.3 ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _authentication_data, T3416 ** + ** ** + ***************************************************************************/ +int emm_proc_authentication_delete(void) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMM-PROC - Delete authentication data RAND and RES"); + + /* Stop timer T3416, if running */ + if (T3416.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3416 (%d)", T3416.id); + T3416.id = nas_timer_stop(T3416.id); + } + /* Delete any previously stored RAND and RES */ + memset(_authentication_data.rand, 0, AUTH_RAND_SIZE); + memset(_authentication_data.res, 0, AUTH_RES_SIZE); + + LOG_FUNC_RETURN (RETURNok); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Authentication procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_proc_authentication() ** + ** ** + ** Description: Initiates authentication procedure to establish partial ** + ** native EPS security context in the UE and the MME. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.2 ** + ** The network initiates the authentication procedure by ** + ** sending an AUTHENTICATION REQUEST message to the UE and ** + ** starting the timer T3460. The AUTHENTICATION REQUEST mes- ** + ** sage contains the parameters necessary to calculate the ** + ** authentication response. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** ksi: NAS key set identifier ** + ** rand: Random challenge number ** + ** autn: Authentication token ** + ** success: Callback function executed when the authen-** + ** tication procedure successfully completes ** + ** reject: Callback function executed when the authen-** + ** tication procedure fails or is rejected ** + ** failure: Callback function executed whener a lower ** + ** layer failure occured before the authenti- ** + ** cation procedure comnpletes ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_authentication(unsigned int ueid, int ksi, + const OctetString* _rand, const OctetString* autn, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure) + +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMM-PROC - Initiate authentication KSI = %d", ksi); + + /* Allocate parameters of the retransmission timer callback */ + authentication_data_t* data = + (authentication_data_t*)malloc(sizeof(authentication_data_t)); + + if (data != NULL) { + /* Setup ongoing EMM procedure callback functions */ + rc = emm_proc_common_initialize(ueid, success, reject, failure, + _authentication_abort, data); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "Failed to initialize EMM callback functions"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Set the UE identifier */ + data->ueid = ueid; + /* Reset the retransmission counter */ + data->retransmission_count = 0; + /* Set the key set identifier */ + data->ksi = ksi; + /* Set the authentication random challenge number */ + if (_rand->length > 0) { + data->rand.value = (uint8_t*)malloc(_rand->length); + data->rand.length = 0; + if (data->rand.value) { + memcpy(data->rand.value, _rand->value, _rand->length); + data->rand.length = _rand->length; + } + } + /* Set the authentication token */ + if (autn->length > 0) { + data->autn.value = (uint8_t*)malloc(autn->length); + data->autn.length = 0; + if (data->autn.value) { + memcpy(data->autn.value, autn->value, autn->length); + data->autn.length = autn->length; + } + } + /* Set the failure notification indicator */ + data->notify_failure = FALSE; + /* Send authentication request message to the UE */ + rc = _authentication_request(data); + if (rc != RETURNerror) { + /* + * Notify EMM that common procedure has been initiated + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REQ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_authentication_complete() ** + ** ** + ** Description: Performs the authentication completion procedure executed ** + ** by the network. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.4 ** + ** Upon receiving the AUTHENTICATION RESPONSE message, the ** + ** MME shall stop timer T3460 and check the correctness of ** + ** the RES parameter. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** emm_cause: Authentication failure EMM cause code ** + ** res: Authentication response parameter ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, T3460 ** + ** ** + ***************************************************************************/ +int emm_proc_authentication_complete(unsigned int ueid, int emm_cause, + const OctetString* res) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + + LOG_TRACE(INFO, "EMM-PROC - Authentication complete (ueid=%u, cause=%d)", + ueid, emm_cause); + + /* Stop timer T3460 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3460 (%d)", T3460.id); + T3460.id = nas_timer_stop(T3460.id); + + /* Release retransmission timer paramaters */ + authentication_data_t* data = + (authentication_data_t*)(emm_proc_common_get_args(ueid)); + if (data) { + if (data->rand.length > 0) { + free(data->rand.value); + } + if (data->autn.length > 0) { + free(data->autn.value); + } + free(data); + } + + /* Get the UE context */ + emm_data_context_t* emm_ctx = NULL; + +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_cause == EMM_CAUSE_SUCCESS) { + /* Check the received RES parameter */ + if ( (emm_ctx == NULL) || + (memcmp(res->value, &emm_ctx->vector.xres, res->length) != 0) ) { + /* RES does not match the XRES parameter */ + LOG_TRACE(WARNING, "EMM-PROC - Failed to authentify the UE"); + emm_cause = EMM_CAUSE_ILLEGAL_UE; + } + } + + if (emm_cause != EMM_CAUSE_SUCCESS) { + /* The MME received an authentication failure message or the RES + * contained in the Authentication Response message received from + * the UE does not match the XRES parameter computed by the network */ + (void) _authentication_reject(ueid); + /* + * Notify EMM that the authentication procedure failed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + } + else { + /* + * Notify EMM that the authentication procedure successfully completed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_CNF; + emm_sap.u.emm_reg.ueid = ueid; + emm_sap.u.emm_reg.u.common.is_attached = emm_ctx->is_attached; + } + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _authentication_t3416_handler() ** + ** ** + ** Description: T3416 timeout handler ** + ** Upon T3416 timer expiration, the RAND and RES values sto- ** + ** red in the ME shall be deleted. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.3 ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: T3416 ** + ** ** + ***************************************************************************/ +static void* _authentication_t3416_handler(void* args) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - T3416 timer expired"); + + /* Stop timer T3416 */ + T3416.id = nas_timer_stop(T3416.id); + /* Delete previouly stored RAND and RES authentication data */ + (void) emm_proc_authentication_delete(); + + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_t3418_handler() ** + ** ** + ** Description: T3418 timeout handler ** + ** Upon T3418 timer expiration, the UE shall deem that the ** + ** source of the authentication challenge is not genuine ** + ** (authentication not accepted by the UE). ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, case c ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _authentication_data, T3418 ** + ** ** + ***************************************************************************/ +static void* _authentication_t3418_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - T3418 timer expired"); + + /* Stop timer T3418 */ + T3418.id = nas_timer_stop(T3418.id); + /* Reset the MAC failure and UMTS challenge failure counters */ + _authentication_data.mac_count = 0; + _authentication_data.umts_count = 0; + /* 3GPP TS 24.301, section 5.4.2.7, case f */ + rc = _authentication_abnormal_case_f(); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to proceed abnormal case f"); + } + + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_t3420_handler() ** + ** ** + ** Description: T3420 timeout handler ** + ** Upon T3420 timer expiration, the UE shall deem that the ** + ** network has failed the authentication check. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, case e ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _authentication_data, T3420 ** + ** ** + ***************************************************************************/ +static void* _authentication_t3420_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - T3420 timer expired"); + + /* Stop timer T3420 */ + T3420.id = nas_timer_stop(T3420.id); + /* Reset the sync failure counter */ + _authentication_data.sync_count = 0; + /* 3GPP TS 24.301, section 5.4.2.7, case f */ + rc = _authentication_abnormal_case_f(); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - Failed to proceed abnormal case f"); + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * Abnormal cases in the UE + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _authentication_abnormal_cases_cde() ** + ** ** + ** Description: Performs the abnormal case authentication procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, cases c, d and e ** + ** ** + ** Inputs: emm_cause: EMM cause code ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _authentication_data, T3418, T3420 ** + ** ** + ***************************************************************************/ +static int _authentication_abnormal_cases_cde(int emm_cause, + const OctetString* auts) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - " + "Abnormal case, authentication counters c/d/e = %d/%d/%d", + _authentication_data.mac_count, _authentication_data.umts_count, + _authentication_data.sync_count); + + /* + * Notify EMM-AS SAP that Authentication Failure message has to be sent + * to the network + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMAS_SECURITY_RES; + emm_sap.u.emm_as.u.security.guti = _emm_data.guti; + emm_sap.u.emm_as.u.security.ueid = 0; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH; + emm_sap.u.emm_as.u.security.emm_cause = emm_cause; + emm_sap.u.emm_as.u.security.auts = auts; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + _emm_data.security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* + * Update the authentication failure counters + */ + switch (emm_cause) + { + case EMM_CAUSE_MAC_FAILURE: + /* 3GPP TS 24.301, section 5.4.2.6, case c + * Update the MAC failure counter */ + _authentication_data.mac_count += 1; + /* Start timer T3418 */ + T3418.id = nas_timer_start(T3418.sec, + _authentication_t3418_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3418 (%d) expires in " + "%ld seconds", T3418.id, T3418.sec); + break; + + case EMM_CAUSE_NON_EPS_AUTH_UNACCEPTABLE: + /* 3GPP TS 24.301, section 5.4.2.6, case d + * Update the UMTS challenge failure counter */ + _authentication_data.umts_count += 1; + /* Start timer T3418 */ + T3418.id = nas_timer_start(T3418.sec, + _authentication_t3418_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3418 (%d) expires in " + "%ld seconds", T3418.id, T3418.sec); + break; + + case EMM_CAUSE_SYNCH_FAILURE: + /* 3GPP TS 24.301, section 5.4.2.6, case e + * Update the synch failure counter */ + _authentication_data.sync_count += 1; + /* Start timer T3420 */ + T3420.id = nas_timer_start(T3420.sec, + _authentication_t3420_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3420 (%d) expires in " + "%ld seconds", T3420.id, T3420.sec); + break; + + default: + LOG_TRACE(WARNING, "EMM cause code is not valid (%d)", + emm_cause); + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Stop any retransmission timers that are running + */ + rc = _authentication_stop_timers(); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to stop retransmission timers"); + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Check whether the network has failed the authentication check + */ + int failure_counter = 0; + if (emm_cause == EMM_CAUSE_MAC_FAILURE) { + failure_counter = _authentication_data.mac_count + + _authentication_data.sync_count; + } else if (emm_cause == EMM_CAUSE_SYNCH_FAILURE) { + failure_counter = _authentication_data.mac_count + + _authentication_data.umts_count + + _authentication_data.sync_count; + } + if (failure_counter >= AUTHENTICATION_COUNTER_MAX) { + /* 3GPP TS 24.301, section 5.4.2.6, case f */ + rc = _authentication_abnormal_case_f(); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-PROC - " + "Failed to proceed abnormal case f"); + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_abnormal_case_f() ** + ** ** + ** Description: Performs the abnormal case authentication procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, case f ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _authentication_abnormal_case_f(void) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - Authentication abnormal case f"); + + /* + * Request RRC to locally release the RRC connection and treat + * the active cell as barred + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMAS_RELEASE_REQ; + emm_sap.u.emm_as.u.release.guti = _emm_data.guti; + emm_sap.u.emm_as.u.release.cause = EMM_AS_CAUSE_AUTHENTICATION; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start any retransmission timers (e.g. T3410, T3417, T3421 or + * T3430), if they were running and stopped when the UE received + * the first AUTHENTICATION REQUEST message containing an invalid + * MAC or SQN */ + rc = _authentication_start_timers(); + } + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * UE specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _authentication_stop_timers() ** + ** ** + ** Description: Stops any retransmission timers (e.g. T3410, T3417, T3421 ** + ** or T3430) that are running ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _authentication_data, T3410, T3417, T3421, ** + ** T3430 ** + ** ** + ***************************************************************************/ +static int _authentication_stop_timers(void) +{ + LOG_FUNC_IN; + + /* Stop attach timer */ + if (T3410.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); + T3410.id = nas_timer_stop(T3410.id); + _authentication_data.timers |= AUTHENTICATION_T3410; + } + /* Stop service request timer */ + if (T3417.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3417 (%d)", T3417.id); + T3417.id = nas_timer_stop(T3417.id); + _authentication_data.timers |= AUTHENTICATION_T3417; + } + /* Stop detach timer */ + if (T3421.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3421 (%d)", T3421.id); + T3421.id = nas_timer_stop(T3421.id); + _authentication_data.timers |= AUTHENTICATION_T3421; + } + /* Stop tracking area update timer */ + if (T3430.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3430 (%d)", T3430.id); + T3430.id = nas_timer_stop(T3430.id); + _authentication_data.timers |= AUTHENTICATION_T3430; + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_start_timers() ** + ** ** + ** Description: Starts any retransmission timers (e.g. T3410, T3417, ** + ** T3421 or T3430), if they were running and stopped when ** + ** the UE received the first AUTHENTICATION REQUEST message ** + ** containing an invalid MAC or SQN ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, case f ** + ** ** + ** Inputs: None ** + ** Others: _authentication_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3410, T3417, T3421, T3430 ** + ** ** + ***************************************************************************/ +static int _authentication_start_timers(void) +{ + LOG_FUNC_IN; + + if (_authentication_data.timers & AUTHENTICATION_T3410) { + /* Start attach timer */ + T3410.id = nas_timer_start(T3410.sec, _emm_attach_t3410_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3410 (%d) expires in " + "%ld seconds", T3410.id, T3410.sec); + } + if (_authentication_data.timers & AUTHENTICATION_T3417) { + /* Start service request timer */ + T3417.id = nas_timer_start(T3417.sec, _emm_service_t3417_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3417 (%d) expires in " + "%ld seconds", T3417.id, T3417.sec); + } + if (_authentication_data.timers & AUTHENTICATION_T3421) { + /* Start detach timer */ + T3421.id = nas_timer_start(T3421.sec, _emm_detach_t3421_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3421 (%d) expires in " + "%ld seconds", T3421.id, T3421.sec); + } + if (_authentication_data.timers & AUTHENTICATION_T3430) { + /* Start tracking area update timer */ + T3430.id = nas_timer_start(T3430.sec, _emm_tau_t3430_handler, NULL); + LOG_TRACE(INFO,"EMM-PROC - Timer T3430 (%d) expires in " + "%ld seconds", T3430.id, T3430.sec); + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_kasme() ** + ** ** + ** Description: Computes the Key Access Security Management Entity Kasme ** + ** from the provided authentication challenge data. ** + ** ** + ** 3GPP TS 33.401, Annex A.2 ** + ** ** + ** Inputs: autn: Authentication token ** + ** ck: Cipherig key ** + ** ik: Integrity key ** + ** plmn: Identifier of the currently selected PLMN ** + ** Others: None ** + ** ** + ** Outputs: kasme: Key Access Security Management Entity ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _authentication_kasme(const OctetString* autn, + const OctetString* ck, const OctetString* ik, + const plmn_t* plmn, OctetString* kasme) +{ + LOG_FUNC_IN; + + /* Compute the derivation key KEY = CK || IK */ + UInt8_t key[ck->length + ik->length]; + memcpy(key, ck->value, ck->length); + memcpy(key + ck->length, ik->value, ik->length); + + /* Compute the KDF input parameter + * S = FC(0x10) || SNid || 0x00 0x03 || SQN ⊕ AK || 0x00 0x06 + */ + UInt8_t input[kasme->length]; + UInt16_t length; + int offset = 0; + int size_of_length = sizeof(length); + input[offset] = 0x10; offset += 1; + length = AUTH_SNID_SIZE; + memcpy(input + offset, plmn, length); offset += length; + memcpy(input + offset, &length, size_of_length); offset += size_of_length; + length = AUTH_SQN_SIZE; + memcpy(input + offset, autn, length); offset += length; + memcpy(input + offset, &length, size_of_length); + + /* TODO !!! Compute the Kasme key */ + // todo_hmac_256(key, input, kasme->value); + + LOG_FUNC_RETURN (RETURNok); +} +#endif // NAS_UE + +#ifdef NAS_MME +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _authentication_t3460_handler() ** + ** ** + ** Description: T3460 timeout handler ** + ** Upon T3460 timer expiration, the authentication request ** + ** message is retransmitted and the timer restarted. When ** + ** retransmission counter is exceed, the MME shall abort the ** + ** authentication procedure and any ongoing EMM specific ** + ** procedure and release the NAS signalling connection. ** + ** ** + ** 3GPP TS 24.301, section 5.4.2.7, case b ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _authentication_t3460_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + authentication_data_t* data = (authentication_data_t*)(args); + + /* Increment the retransmission counter */ + data->retransmission_count += 1; + + LOG_TRACE(WARNING, "EMM-PROC - T3460 timer expired, retransmission " + "counter = %d", data->retransmission_count); + + if (data->retransmission_count < AUTHENTICATION_COUNTER_MAX) { + /* Send authentication request message to the UE */ + rc = _authentication_request(data); + } + else { + unsigned int ueid = data->ueid; + /* Set the failure notification indicator */ + data->notify_failure = TRUE; + /* Abort the authentication procedure */ + rc = _authentication_abort(data); + /* Release the NAS signalling connection */ + if (rc != RETURNerror) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMAS_RELEASE_REQ; + emm_sap.u.emm_as.u.release.guti = NULL; + emm_sap.u.emm_as.u.release.ueid = ueid; + emm_sap.u.emm_as.u.release.cause = EMM_AS_CAUSE_AUTHENTICATION; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _authentication_request() ** + ** ** + ** Description: Sends AUTHENTICATION REQUEST message and start timer T3460** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3460 ** + ** ** + ***************************************************************************/ +int _authentication_request(authentication_data_t* data) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + struct emm_data_context_s *emm_ctx; + + /* + * Notify EMM-AS SAP that Authentication Request message has to be sent + * to the UE + */ + emm_sap.primitive = EMMAS_SECURITY_REQ; + emm_sap.u.emm_as.u.security.guti = NULL; + emm_sap.u.emm_as.u.security.ueid = data->ueid; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH; + emm_sap.u.emm_as.u.security.ksi = data->ksi; + emm_sap.u.emm_as.u.security.rand = &data->rand; + emm_sap.u.emm_as.u.security.autn = &data->autn; + + /* TODO: check for pointer validity */ +#if defined(EPC_BUILD) + emm_ctx = emm_data_context_get(&_emm_data, data->ueid); +#else + emm_ctx = _emm_data.ctx[data->ueid]; +#endif + + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + emm_ctx->security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + if (T3460.id != NAS_TIMER_INACTIVE_ID) { + /* Re-start T3460 timer */ + T3460.id = nas_timer_restart(T3460.id); + } else { + /* Start T3460 timer */ + T3460.id = nas_timer_start(T3460.sec, _authentication_t3460_handler, + data); + } + LOG_TRACE(INFO,"EMM-PROC - Timer T3460 (%d) expires in %ld seconds", + T3460.id, T3460.sec); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_reject() ** + ** ** + ** Description: Sends AUTHENTICATION REJECT message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _authentication_reject(unsigned int ueid) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + struct emm_data_context_s *emm_ctx; + + /* + * Notify EMM-AS SAP that Authentication Reject message has to be sent + * to the UE + */ + emm_sap.primitive = EMMAS_SECURITY_REJ; + emm_sap.u.emm_as.u.security.guti = NULL; + emm_sap.u.emm_as.u.security.ueid = ueid; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH; + +#if defined(EPC_BUILD) + emm_ctx = emm_data_context_get(&_emm_data, ueid); +#else + emm_ctx = _emm_data.ctx[ueid]; +#endif + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + emm_ctx->security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _authentication_abort() ** + ** ** + ** Description: Aborts the authentication procedure currently in progress ** + ** ** + ** Inputs: args: Authentication data to be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3460 ** + ** ** + ***************************************************************************/ +static int _authentication_abort(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + authentication_data_t* data = (authentication_data_t*)(args); + + if (data) + { + unsigned int ueid = data->ueid; + int notify_failure = data->notify_failure; + + LOG_TRACE(WARNING, "EMM-PROC - Abort authentication procedure " + "(ueid=%u)", ueid); + + /* Stop timer T3460 */ + if (T3460.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3460 (%d)", T3460.id); + T3460.id = nas_timer_stop(T3460.id); + } + /* Release retransmission timer paramaters */ + if (data->rand.length > 0) { + free(data->rand.value); + } + if (data->autn.length > 0) { + free(data->autn.value); + } + free(data); + + /* + * Notify EMM that the authentication procedure failed + */ + if (notify_failure) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } else { + rc = RETURNok; + } + } + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_MME + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/Detach.c b/openair-cn/NAS/EURECOM-NAS/src/emm/Detach.c new file mode 100644 index 0000000000..795107cedf --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/Detach.c @@ -0,0 +1,654 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source Detach.c + +Version 0.1 + +Date 2013/05/07 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the detach related EMM procedure executed by the + Non-Access Stratum. + + The detach procedure is used by the UE to detach for EPS servi- + ces, to disconnect from the last PDN it is connected to; by the + network to inform the UE that it is detached for EPS services + or non-EPS services or both, to disconnect the UE from the last + PDN to which it is connected and to inform the UE to re-attach + to the network and re-establish all PDN connections. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" +#include "esm_sap.h" + +#include <stdlib.h> // free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* String representation of the detach type */ +static const char* _emm_detach_type_str[] = { + "EPS", "IMSI", "EPS/IMSI", + "RE-ATTACH REQUIRED", "RE-ATTACH NOT REQUIRED", "RESERVED" +}; + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the detach procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Timer handlers + */ +void* _emm_detach_t3421_handler(void*); + +/* + * Abnormal case detach procedures + */ +static int _emm_detach_abort(emm_proc_detach_type_t type); + +/* + * Internal data used for detach procedure + */ +static struct { +#define EMM_DETACH_COUNTER_MAX 5 + unsigned int count; /* Counter used to limit the number of + * subsequently detach attempts */ + int switch_off; /* UE switch-off indicator */ + emm_proc_detach_type_t type; /* Type of the detach procedure + * currently in progress */ +} _emm_detach_data = {0, FALSE, EMM_DETACH_TYPE_RESERVED}; +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the detach procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Detach procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_detach() ** + ** ** + ** Description: Initiates the detach procedure in order for the UE to de- ** + ** tach for EPS services. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.1 ** + ** In state EMM-REGISTERED or EMM-REGISTERED-INITIATED, the ** + ** UE initiates the detach procedure by sending a DETACH RE- ** + ** QUEST message to the network, starting timer T3421 and ** + ** entering state EMM-DEREGISTERED-INITIATED. ** + ** ** + ** Inputs: type: Type of the requested detach ** + ** switch_off: Indicates whether the detach is required ** + ** because the UE is switched off or not ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_detach_data ** + ** ** + ***************************************************************************/ +int emm_proc_detach(emm_proc_detach_type_t type, int switch_off) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + emm_as_data_t *emm_as = &emm_sap.u.emm_as.u.data; + int rc; + + LOG_TRACE(INFO, "EMM-PROC - Initiate EPS detach type = %s (%d)", + _emm_detach_type_str[type], type); + + /* Initialize the detach procedure internal data */ + _emm_detach_data.count = 0; + _emm_detach_data.switch_off = switch_off; + _emm_detach_data.type = type; + + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(emm_proc_detach_request, + emm_proc_detach_failure, + emm_proc_detach_release, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Setup NAS information message to transfer */ + emm_as->NASinfo = EMM_AS_NAS_INFO_DETACH; + emm_as->NASmsg.length = 0; + emm_as->NASmsg.value = NULL; + /* Set the detach type */ + emm_as->type = type; + /* Set the switch-off indicator */ + emm_as->switch_off = switch_off; + /* Set the EPS mobile identity */ + emm_as->guti = _emm_data.guti; + emm_as->ueid = 0; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_as->sctx, _emm_data.security, FALSE, TRUE); + + /* + * Notify EMM-AS SAP that Detach Request message has to + * be sent to the network + */ + emm_sap.primitive = EMMAS_DATA_REQ; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_detach_request() ** + ** ** + ** Description: Performs the detach procedure upon receipt of indication ** + ** from lower layers that Detach Request message has been ** + ** successfully delivered to the network. ** + ** ** + ** Inputs: args: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3421 ** + ** ** + ***************************************************************************/ +int emm_proc_detach_request(void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + if ( !_emm_detach_data.switch_off ) { + /* Start T3421 timer */ + T3421.id = nas_timer_start(T3421.sec, _emm_detach_t3421_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3421 (%d) expires in %ld seconds", + T3421.id, T3421.sec); + } + + /* + * Notify EMM that Detach Request has been sent to the network + */ + emm_sap.primitive = EMMREG_DETACH_REQ; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_detach_accept() ** + ** ** + ** Description: Performs the UE initiated detach procedure for EPS servi- ** + ** ces only When the DETACH ACCEPT message is received from ** + ** the network. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.2 ** + ** Upon receiving the DETACH ACCEPT message, the UE shall ** + ** stop timer T3421, locally deactivate all EPS bearer con- ** + ** texts without peer-to-peer signalling and enter state EMM-** + ** DEREGISTERED. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3421 ** + ** ** + ***************************************************************************/ +int emm_proc_detach_accept(void) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMM-PROC - UE initiated detach procedure completion"); + + /* Reset EMM procedure handler */ + (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + + /* Stop timer T3421 */ + T3421.id = nas_timer_stop(T3421.id); + + /* + * Notify ESM that all EPS bearer contexts have to be locally deactivated + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; + esm_sap.data.eps_bearer_context_deactivate.ebi = ESM_SAP_ALL_EBI; + rc = esm_sap_send(&esm_sap); + + /* + * XXX - Upon receiving notification from ESM that all EPS bearer + * contexts are locally deactivated, the UE is considered as + * detached from the network and is entered state EMM-DEREGISTERED + */ + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_detach_failure() ** + ** ** + ** Description: Performs the detach procedure abnormal case upon receipt ** + ** of transmission failure of Detach Request message. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.4, case h ** + ** The UE shall restart the detach procedure. ** + ** ** + ** Inputs: is_initial: Not used ** + ** args: Not used ** + ** Others: _emm_detach_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_detach_failure(int is_initial, void* args) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + LOG_TRACE(WARNING, "EMM-PROC - Network detach failure"); + + /* Reset EMM procedure handler */ + (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + + /* Stop timer T3421 */ + T3421.id = nas_timer_stop(T3421.id); + + /* + * Notify EMM that detach procedure has to be restarted + */ + emm_sap.primitive = EMMREG_DETACH_INIT; + emm_sap.u.emm_reg.u.detach.switch_off = _emm_detach_data.switch_off; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_detach_release() ** + ** ** + ** Description: Performs the detach procedure abnormal case upon receipt ** + ** of NAS signalling connection release indication before ** + ** reception of Detach Accept message. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.4, case b ** + ** The detach procedure shall be aborted. ** + ** ** + ** Inputs: args: not used ** + ** Others: _emm_detach_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_detach_release(void* args) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - NAS signalling connection released"); + + /* Abort the detach procedure */ + int rc = _emm_detach_abort(_emm_detach_data.type); + + LOG_FUNC_RETURN(rc); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Detach procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_proc_detach() ** + ** ** + ** Description: Initiate the detach procedure to inform the UE that it is ** + ** detached for EPS services, or to re-attach to the network ** + ** and re-establish all PDN connections. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.3.1 ** + ** In state EMM-REGISTERED the network initiates the detach ** + ** procedure by sending a DETACH REQUEST message to the UE, ** + ** starting timer T3422 and entering state EMM-DEREGISTERED- ** + ** INITIATED. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** type: Type of the requested detach ** + ** Others: _emm_detach_type_str ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3422 ** + ** ** + ***************************************************************************/ +int emm_proc_detach(unsigned int ueid, emm_proc_detach_type_t type) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMM-PROC - Initiate detach type = %s (%d)", + _emm_detach_type_str[type], type); + + /* TODO */ + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_detach_request() ** + ** ** + ** Description: Performs the UE initiated detach procedure for EPS servi- ** + ** ces only When the DETACH REQUEST message is received by ** + ** the network. ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.2 ** + ** Upon receiving the DETACH REQUEST message the network ** + ** shall send a DETACH ACCEPT message to the UE and store ** + ** the current EPS security context, if the detach type IE ** + ** does not indicate "switch off". Otherwise, the procedure ** + ** is completed when the network receives the DETACH REQUEST ** + ** message. ** + ** The network shall deactivate the EPS bearer context(s) ** + ** for this UE locally without peer-to-peer signalling and ** + ** shall enter state EMM-DEREGISTERED. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** type: Type of the requested detach ** + ** switch_off: Indicates whether the detach is required ** + ** because the UE is switched off or not ** + ** native_ksi: TRUE if the security context is of type ** + ** native ** + ** ksi: The NAS ket sey identifier ** + ** guti: The GUTI if provided by the UE ** + ** imsi: The IMSI if provided by the UE ** + ** imei: The IMEI if provided by the UE ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_detach_request(unsigned int ueid, emm_proc_detach_type_t type, + int switch_off, int native_ksi, int ksi, + GUTI_t* guti, imsi_t* imsi, imei_t* imei) +{ + LOG_FUNC_IN; + + int rc; + emm_data_context_t* emm_ctx = NULL; + + LOG_TRACE(INFO, "EMM-PROC - Detach type = %s (%d) requested (ueid=%u)", + _emm_detach_type_str[type], type, ueid); + + /* Get the UE context */ +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_ctx == NULL) { + LOG_TRACE(WARNING, "No EMM context exists for the UE (ueid=%u)", ueid); + LOG_FUNC_RETURN(RETURNok); + } + + if (switch_off) + { + /* The UE is switched off */ + if (emm_ctx->guti) free(emm_ctx->guti); + if (emm_ctx->imsi) free(emm_ctx->imsi); + if (emm_ctx->imei) free(emm_ctx->imei); + if (emm_ctx->esm_msg.length > 0) free(emm_ctx->esm_msg.value); + /* Release NAS security context */ + if (emm_ctx->security) { + emm_security_context_t* security = emm_ctx->security; + if (security->kasme.value) free(security->kasme.value); + if (security->knas_enc.value) free(security->knas_enc.value); + if (security->knas_int.value) free(security->knas_int.value); + free(emm_ctx->security); + } + /* Release the EMM context */ +#if defined(EPC_BUILD) + emm_data_context_remove(&_emm_data, emm_ctx); + free(emm_ctx); +#else + free(_emm_data.ctx[ueid]); + _emm_data.ctx[ueid] = NULL; +#endif + rc = RETURNok; + } + else { + /* Normal detach without UE switch-off */ + emm_sap_t emm_sap; + emm_as_data_t *emm_as = &emm_sap.u.emm_as.u.data; + + /* Setup NAS information message to transfer */ + emm_as->NASinfo = EMM_AS_NAS_INFO_DETACH; + emm_as->NASmsg.length = 0; + emm_as->NASmsg.value = NULL; + /* Set the UE identifier */ + emm_as->guti = NULL; + emm_as->ueid = ueid; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_as->sctx, emm_ctx->security, FALSE, TRUE); + /* + * Notify EMM-AS SAP that Detach Accept message has to + * be sent to the network + */ + emm_sap.primitive = EMMAS_DATA_REQ; + rc = emm_sap_send(&emm_sap); + } + + if (rc != RETURNerror) { + /* + * Notify ESM that all EPS bearer contexts allocated for this UE have + * to be locally deactivated + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; + esm_sap.ueid = ueid; + esm_sap.data.eps_bearer_context_deactivate.ebi = ESM_SAP_ALL_EBI; + rc = esm_sap_send(&esm_sap); + + if (rc != RETURNerror) { + emm_sap_t emm_sap; + /* + * Notify EMM that the UE has been implicitly detached + */ + emm_sap.primitive = EMMREG_DETACH_REQ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN(rc); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_detach_t3421_handler() ** + ** ** + ** Description: T3421 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.5.2.2.4 case c ** + ** On the first four expiries of the timer, the UE shall re- ** + ** transmit the DETACH REQUEST message and shall reset and ** + ** restart timer T3421. On the fifth expiry of timer T3421, ** + ** the detach procedure shall be aborted. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: _emm_detach_data ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* _emm_detach_t3421_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Increment the retransmission counter */ + _emm_detach_data.count += 1; + + LOG_TRACE(WARNING, "EMM-PROC - T3421 timer expired, " + "retransmission counter = %d", _emm_detach_data.count); + + if (_emm_detach_data.count < EMM_DETACH_COUNTER_MAX) + { + /* Retransmit the Detach Request message */ + emm_sap_t emm_sap; + emm_as_data_t *emm_as = &emm_sap.u.emm_as.u.data; + + /* Stop timer T3421 */ + T3421.id = nas_timer_stop(T3421.id); + + /* Setup NAS information message to transfer */ + emm_as->NASinfo = EMM_AS_NAS_INFO_DETACH; + emm_as->NASmsg.length = 0; + emm_as->NASmsg.value = NULL; + /* Set the detach type */ + emm_as->type = _emm_detach_data.type; + /* Set the switch-off indicator */ + emm_as->switch_off = _emm_detach_data.switch_off; + /* Set the EPS mobile identity */ + emm_as->guti = _emm_data.guti; + emm_as->ueid = 0; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_as->sctx, _emm_data.security, + FALSE, TRUE); + + /* + * Notify EMM-AS SAP that Detach Request message has to + * be sent to the network + */ + emm_sap.primitive = EMMAS_DATA_REQ; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3421 timer */ + T3421.id = nas_timer_start(T3421.sec, _emm_detach_t3421_handler, NULL); + LOG_TRACE(INFO, "EMM-PROC - Timer T3421 (%d) expires in %ld " + "seconds", T3421.id, T3421.sec); + } + } + else { + /* Abort the detach procedure */ + rc = _emm_detach_abort(_emm_detach_data.type); + } + + LOG_FUNC_RETURN(NULL); +} + +/* + * -------------------------------------------------------------------------- + * Abnormal cases in the UE + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_detach_abort() ** + ** ** + ** Description: Aborts the detach procedure ** + ** ** + ** Inputs: type: not used ** + ** Others: _emm_detach_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3421 ** + ** ** + ***************************************************************************/ +static int _emm_detach_abort(emm_proc_detach_type_t type) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc ; + + LOG_TRACE(WARNING, "EMM-PROC - Abort the detach procedure"); + + /* Reset EMM procedure handler */ + (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + + /* Stop timer T3421 */ + T3421.id = nas_timer_stop(T3421.id); + + /* + * Notify EMM that detach procedure failed + */ + emm_sap.primitive = EMMREG_DETACH_FAILED; + emm_sap.u.emm_reg.u.detach.type = type; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.c b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.c new file mode 100644 index 0000000000..ac49332d5e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.c @@ -0,0 +1,483 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmCommon.h + +Version 0.1 + +Date 2013/04/19 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines callback functions executed within EMM common procedures + by the Non-Access Stratum running at the network side. + + Following EMM common procedures can always be initiated by the + network whilst a NAS signalling connection exists: + + GUTI reallocation + authentication + security mode control + identification + EMM information + +*****************************************************************************/ + +#ifdef NAS_MME + +#include "EmmCommon.h" + +#include "commonDef.h" +#include "nas_log.h" +#include "emmData.h" + +#include <stdlib.h> // malloc, free +#include <string.h> +#include <assert.h> + +#if defined(EPC_BUILD) +# include "assertions.h" +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* EMM procedure callback cleanup function */ +static void _emm_common_cleanup(unsigned int ueid); + +/* Ongoing EMM procedure callback functions */ +typedef struct emm_common_data_s { + unsigned int ueid; + int ref_count; + emm_common_success_callback_t success; + emm_common_reject_callback_t reject; + emm_common_failure_callback_t failure; + emm_common_abort_callback_t abort; + void* args; + +#if defined(EPC_BUILD) + RB_ENTRY(emm_common_data_s) entries; +#endif +} emm_common_data_t; + +#if defined(EPC_BUILD) +typedef struct emm_common_data_head_s { + RB_HEAD(emm_common_data_map, emm_common_data_s) emm_common_data_root; +} emm_common_data_head_t; + +emm_common_data_head_t emm_common_data_head = { RB_INITIALIZER() }; + +static inline +int emm_common_data_compare_ueid(struct emm_common_data_s *p1, + struct emm_common_data_s *p2); +struct emm_common_data_s *emm_common_data_context_get( + struct emm_common_data_head_s *root, unsigned int _ueid); + +RB_PROTOTYPE(emm_common_data_map, emm_common_data_s, entries, + emm_common_data_compare_ueid); + +/* Generate functions used for the MAP */ +RB_GENERATE(emm_common_data_map, emm_common_data_s, entries, + emm_common_data_compare_ueid); + +static inline +int emm_common_data_compare_ueid(struct emm_common_data_s *p1, + struct emm_common_data_s *p2) +{ + if (p1->ueid > p2->ueid) { + return 1; + } + if (p1->ueid < p2->ueid) { + return -1; + } + /* Matching reference -> return 0 */ + return 0; +} + +struct emm_common_data_s *emm_common_data_context_get( + struct emm_common_data_head_s *root, unsigned int _ueid) +{ + struct emm_common_data_s reference; + + DevAssert(root != NULL); + DevCheck(_ueid > 0, _ueid, 0, 0); + + memset(&reference, 0, sizeof(struct emm_common_data_s)); + reference.ueid = _ueid; + return RB_FIND(emm_common_data_map, &root->emm_common_data_root, &reference); +} +#else +static emm_common_data_t* _emm_common_data[EMM_DATA_NB_UE_MAX]; +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_initialize() ** + ** ** + ** Description: Initialize EMM procedure callback functions executed for ** + ** the UE with the given identifier ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** success: EMM procedure executed upon successful EMM ** + ** common procedure completion ** + ** reject: EMM procedure executed if the EMM common ** + ** procedure failed or is rejected ** + ** failure: EMM procedure executed upon transmission ** + ** failure reported by lower layer ** + ** abort: EMM common procedure executed when the on- ** + ** going EMM procedure is aborted ** + ** args: EMM common procedure argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_common_data ** + ** ** + ***************************************************************************/ +int emm_proc_common_initialize(unsigned int ueid, + emm_common_success_callback_t _success, + emm_common_reject_callback_t _reject, + emm_common_failure_callback_t _failure, + emm_common_abort_callback_t _abort, + void* args) +{ + struct emm_common_data_s *emm_common_data_ctx = NULL; + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + assert(ueid > 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); +#endif + + if (emm_common_data_ctx == NULL) { + emm_common_data_ctx = (emm_common_data_t*)malloc(sizeof(emm_common_data_t)); + emm_common_data_ctx->ueid = ueid; +#if defined(EPC_BUILD) + RB_INSERT(emm_common_data_map, &emm_common_data_head.emm_common_data_root, + emm_common_data_ctx); +#endif + if (emm_common_data_ctx) { + emm_common_data_ctx->ref_count = 0; + } + } + if (emm_common_data_ctx) { + emm_common_data_ctx->ref_count += 1; + emm_common_data_ctx->success = _success; + emm_common_data_ctx->reject = _reject; + emm_common_data_ctx->failure = _failure; + emm_common_data_ctx->abort = _abort; + emm_common_data_ctx->args = args; + LOG_FUNC_RETURN(RETURNok); + } + + LOG_FUNC_RETURN(RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_success() ** + ** ** + ** Description: The EMM common procedure initiated between the UE with ** + ** the specified identifier and the MME completed success- ** + ** fully. The network performs required actions related to ** + ** the ongoing EMM procedure. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: _emm_common_data, _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_common_success(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + emm_common_success_callback_t emm_callback; + + int rc = RETURNerror; + + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + + assert(emm_common_data_ctx != NULL); + + emm_callback = emm_common_data_ctx->success; + if (emm_callback) { + struct emm_data_context_s *ctx = NULL; + +#if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +#else + ctx = _emm_data.ctx[ueid]; +#endif + rc = (*emm_callback)(ctx); + } + + _emm_common_cleanup(ueid); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_reject() ** + ** ** + ** Description: The EMM common procedure initiated between the UE with ** + ** the specified identifier and the MME failed or has been ** + ** rejected. The network performs required actions related ** + ** to the ongoing EMM procedure. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: _emm_common_data, _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_common_reject(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + int rc = RETURNerror; + emm_common_reject_callback_t emm_callback; + + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + + assert(emm_common_data_ctx != NULL); + + emm_callback = emm_common_data_ctx->reject; + + if (emm_callback) { + struct emm_data_context_s *ctx = NULL; + +#if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +#else + ctx = _emm_data.ctx[ueid]; +#endif + rc = (*emm_callback)(ctx); + } + + _emm_common_cleanup(ueid); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_failure() ** + ** ** + ** Description: The EMM common procedure has been initiated between the ** + ** UE with the specified identifier and the MME, and a lower ** + ** layer failure occurred before the EMM common procedure ** + ** being completed. The network performs required actions ** + ** related to the ongoing EMM procedure. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: _emm_common_data, _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_common_failure(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + emm_common_failure_callback_t emm_callback; + + int rc = RETURNerror; + + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + assert(emm_common_data_ctx != NULL); + + emm_callback = emm_common_data_ctx->failure; + if (emm_callback) { + struct emm_data_context_s *ctx = NULL; + +#if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +#else + ctx = _emm_data.ctx[ueid]; +#endif + rc = (*emm_callback)(ctx); + } + + _emm_common_cleanup(ueid); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_abort() ** + ** ** + ** Description: The ongoing EMM procedure has been aborted. The network ** + ** performs required actions related to the EMM common pro- ** + ** cedure previously initiated between the UE with the spe- ** + ** cified identifier and the MME. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: _emm_common_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_common_abort(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + emm_common_failure_callback_t emm_callback; + + int rc = RETURNerror; + + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + assert(emm_common_data_ctx != NULL); + + emm_callback = emm_common_data_ctx->abort; + if (emm_callback) { + struct emm_data_context_s *ctx = NULL; + +#if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +#else + ctx = _emm_data.ctx[ueid]; +#endif + rc = (*emm_callback)(ctx); + } + + _emm_common_cleanup(ueid); + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_get_args() ** + ** ** + ** Description: Returns pointer to the EMM common procedure argument pa- ** + ** rameters allocated for the UE with the given identifier. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: _emm_common_data ** + ** ** + ** Outputs: None ** + ** Return: pointer to the EMM common procedure argu- ** + ** ment parameters ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* emm_proc_common_get_args(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + LOG_FUNC_IN; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + assert(emm_common_data_ctx != NULL); + + LOG_FUNC_RETURN(emm_common_data_ctx->args); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_proc_common_cleanup() ** + ** ** + ** Description: Cleans EMM procedure callback functions upon completion ** + ** of an EMM common procedure previously initiated within an ** + ** EMM procedure currently in progress between the network ** + ** and the UE with the specified identifier. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_common_data ** + ** ** + ***************************************************************************/ +static void _emm_common_cleanup(unsigned int ueid) +{ + emm_common_data_t *emm_common_data_ctx = NULL; + +#if defined(EPC_BUILD) + DevCheck(ueid > 0, ueid, 0, 0); + emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); +#else + assert(ueid < EMM_DATA_NB_UE_MAX); + emm_common_data_ctx = _emm_common_data[ueid]; +#endif + + if (emm_common_data_ctx) { + emm_common_data_ctx->ref_count -= 1; + if (emm_common_data_ctx->ref_count == 0) { + /* Release the callback functions */ +#if defined(EPC_BUILD) + RB_REMOVE(emm_common_data_map, + &emm_common_data_head.emm_common_data_root, + emm_common_data_ctx); +#endif + free(emm_common_data_ctx); + emm_common_data_ctx = NULL; + } + } +} +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.h b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.h new file mode 100644 index 0000000000..33705285d8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmCommon.h @@ -0,0 +1,84 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmCommon.h + +Version 0.1 + +Date 2013/04/19 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines callback functions executed within EMM common procedures + by the Non-Access Stratum running at the network side. + + Following EMM common procedures can always be initiated by the + network whilst a NAS signalling connection exists: + + GUTI reallocation + authentication + security mode control + identification + EMM information + +*****************************************************************************/ +#ifndef __EMM_COMMON_H__ +#define __EMM_COMMON_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Type of EMM procedure callback functions + * ---------------------------------------- + * EMM procedure to be executed under certain conditions, when an EMM common + * procedure has been initiated by the ongoing EMM procedure. + * - The EMM common procedure successfully completed + * - The EMM common procedure failed or is rejected + * - Lower layer failure occured before the EMM common procedure completion + */ +typedef int (*emm_common_success_callback_t)(void*); +typedef int (*emm_common_reject_callback_t) (void*); +typedef int (*emm_common_failure_callback_t)(void*); + +/* + * Type of EMM common procedure callback function + * ---------------------------------------------- + * EMM common procedure to be executed when the ongoing EMM procedure is + * aborted. + */ +typedef int (*emm_common_abort_callback_t)(void*); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int emm_proc_common_initialize(unsigned int ueid, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure, + emm_common_abort_callback_t abort, + void* args); + +int emm_proc_common_success(unsigned int ueid); +int emm_proc_common_reject(unsigned int ueid); +int emm_proc_common_failure(unsigned int ueid); +int emm_proc_common_abort(unsigned int ueid); + +void* emm_proc_common_get_args(unsigned int ueid); + +#endif /* __EMM_COMMON_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/EmmStatusHdl.c b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmStatusHdl.c new file mode 100644 index 0000000000..d6f52223da --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/EmmStatusHdl.c @@ -0,0 +1,145 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source Emmstatus.c + +Version 0.1 + +Date 2013/06/26 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMM status procedure executed by the Non-Access + Stratum. + + The purpose of the sending of the EMM STATUS message is to + report at any time certain error conditions detected upon + receipt of EMM protocol data. The EMM STATUS message can be + sent by both the MME and the UE. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_cause.h" +#include "emmData.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_proc_status_ind() ** + ** ** + ** Description: Processes received EMM status message. ** + ** ** + ** 3GPP TS 24.301, section 5.7 ** + ** On receipt of an EMM STATUS message no state transition ** + ** and no specific action shall be taken. Local actions are ** + ** possible and are implementation dependent. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** emm_cause: Received EMM cause code ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_status_ind(unsigned int ueid, int emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO,"EMM-PROC - EMM status procedure requested (cause=%d)", + emm_cause); + + LOG_TRACE(DEBUG, "EMM-PROC - To be implemented"); + + /* TODO */ + rc = RETURNok; + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_status() ** + ** ** + ** Description: Initiates EMM status procedure. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** emm_cause: EMM cause code to be reported ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_status(unsigned int ueid, int emm_cause) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + + emm_security_context_t *sctx = NULL; + struct emm_data_context_s *ctx = NULL; + + LOG_TRACE(INFO,"EMM-PROC - EMM status procedure requested"); + + /* + * Notity EMM that EMM status indication has to be sent to lower layers + */ + emm_sap.primitive = EMMAS_STATUS_IND; + emm_sap.u.emm_as.u.status.emm_cause = emm_cause; + emm_sap.u.emm_as.u.status.ueid = ueid; + +#ifdef NAS_UE + emm_sap.u.emm_as.u.status.guti = _emm_data.guti; + sctx = _emm_data.security; +#endif +#ifdef NAS_MME + emm_sap.u.emm_as.u.status.guti = NULL; +# if defined(EPC_BUILD) + ctx = emm_data_context_get(&_emm_data, ueid); +# else + ctx = _emm_data.ctx[ueid]; +# endif + if (ctx) { + sctx = ctx->security; + } +#endif + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.status.sctx, sctx, + FALSE, TRUE); + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/Identification.c b/openair-cn/NAS/EURECOM-NAS/src/emm/Identification.c new file mode 100644 index 0000000000..c2ad0a5290 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/Identification.c @@ -0,0 +1,568 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source Identification.c + +Version 0.1 + +Date 2013/04/09 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the identification EMM procedure executed by the + Non-Access Stratum. + + The identification procedure is used by the network to request + a particular UE to provide specific identification parameters + (IMSI, IMEI). + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* String representation of the requested identity type */ +static const char* _emm_identity_type_str[] = { + "NOT AVAILABLE", "IMSI", "IMEI", "IMEISV", "TMSI" +}; + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the identification procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the identification procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _identification_t3470_handler(void*); + +/* + * Function executed whenever the ongoing EMM procedure that initiated + * the identification procedure is aborted or the maximum value of the + * retransmission timer counter is exceed + */ +static int _identification_abort(void*); + +/* + * Internal data used for identification procedure + */ +typedef struct { + unsigned int ueid; /* UE identifier */ +#define IDENTIFICATION_COUNTER_MAX 5 + unsigned int retransmission_count; /* Retransmission counter */ + emm_proc_identity_type_t type; /* Type of UE identity */ + int notify_failure; /* Indicates whether the identification + * procedure failure shall be notified + * to the ongoing EMM procedure */ +} identification_data_t; + +static int _identification_request(identification_data_t* data); +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Identification procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_identification_request() ** + ** ** + ** Description: Performs the MME requested identification procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.4.3 ** + ** Upon receiving the IDENTITY REQUEST message, the UE shall ** + ** send an IDENTITY RESPONSE message to the network. The ** + ** IDENTITY RESPONSE message shall contain the identifica- ** + ** tion parameters as requested by the network. ** + ** ** + ** Inputs: type: Type of the requested identity ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_identification_request(emm_proc_identity_type_t type) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + + LOG_TRACE(INFO, "EMM-PROC - Identification requested type = %s (%d)", + _emm_identity_type_str[type], type); + + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "EMM-PROC - Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + + emm_sap.u.emm_as.u.security.identType = EMM_IDENT_TYPE_NOT_AVAILABLE; + + switch (type) + { + case EMM_IDENT_TYPE_IMSI: + /* International Mobile Subscriber Identity is requested */ + if (_emm_data.imsi) { + emm_sap.u.emm_as.u.security.identType = EMM_IDENT_TYPE_IMSI; + emm_sap.u.emm_as.u.security.imsi = _emm_data.imsi; + } + break; + + case EMM_IDENT_TYPE_IMEI: + /* International Mobile Equipment Identity is requested */ + if (_emm_data.imei) { + emm_sap.u.emm_as.u.security.identType = EMM_IDENT_TYPE_IMEI; + emm_sap.u.emm_as.u.security.imei = _emm_data.imei; + } + break; + + case EMM_IDENT_TYPE_TMSI: + /* Temporary Mobile Subscriber Identity is requested */ + if (_emm_data.guti) { + emm_sap.u.emm_as.u.security.identType = EMM_IDENT_TYPE_TMSI; + emm_sap.u.emm_as.u.security.tmsi = _emm_data.guti->m_tmsi; + } + break; + + default: + /* Other identities are not available */ + break; + } + + /* + * Notify EMM-AS SAP that Identity Response message has to be sent + * to the MME + */ + emm_sap.primitive = EMMAS_SECURITY_RES; + emm_sap.u.emm_as.u.security.guti = _emm_data.guti; + emm_sap.u.emm_as.u.security.ueid = 0; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_IDENT; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + _emm_data.security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Identification procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_proc_identification() ** + ** ** + ** Description: Initiates an identification procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.4.2 ** + ** The network initiates the identification procedure by ** + ** sending an IDENTITY REQUEST message to the UE and star- ** + ** ting the timer T3470. The IDENTITY REQUEST message speci- ** + ** fies the requested identification parameters in the Iden- ** + ** tity type information element. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** type: Type of the requested identity ** + ** success: Callback function executed when the identi-** + ** fication procedure successfully completes ** + ** reject: Callback function executed when the identi-** + ** fication procedure fails or is rejected ** + ** failure: Callback function executed whener a lower ** + ** layer failure occured before the identifi- ** + ** cation procedure comnpletes ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_identification(unsigned int ueid, + emm_data_context_t *emm_ctx, + emm_proc_identity_type_t type, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMM-PROC - Initiate identification type = %s (%d)", + _emm_identity_type_str[type], type); + + /* Allocate parameters of the retransmission timer callback */ + identification_data_t* data = + (identification_data_t*)malloc(sizeof(identification_data_t)); + + if (data != NULL) { + /* Setup ongoing EMM procedure callback functions */ + rc = emm_proc_common_initialize(ueid, success, reject, failure, + _identification_abort, data); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "Failed to initialize EMM callback functions"); + free(data); + LOG_FUNC_RETURN (RETURNerror); + } + /* Set the UE identifier */ + data->ueid = ueid; + /* Reset the retransmission counter */ + data->retransmission_count = 0; + /* Set the type of the requested identity */ + data->type = type; + /* Set the failure notification indicator */ + data->notify_failure = FALSE; + /* Send identity request message to the UE */ + rc = _identification_request(data); + if (rc != RETURNerror) { + /* + * Notify EMM that common procedure has been initiated + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REQ; + emm_sap.u.emm_reg.ueid = ueid; + emm_sap.u.emm_reg.ctx = emm_ctx; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_identification_complete() ** + ** ** + ** Description: Performs the identification completion procedure executed ** + ** by the network. ** + ** ** + ** 3GPP TS 24.301, section 5.4.4.4 ** + ** Upon receiving the IDENTITY RESPONSE message, the MME ** + ** shall stop timer T3470. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** imsi: The IMSI received from the UE ** + ** imei: The IMEI received from the UE ** + ** tmsi: The TMSI received from the UE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data, T3470 ** + ** ** + ***************************************************************************/ +int emm_proc_identification_complete(unsigned int ueid, const imsi_t* imsi, + const imei_t* imei, UInt32_t* tmsi) +{ + int rc = RETURNerror; + emm_sap_t emm_sap; + + emm_data_context_t* emm_ctx = NULL; + + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMM-PROC - Identification complete (ueid=%u)", ueid); + + /* Stop timer T3470 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3470 (%d)", T3470.id); + T3470.id = nas_timer_stop(T3470.id); + + /* Release retransmission timer paramaters */ + identification_data_t* data = + (identification_data_t*)(emm_proc_common_get_args(ueid)); + if (data) free(data); + + /* Get the UE context */ +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_ctx) { + if (imsi) { + /* Update the IMSI */ + if (emm_ctx->imsi == NULL) { + emm_ctx->imsi = (imsi_t*)malloc(sizeof(imsi_t)); + } + if (emm_ctx->imsi) { + memcpy(emm_ctx->imsi, imsi, sizeof(imsi_t)); + } + } + else if (imei) { + /* Update the IMEI */ + if (emm_ctx->imei == NULL) { + emm_ctx->imei = (imei_t*)malloc(sizeof(imei_t)); + } + if (emm_ctx->imei) { + memcpy(emm_ctx->imei, imei, sizeof(imei_t)); + } + } + else if (tmsi) { + /* Update the GUTI */ + if (emm_ctx->guti == NULL) { + emm_ctx->guti = (GUTI_t*)malloc(sizeof(GUTI_t)); + } + if (emm_ctx->guti) { + memcpy(&emm_ctx->guti->gummei, + &_emm_data.conf.gummei, sizeof(gummei_t)); + emm_ctx->guti->m_tmsi = *tmsi; + } + } + /* + * Notify EMM that the identification procedure successfully completed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_CNF; + emm_sap.u.emm_reg.ueid = ueid; + emm_sap.u.emm_reg.u.common.is_attached = emm_ctx->is_attached; + } + else { + LOG_TRACE(ERROR, "EMM-PROC - No EMM context exists"); + /* + * Notify EMM that the identification procedure failed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + } + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_MME +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _identification_t3470_handler() ** + ** ** + ** Description: T3470 timeout handler ** + ** Upon T3470 timer expiration, the identification request ** + ** message is retransmitted and the timer restarted. When ** + ** retransmission counter is exceed, the MME shall abort the ** + ** identification procedure and any ongoing EMM procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.4.6, case b ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _identification_t3470_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + identification_data_t* data = (identification_data_t*)(args); + + /* Increment the retransmission counter */ + data->retransmission_count += 1; + + LOG_TRACE(WARNING, "EMM-PROC - T3470 timer expired, retransmission " + "counter = %d", data->retransmission_count); + + if (data->retransmission_count < IDENTIFICATION_COUNTER_MAX) { + /* Send identity request message to the UE */ + rc = _identification_request(data); + } + else { + /* Set the failure notification indicator */ + data->notify_failure = TRUE; + /* Abort the identification procedure */ + rc = _identification_abort(data); + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _identification_request() ** + ** ** + ** Description: Sends IDENTITY REQUEST message and start timer T3470. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: T3470 ** + ** ** + ***************************************************************************/ +int _identification_request(identification_data_t* data) +{ + emm_sap_t emm_sap; + int rc; + + struct emm_data_context_s *emm_ctx = NULL; + + LOG_FUNC_IN; + + /* + * Notify EMM-AS SAP that Identity Request message has to be sent + * to the UE + */ + emm_sap.primitive = EMMAS_SECURITY_REQ; + emm_sap.u.emm_as.u.security.guti = NULL; + emm_sap.u.emm_as.u.security.ueid = data->ueid; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_IDENT; + emm_sap.u.emm_as.u.security.identType = data->type; + +#if defined(EPC_BUILD) + if (data->ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, data->ueid); + } +#else + if (data->ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[data->ueid]; + } +#endif + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + emm_ctx->security, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + if (T3470.id != NAS_TIMER_INACTIVE_ID) { + /* Re-start T3470 timer */ + T3470.id = nas_timer_restart(T3470.id); + } else { + /* Start T3470 timer */ + T3470.id = nas_timer_start(T3470.sec, _identification_t3470_handler, + data); + } + LOG_TRACE(INFO,"EMM-PROC - Timer T3470 (%d) expires in %ld seconds", + T3470.id, T3470.sec); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _identification_abort() ** + ** ** + ** Description: Aborts the identification procedure currently in progress ** + ** ** + ** Inputs: args: Identification data to be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: T3470 ** + ** ** + ***************************************************************************/ +static int _identification_abort(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + identification_data_t* data = (identification_data_t*)(args); + + if (data) + { + unsigned int ueid = data->ueid; + int notify_failure = data->notify_failure; + + LOG_TRACE(WARNING, "EMM-PROC - Abort identification procedure " + "(ueid=%u)", ueid); + + /* Stop timer T3470 */ + if (T3470.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3470 (%d)", T3470.id); + T3470.id = nas_timer_stop(T3470.id); + } + /* Release retransmission timer paramaters */ + free(data); + + /* + * Notify EMM that the identification procedure failed + */ + if (notify_failure) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } else { + rc = RETURNok; + } + } + + LOG_FUNC_RETURN(rc); +} + +#endif // NAS_MME + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.c b/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.c new file mode 100644 index 0000000000..63ce97bc7e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.c @@ -0,0 +1,1137 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source IdleMode.c + +Version 0.1 + +Date 2012/10/18 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines EMM procedures executed by the Non-Access Stratum + when the UE is in idle mode. + + When a UE is switched on, a Public Land Mobile Network is + selected and the UE searches for a suitable cell of this PLMN + to camp on. The UE will, if necessary, register its presence + in the registration area of the chosen cell and as outcome of + a successful Location Registration the selected PLMN becomes + the registered PLMN. + + If the UE loses coverage of the registered PLMN, either a new + PLMN is selected automatically (automatic mode), or an indi- + cation of which PLMNs are available is given to the user, so + that a manual selection can be made (manual mode). + + If the UE is unable to find a suitable cell to camp on, or + the USIM is not inserted, or if the location registration + failed under certain conditions, it attempts to camp on a + cell irrespective of the PLMN identity, and enters a "limited + service" state in which it can only attempt to make emergency + calls. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_proc.h" +#include "nas_log.h" + +#include "emm_sap.h" + +#include "IdleMode.h" +#include "emmData.h" + +#include <assert.h> +#include <stdio.h> // sprintf +#include <string.h> // strlen, strncpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static int _IdleMode_plmn_str(char* plmn_str, const plmn_t* plmn); +static int _IldlMode_get_opnn_id(const plmn_t* plmn); +static int _IdleMode_get_suitable_cell(int index); + +/* + * A list of PLMN identities in priority order is maintained locally + * to perform the PLMN selection procedure. + * + * In automatic mode of operation, this list is used for PLMN selection when + * the UE is switched on, or upon recovery from lack of coverage, or when the + * user requests the UE to initiate PLMN reselection, and registration. + * In manual mode of operation, this list is displayed to the user that may + * select an available PLMN and initiate registration. + * + * The list may contain PLMN identifiers in the following order: + * - The last registered PLMN or each equivalent PLMN present in the list of + * "equivalent PLMNs" (EPLMN_MAX), when UE is switched on or following + * recovery from lack of coverage; + * - The highest priority PLMN in the list of "equivalent HPLMNs" or the + * HPLMN derived from the IMSI (1) + * - Each PLMN/access technology combination in the "User Controlled PLMN + * Selector with Access Technology" (PLMN_MAX) + * - Each PLMN/access technology combination in the "Operator Controlled PLMN + * Selector with Access Technology" (OPLMN_MAX) + * - Other PLMN/access technology combinations with received high quality + * signal in random order (TODO) + * - Other PLMN/access technology combinations in order of decreasing signal + * quality (TODO) + * - The last selected PLMN again (1) + */ +static struct { + int n_plmns; +#define EMM_PLMN_LIST_SIZE (EMM_DATA_EPLMN_MAX + EMM_DATA_PLMN_MAX + \ + EMM_DATA_OPLMN_MAX + 2) + plmn_t* plmn[EMM_PLMN_LIST_SIZE]; + int index; /* Index of the PLMN for which selection is ongoing */ + int hplmn; /* Index of the home PLMN or the highest priority + * equivalent home PLMN */ + int fplmn; /* Index of the first forbidden PLMN */ + int splmn; /* Index of the currently selected PLMN */ + int rplmn; /* Index of the currently registered PLMN */ + struct plmn_param_t { + char fullname[NET_FORMAT_LONG_SIZE+1]; /* PLMN full identifier */ + char shortname[NET_FORMAT_SHORT_SIZE+1]; /* PLMN short identifier */ + char num[NET_FORMAT_NUM_SIZE+1]; /* PLMN numeric identifier */ + int stat; /* Indication of the PLMN availability */ + int tac; /* Location/Tracking Area Code */ + int ci; /* Serving cell identifier */ + int rat; /* Radio Access Technology supported by the serving cell */ + } param[EMM_PLMN_LIST_SIZE]; +} _emm_plmn_list; + +/* Callback executed whenever a network indication is received */ +static IdleMode_callback_t _emm_indication_notify; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: IdleMode_initialize() ** + ** ** + ** Description: Initializes EMM internal data used when the UE operates ** + ** in idle mode ** + ** ** + ** Inputs: cb: The function to executed whenever a net- ** + ** work indication is received ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_plmn_list, _emm_indication_notify ** + ** ** + ***************************************************************************/ +void IdleMode_initialize(IdleMode_callback_t cb) +{ + /* Initialize the list of available PLMNs */ + _emm_plmn_list.n_plmns = 0; + _emm_plmn_list.index = 0; + _emm_plmn_list.hplmn = -1; + _emm_plmn_list.fplmn = -1; + _emm_plmn_list.splmn = -1; + _emm_plmn_list.rplmn = -1; + + /* Initialize the network notification handler */ + _emm_indication_notify = *cb; + + /* Initialize EMM Service Access Point */ + emm_sap_initialize(); +} + +/* + *--------------------------------------------------------------------------- + * Functions used to get information from the local list of available PLMNs + *--------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_nb_plmns() ** + ** ** + ** Description: Get the number of available PLMNs in the ordered list. ** + ** ** + ** Inputs: None ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The number of PLMNs in the ordered list of ** + ** available PLMNs ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_nb_plmns(void) +{ + return _emm_plmn_list.n_plmns; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_hplmn_index() ** + ** ** + ** Description: Get the index of the Home PLMN or the highest priority ** + ** Equivalent HPLMN in the ordered list of available PLMNs. ** + ** ** + ** Inputs: None ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the HPLMN or the first EHPLMN ** + ** in the list ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_hplmn_index(void) +{ + return _emm_plmn_list.hplmn; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_rplmn_index() ** + ** ** + ** Description: Get the index of the registered PLMN in the ordered list ** + ** of available PLMNs. ** + ** ** + ** Inputs: None ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the registered PLMN in the ** + ** list ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_rplmn_index(void) +{ + return _emm_plmn_list.rplmn; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_splmn_index() ** + ** ** + ** Description: Get the index of the selected PLMN in the ordered list of ** + ** available PLMNs. ** + ** ** + ** Inputs: None ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the selected PLMN in the list ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_splmn_index(void) +{ + return _emm_plmn_list.splmn; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_update_plmn_list() ** + ** ** + ** Description: Updates the string representation of the list of opera- ** + ** tors present in the network ** + ** ** + ** Inputs: i: Index of the first operator to update ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The size of the list in bytes ** + ** Others: _emm_data.plist ** + ** ** + ***************************************************************************/ +int IdleMode_update_plmn_list(int i) +{ + int offset = 0; + int n = 1; + + while ( (i < _emm_plmn_list.n_plmns) && (offset < EMM_DATA_BUFFER_SIZE) ) + { + struct plmn_param_t* plmn = &(_emm_plmn_list.param[i++]); + if (n++ > 1) { + offset += snprintf(_emm_data.plist.buffer + offset, + EMM_DATA_BUFFER_SIZE - offset, ","); + } + offset += snprintf(_emm_data.plist.buffer + offset, + EMM_DATA_BUFFER_SIZE - offset, "(%d,%s,%s,%s", + plmn->stat, plmn->fullname, + plmn->shortname, plmn->num); + if (plmn->rat != NET_ACCESS_UNAVAILABLE) { + offset += snprintf(_emm_data.plist.buffer + offset, + EMM_DATA_BUFFER_SIZE - offset, ",%d", + plmn->rat); + } + offset += snprintf(_emm_data.plist.buffer + offset, + EMM_DATA_BUFFER_SIZE - offset, ")"); + } + + return (offset); +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_fullname() ** + ** ** + ** Description: Get the full name of the PLMN at the given index in the ** + ** ordered list of available PLMNs. ** + ** ** + ** Inputs: plmn: The PLMN of which the name is queried ** + ** index: The index of the PLMN in the ordered list ** + ** of available PLMNs ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: size: The length of the PLMN's name ** + ** Return: A pointer to the full name of the PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* IdleMode_get_plmn_fullname(const plmn_t* plmn, int index, size_t* len) +{ + if (index < _emm_plmn_list.n_plmns) { + assert( PLMNS_ARE_EQUAL(*plmn, *_emm_plmn_list.plmn[index]) ); + *len = strlen(_emm_plmn_list.param[index].fullname); + return _emm_plmn_list.param[index].fullname; + } + return NULL; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_shortname() ** + ** ** + ** Description: Get the short name of the PLMN at the given index in the ** + ** ordered list of available PLMNs. ** + ** ** + ** Inputs: plmn: The PLMN of which the name is queried ** + ** index: The index of the PLMN in the ordered list ** + ** of available PLMNs ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: size: The length of the PLMN's name ** + ** Return: A pointer to the short name of the PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* IdleMode_get_plmn_shortname(const plmn_t* plmn, int index, size_t* len) +{ + if (index < _emm_plmn_list.n_plmns) { + assert( PLMNS_ARE_EQUAL(*plmn, *_emm_plmn_list.plmn[index]) ); + *len = strlen(_emm_plmn_list.param[index].shortname); + return _emm_plmn_list.param[index].shortname; + } + return NULL; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_id() ** + ** ** + ** Description: Get the numeric identifier of the PLMN at the given index ** + ** in the ordered list of available PLMNs. ** + ** ** + ** Inputs: plmn: The PLMN of which the name is queried ** + ** index: The index of the PLMN in the ordered list ** + ** of available PLMNs ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: size: The length of the PLMN's name ** + ** Return: A pointer to the numeric identifier of the ** + ** PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* IdleMode_get_plmn_id(const plmn_t* plmn, int index, size_t* len) +{ + if (index < _emm_plmn_list.n_plmns) { + assert( PLMNS_ARE_EQUAL(*plmn, *_emm_plmn_list.plmn[index]) ); + *len = strlen(_emm_plmn_list.param[index].num); + return _emm_plmn_list.param[index].num; + } + return NULL; +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_fullname_index() ** + ** ** + ** Description: Search the list of available PLMNs for the index of the ** + ** PLMN identifier given by the specified fullname ** + ** ** + ** Inputs: plmn: The full name of the PLMN ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the PLMN, if found in the ** + ** list of available PLMNs; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_plmn_fullname_index(const char* plmn) +{ + /* Get the index of the PLMN identifier with specified full name */ + for (int index = 0; index < _emm_plmn_list.n_plmns; index++) + { + if ( strncmp(plmn, _emm_plmn_list.param[index].fullname, + NET_FORMAT_LONG_SIZE) != 0 ) { + continue; + } + return (index); + } + return (-1); +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_shortname_index() ** + ** ** + ** Description: Search the list of available PLMNs for the index of the ** + ** PLMN identifier given by the specified shortname ** + ** ** + ** Inputs: plmn: The short name of the PLMN ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the PLMN, if found in the ** + ** list of available PLMNs; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_plmn_shortname_index(const char* plmn) +{ + /* Get the index of the PLMN identifier with specified short name */ + for (int index = 0; index < _emm_plmn_list.n_plmns; index++) + { + if ( !strncmp(plmn, _emm_plmn_list.param[index].shortname, + NET_FORMAT_SHORT_SIZE) ) { + continue; + } + return (index); + } + return (-1); +} + +/**************************************************************************** + ** ** + ** Name: IdleMode_get_plmn_id_index() ** + ** ** + ** Description: Search the list of available PLMNs for the index of the ** + ** PLMN identifier given by the specified numeric identifier ** + ** ** + ** Inputs: plmn: The numeric identifier of the PLMN ** + ** Others: _emm_plmn_list ** + ** ** + ** Outputs: None ** + ** Return: The index of the PLMN, if found in the ** + ** list of available PLMNs; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int IdleMode_get_plmn_id_index(const char* plmn) +{ + /* Get the index of the PLMN identifier with specified numeric identifier */ + for (int index = 0; index < _emm_plmn_list.n_plmns; index++) + { + if ( !strncmp(plmn, _emm_plmn_list.param[index].num, + NET_FORMAT_LONG_SIZE) ) { + continue; + } + return (index); + } + return (-1); +} + +/* + *--------------------------------------------------------------------------- + * Idle mode EMM procedures + *--------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: emm_proc_initialize() ** + ** ** + ** Description: Initialize the ordered list of available PLMNs candidate ** + ** to PLMN selection procedure. ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_plmn_list ** + ** ** + ***************************************************************************/ +int emm_proc_initialize(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + if (!_emm_data.usim_is_valid) { + /* The USIM application is not present or not valid */ + LOG_TRACE(WARNING, "EMM-IDLE - USIM is not valid"); + emm_sap.primitive = EMMREG_NO_IMSI; + } + else + { + /* The highest priority is given to either the "equivalent PLMNs" + * if available, or the last registered PLMN */ + if (_emm_data.nvdata.eplmn.n_plmns > 0) { + for (int i=0; i < _emm_data.nvdata.eplmn.n_plmns; i++) { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = + &_emm_data.nvdata.eplmn.plmn[i]; + } + } + else if ( PLMN_IS_VALID(_emm_data.nvdata.rplmn) ) { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = + &_emm_data.nvdata.rplmn; + } + + /* Update the index of the HPLMN or EHPLM of highest priority. + * When switched on, the UE will try to automatically register + * to each previous PLMN within the ordered list of available + * PLMNs regardless of the network selection mode of operation */ + _emm_plmn_list.hplmn = _emm_plmn_list.n_plmns; + + /* Add the highest priority PLMN in the list of "equivalent HPLMNs" + if present and not empty, or the HPLMN derived from the IMSI */ + if (_emm_data.ehplmn.n_plmns > 0) { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = + &_emm_data.ehplmn.plmn[0]; + } + else { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = &_emm_data.hplmn; + } + + /* Each PLMN/access technology combination in the "User + * Controlled PLMN Selector with Access Technology" */ + for (int i=0; i < _emm_data.plmn.n_plmns; i++) { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = + &_emm_data.plmn.plmn[i]; + } + + /* Each PLMN/access technology combination in the "Operator + * Controlled PLMN Selector with Access Technology" */ + for (int i=0; i < _emm_data.oplmn.n_plmns; i++) { + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns++] = + &_emm_data.oplmn.plmn[i]; + } + + /* Other PLMN/access technology combinations with received + * high quality signal in random order */ + + /* Other PLMN/access technology combinations in order of + * decreasing signal quality */ + + /* TODO: Schedule periodic network selection attemps (hpplmn timer) */ + + /* Initialize the PLMNs' parameters */ + for (int i=0; i < _emm_plmn_list.n_plmns; i++) { + struct plmn_param_t* plmn = &(_emm_plmn_list.param[i]); + int id = _IldlMode_get_opnn_id(_emm_plmn_list.plmn[i]); + if (id < 0) { + plmn->fullname[0] = '\0'; + plmn->shortname[0] = '\0'; + } else { + strncpy(plmn->fullname, _emm_data.opnn[id].fullname, + NET_FORMAT_LONG_SIZE); + strncpy(plmn->shortname, _emm_data.opnn[id].shortname, + NET_FORMAT_SHORT_SIZE); + } + (void)_IdleMode_plmn_str(plmn->num, _emm_plmn_list.plmn[i]); + plmn->stat = NET_OPER_UNKNOWN; + plmn->tac = 0; + plmn->ci = 0; + plmn->rat = NET_ACCESS_UNAVAILABLE; + } + + LOG_TRACE(INFO, "EMM-IDLE - %d PLMNs available for network selection", + _emm_plmn_list.n_plmns); + + /* Notify EMM that PLMN selection procedure has to be executed */ + emm_sap.primitive = EMMREG_REGISTER_REQ; + emm_sap.u.emm_reg.u.regist.index = 0; + } + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); + + /* TODO: Update the list of PLMNs upon receiving AS system information */ +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_plmn_selection() ** + ** ** + ** Description: Performs the network selection procedure when the UE is ** + ** swicthed on. ** + ** ** + ** The MS shall select the registered PLMN or equivalent ** + ** PLMN (if it is available) using all access technologies ** + ** that the MS is capable. ** + ** If there is no registered PLMN, or if registration is ** + ** not possible due to the PLMN being unavailable or regis- ** + ** tration failure, the MS performs the automatic or the ma- ** + ** nual procedure depending on its PLMN selection operating ** + ** mode. ** + ** ** + ** Inputs: None ** + ** Others: _emm_plmn_list, _emm_data ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_plmn_list.index ** + ** ** + ***************************************************************************/ +int emm_proc_plmn_selection(int index) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if (_emm_data.plmn_mode != EMM_DATA_PLMN_AUTO) { + /* + * Manual or manual/automatic mode of operation + * -------------------------------------------- + */ + if (index >= _emm_plmn_list.hplmn) { + /* + * Selection of the last registered or equivalent PLMNs failed + */ + if (_emm_data.plmn_index < 0) { + /* + * The user did not select any PLMN yet; display the ordered + * list of available PLMNs to the user + */ + index = -1; + rc = emm_proc_network_notify(_emm_plmn_list.hplmn); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-IDLE - Failed to notify " + "network list update"); + } + } + else { + /* + * Try to register to the PLMN manually selected by the user + */ + index = _emm_data.plmn_index; + } + } + } + + if ( !(index < 0) ) { + /* + * Search for a suitable cell of the currently selected PLMN: + * It can be the last registered or one of the equivalent PLMNs + * if available, or the PLMN selected by the user in manual mode, + * or any other PLMN in the ordered list of available PLMNs in + * automatic mode. + */ + _emm_plmn_list.index = index; + rc = _IdleMode_get_suitable_cell(index); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_plmn_end() ** + ** ** + ** Description: Completes the network selection procedure or triggers a ** + ** new one until a suitable or acceptable cell of the chosen ** + ** PLMN is found. ** + ** ** + ** If a suitable cell of the selected PLMN has been found, ** + ** that cell is chosen to camp on and provide available ser- ** + ** vices, and tunes to its control channel. ** + ** The MS will then register its presence in the registra- ** + ** tion area of the chosen cell, if it is capable of servi- ** + ** ces which require registration. As outcome of a success- ** + ** ful Location Registration the selected PLMN becomes the ** + ** registered PLMN. ** + ** ** + ** When no suitable cell can be found, the MS is unable to ** + ** obtain normal service from a PLMN. Then the MS attempts ** + ** to camp on an acceptable cell, irrespective of its PLMN ** + ** identity, so that only emergency calls can be made. ** + ** ** + ** Inputs: found: TRUE if a suitable cell of the chosen ** + ** PLMN has been found; FALSE otherwise. ** + ** tac: The code of the location/tracking area the ** + ** chosen PLMN belongs to ** + ** ci: The identifier of the cell ** + ** rat: The radio access technology supported by ** + ** the cell ** + ** Others: _emm_plmn_list, _emm_data ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_plmn_list, _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_plmn_selection_end(int found, tac_t tac, ci_t ci, AcT_t rat) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc = RETURNerror; + int index = _emm_plmn_list.index; + int select_next_plmn = FALSE; + + LOG_TRACE(INFO, "EMM-IDLE - %s cell found for PLMN %d in %s mode", + (found)? "One" : "No", index, + (_emm_data.plmn_mode == EMM_DATA_PLMN_AUTO)? "Automatic" : + (_emm_data.plmn_mode == EMM_DATA_PLMN_MANUAL)? "Manual" : + "Automatic/manual"); + + if (found) + { + int is_forbidden = FALSE; + + /* Select the PLMN of which a suitable cell has been found */ + _emm_data.splmn = *_emm_plmn_list.plmn[index]; + + /* Update the selected PLMN's parameters */ + _emm_plmn_list.param[index].tac = tac; + _emm_plmn_list.param[index].ci = ci; + _emm_plmn_list.param[index].rat = rat; + + /* Update the location data and notify EMM that data have changed */ + rc = emm_proc_location_notify(tac, ci , rat); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-IDLE - Failed to notify location update"); + } + + if (_emm_data.plmn_mode == EMM_DATA_PLMN_AUTO) { + /* + * Automatic mode of operation + * --------------------------- + */ + int i; + + /* Check if the selected PLMN is in the forbidden list */ + for (i = 0; i < _emm_data.fplmn.n_plmns; i++) { + if (PLMNS_ARE_EQUAL(_emm_data.splmn, _emm_data.fplmn.plmn[i])) { + is_forbidden = TRUE; + break; + } + } + if (!is_forbidden) { + for (i = 0; i < _emm_data.fplmn_gprs.n_plmns; i++) { + if (PLMNS_ARE_EQUAL(_emm_data.splmn, + _emm_data.fplmn_gprs.plmn[i])) { + is_forbidden = TRUE; + break; + } + } + } + /* Check if the selected PLMN belongs to a forbidden + * tracking area */ + tai_t tai; + tai.plmn = _emm_data.splmn; + tai.tac = tac; + if (!is_forbidden) { + for (i = 0; i < _emm_data.ftai.n_tais; i++) { + if (TAIS_ARE_EQUAL(tai, _emm_data.ftai.tai[i])) { + is_forbidden = TRUE; + break; + } + } + } + if (!is_forbidden) { + for (i = 0; i < _emm_data.ftai_roaming.n_tais; i++) { + if (TAIS_ARE_EQUAL(tai, _emm_data.ftai_roaming.tai[i])) { + is_forbidden = TRUE; + break; + } + } + } + } + + if (is_forbidden) { + /* The selected cell is known not to be able to provide normal + * service */ + LOG_TRACE(INFO, "EMM-IDLE - UE may camp on this acceptable cell ", + "for limited services"); + + /* Save the index of the first forbidden PLMN */ + if (_emm_plmn_list.fplmn < 0) { + _emm_plmn_list.fplmn = index; + } + _emm_plmn_list.param[index].stat = NET_OPER_FORBIDDEN; + } + else { + /* A suitable cell has been found and the PLMN or tracking area + * is not in the forbidden list */ + LOG_TRACE(INFO, "EMM-IDLE - UE may camp on this suitable cell ", + "for normal services"); + _emm_plmn_list.fplmn = -1; + _emm_plmn_list.param[index].stat = NET_OPER_CURRENT; + emm_sap.primitive = EMMREG_REGISTER_CNF; + } + + /* Duplicate the new selected PLMN at the end of the ordered list */ + _emm_plmn_list.plmn[_emm_plmn_list.n_plmns] = &_emm_data.splmn; + } + + else if (_emm_data.plmn_mode == EMM_DATA_PLMN_AUTO) { + /* + * Automatic mode of operation + * --------------------------- + * No suitable cell of the chosen PLMN has been found; + * Try to select the next PLMN in the ordered list of available PLMNs + */ + index += 1; + select_next_plmn = TRUE; + + /* Bypass the previously selected PLMN */ + if (index == _emm_plmn_list.splmn) { + index += 1; + } + } + + else if (_emm_data.plmn_index < 0) { + /* + * Manual or manual/automatic mode of operation + * -------------------------------------------- + * Attempt to automatically find a suitable cell of the last + * registered or equivalent PLMNs is ongoing + */ + index += 1; + select_next_plmn = TRUE; + } + + else if (_emm_data.plmn_mode == EMM_DATA_PLMN_MANUAL) { + /* + * Manual mode of operation + * ------------------------ + * No suitable cell of the PLMN selected by the user has been found + */ + emm_sap.primitive = EMMREG_NO_CELL; + } + + else { + /* + * Manual/automatic mode of operation + * -------------------------------------------- + * Attempt to find a suitable cell of the PLMN selected by the user + * failed; Try to automatically select another PLMN + */ + _emm_data.plmn_mode = EMM_DATA_PLMN_AUTO; + index = _emm_plmn_list.hplmn; + select_next_plmn = TRUE; + } + + /* + * Force an attempt to register to the next PLMN + */ + if (select_next_plmn) { + int last_plmn_index = _emm_plmn_list.n_plmns; + if (_emm_plmn_list.splmn != -1) { + /* The last attempt was to register the previously selected PLMN */ + last_plmn_index += 1; + } + if (index < last_plmn_index) { + /* Try to select the next PLMN in the list of available PLMNs */ + _emm_plmn_list.index = index; + rc = emm_proc_plmn_selection(index); + } + else { + /* No suitable cell of any PLMN within the ordered list + * of available PLMNs has been found */ + select_next_plmn = FALSE; + emm_sap.primitive = EMMREG_NO_CELL; + } + } + + /* + * Or terminate the PLMN selection procedure + */ + if (!select_next_plmn) { + if (!(_emm_plmn_list.fplmn) < 0) { + /* There were one or more PLMNs which were available and allowable, + * but an LR failure made registration on those PLMNs unsuccessful + * or an entry in any of the forbidden area lists prevented a + * registration attempt; select the first such PLMN and enters a + * limited service state. */ + index = _emm_plmn_list.fplmn; + _emm_plmn_list.fplmn = -1; + emm_sap.primitive = EMMREG_REGISTER_REJ; + } + /* Update the availability indicator of the previously selected PLMN */ + if (_emm_plmn_list.splmn != -1) { + _emm_plmn_list.param[_emm_plmn_list.splmn].stat = NET_OPER_UNKNOWN; + } + /* Update the index of the new selected PLMN */ + if (emm_sap.primitive != EMMREG_NO_CELL) { + _emm_plmn_list.splmn = index; + } + else { + _emm_plmn_list.splmn = -1; + } + /* + * Notify EMM that PLMN selection procedure has completed + */ + rc = emm_sap_send(&emm_sap); + + if (_emm_plmn_list.splmn != -1) { + if (_emm_plmn_list.splmn == _emm_plmn_list.rplmn) { + /* The selected PLMN is the registered PLMN */ + _emm_data.is_rplmn = TRUE; + } + else if (_emm_plmn_list.splmn < _emm_plmn_list.hplmn) { + /* The selected PLMN is in the list of equivalent PLMNs */ + _emm_data.is_eplmn = TRUE; + } + /* + * Notify EMM that an attach procedure has to be initiated + * to register the presence of the UE to the selected PLMN + */ + emm_sap.primitive = EMMREG_ATTACH_INIT; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN (rc); +} + +/* + *--------------------------------------------------------------------------- + * Network indication handlers + *--------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: emm_proc_registration_notify() ** + ** ** + ** Description: Updates the current network registration status and noti- ** + ** fy the EMM main controller that network registration sta- ** + ** tus has changed. ** + ** ** + ** Inputs: status: The new network registraton status ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_registration_notify(Stat_t status) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + /* Update the network registration status */ + if (_emm_data.stat != status) { + _emm_data.stat = status; + /* Notify EMM that data has changed */ + rc = (*_emm_indication_notify)(1); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_location_notify() ** + ** ** + ** Description: Updates the current location information and notify the ** + ** EMM main controller that location area has changed. ** + ** ** + ** Inputs: tac: The code of the new location/tracking area ** + ** ci: The identifier of the new serving cell ** + ** rat: The Radio Access Technology supported by ** + ** the new serving cell ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_location_notify(tac_t tac, ci_t ci, AcT_t rat) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + /* Update the location information */ + if ( (_emm_data.tac != tac) || + (_emm_data.ci != ci) || + (_emm_data.rat != rat) ) + { + _emm_data.tac = tac; + _emm_data.ci = ci; + _emm_data.rat = rat; + /* Notify EMM that data has changed */ + rc = (*_emm_indication_notify)(0); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_network_notify() ** + ** ** + ** Description: Updates the string representation of the list of opera- ** + ** tors present in the network and notify the EMM main con- ** + ** troller that the list has to be displayed to the user ** + ** application. ** + ** ** + ** Inputs: index: Index of the first operator to update ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_proc_network_notify(int index) +{ + LOG_FUNC_IN; + + /* Update the list of operators present in the network */ + int size = IdleMode_update_plmn_list(index); + /* Notify EMM that data has changed */ + int rc = (*_emm_indication_notify)(size); + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _IdleMain_plmn_str() ** + ** ** + ** Description: Converts a PLMN identifier to a string representation in ** + ** the numeric format ** + ** ** + ** Inputs: plmn: The PLMN identifier to convert ** + ** Others: None ** + ** ** + ** Outputs: plmn_str: The PLMN identifier in numeric format ** + ** Return: The size in bytes of the string represen- ** + ** tation of the PLMN identifier ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _IdleMode_plmn_str(char* plmn_str, const plmn_t* plmn) +{ + char* p = plmn_str; + if (plmn == NULL) { + return 0; + } + + if (plmn->MCCdigit1 != 0x0F) sprintf(p++, "%u", plmn->MCCdigit1); + if (plmn->MCCdigit2 != 0x0F) sprintf(p++, "%u", plmn->MCCdigit2); + if (plmn->MCCdigit3 != 0x0F) sprintf(p++, "%u", plmn->MCCdigit3); + if (plmn->MNCdigit1 != 0x0F) sprintf(p++, "%u", plmn->MNCdigit1); + if (plmn->MNCdigit2 != 0x0F) sprintf(p++, "%u", plmn->MNCdigit2); + if (plmn->MNCdigit3 != 0x0F) sprintf(p++, "%u", plmn->MNCdigit3); + + return (p - plmn_str); +} + +/**************************************************************************** + ** ** + ** Name: _IldlMode_get_opnn_id() ** + ** ** + ** Description: Get the index of the specified PLMN in the list of opera- ** + ** tor network name records ** + ** ** + ** Inputs: plmn: The PLMN identifier ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The index of the PLMN if found in the list ** + ** of operator network name records; ** + ** -1 otherwise; ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _IldlMode_get_opnn_id(const plmn_t* plmn) +{ + for (int i = 0; i < _emm_data.n_opnns; i++) { + if (plmn->MCCdigit1 != _emm_data.opnn[i].plmn->MCCdigit1) continue; + if (plmn->MCCdigit2 != _emm_data.opnn[i].plmn->MCCdigit2) continue; + if (plmn->MCCdigit3 != _emm_data.opnn[i].plmn->MCCdigit3) continue; + if (plmn->MNCdigit1 != _emm_data.opnn[i].plmn->MNCdigit1) continue; + if (plmn->MNCdigit2 != _emm_data.opnn[i].plmn->MNCdigit2) continue; + if (plmn->MNCdigit3 != _emm_data.opnn[i].plmn->MNCdigit3) continue; + /* Found */ + return (i); + } + /* Not found */ + return (-1); +} + +/**************************************************************************** + ** ** + ** Name: _IdleMode_get_suitable_cell() ** + ** ** + ** Description: Query the Access Stratum to search for a suitable cell ** + ** that belongs to the selected PLMN. ** + ** ** + ** Inputs: index: Index of the selected PLMN in the ordered ** + ** list of available PLMNs ** + ** Others: _emm_plmn_list.plmn ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _IdleMode_get_suitable_cell(int index) +{ + emm_sap_t emm_sap; + const plmn_t* plmn = _emm_plmn_list.plmn[index]; + + LOG_TRACE(INFO, "EMM-IDLE - Trying to search a suitable cell " + "of PLMN %d in %s mode", index, + (_emm_data.plmn_mode == EMM_DATA_PLMN_AUTO)? "Automatic" : + (_emm_data.plmn_mode == EMM_DATA_PLMN_MANUAL)? "Manual" : + "Automatic/manual"); + /* + * Notify EMM-AS SAP that cell information related to the given + * PLMN are requested from the Access-Stratum + */ + emm_sap.primitive = EMMAS_CELL_INFO_REQ; + emm_sap.u.emm_as.u.cell_info.plmnIDs.n_plmns = 1; + emm_sap.u.emm_as.u.cell_info.plmnIDs.plmn[0] = *plmn; + if (_emm_data.plmn_rat != NET_ACCESS_UNAVAILABLE) { + emm_sap.u.emm_as.u.cell_info.rat = (1 << _emm_data.plmn_rat); + } else { + emm_sap.u.emm_as.u.cell_info.rat = NET_ACCESS_UNAVAILABLE; + } + + return emm_sap_send(&emm_sap); +} +#endif // NAS_UE + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.h b/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.h new file mode 100644 index 0000000000..db1a51f032 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/IdleMode.h @@ -0,0 +1,62 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source IdleMode.h + +Version 0.1 + +Date 2012/10/23 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the functions used to get information from the list + of available PLMNs locally maintained when the UE is in + idle mode. + +*****************************************************************************/ +#ifndef __IDLEMODE_H__ +#define __IDLEMODE_H__ + +#include "commonDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +typedef int (*IdleMode_callback_t) (int); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void IdleMode_initialize(IdleMode_callback_t cb); + +int IdleMode_get_nb_plmns(void); +int IdleMode_get_hplmn_index(void); +int IdleMode_get_rplmn_index(void); +int IdleMode_get_splmn_index(void); + +int IdleMode_update_plmn_list(int index); + +const char* IdleMode_get_plmn_fullname(const plmn_t* plmn, int index, size_t* len); +const char* IdleMode_get_plmn_shortname(const plmn_t* plmn, int index, size_t* len); +const char* IdleMode_get_plmn_id(const plmn_t* plmn, int index, size_t* len); + +int IdleMode_get_plmn_fullname_index(const char* plmn); +int IdleMode_get_plmn_shortname_index(const char* plmn); +int IdleMode_get_plmn_id_index(const char* plmn); + +#endif /* __IDLEMODE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.c b/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.c new file mode 100644 index 0000000000..7396e2bd57 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.c @@ -0,0 +1,478 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source LowerLayer.c + +Version 0.1 + +Date 2012/03/14 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines EMM procedures executed by the Non-Access Stratum + upon receiving notifications from lower layers so that data + transfer succeed or failed, or NAS signalling connection is + released, or ESM unit data has been received from under layer, + and to request ESM unit data transfer to under layer. + +*****************************************************************************/ + +#include "LowerLayer.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emmData.h" + +#include "emm_sap.h" +#include "esm_sap.h" + +#include <string.h> // memset + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * Data structure used to handle EMM procedures executed by the UE upon + * receiving lower layer notifications + */ +static struct { + lowerlayer_success_callback_t success; /* Successful data delivery */ + lowerlayer_failure_callback_t failure; /* Lower layer failure */ + lowerlayer_release_callback_t release; /* NAS signalling release */ + void* args; /* EMM procedure argument parameters */ +} _lowerlayer_data; +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Lower layer notification handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: lowerlayer_success() ** + ** ** + ** Description: Notify the EPS Mobility Management entity that data have ** + ** been successfully delivered to the network ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_success(unsigned int ueid) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + emm_sap.primitive = EMMREG_LOWERLAYER_SUCCESS; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: lowerlayer_failure() ** + ** ** + ** Description: Notify the EPS Mobility Management entity that lower la- ** + ** yers failed to deliver data to the network ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_failure(unsigned int ueid) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + emm_sap.primitive = EMMREG_LOWERLAYER_FAILURE; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: lowerlayer_establish() ** + ** ** + ** Description: Update the EPS connection management status upon recei- ** + ** ving indication so that the NAS signalling connection is ** + ** established ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_establish(void) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + /* Update the EPS Connection Management status */ + _emm_data.ecm_status = ECM_CONNECTED; +#endif + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: lowerlayer_release() ** + ** ** + ** Description: Notify the EPS Mobility Management entity that NAS signal-** + ** ling connection has been released ** + ** ** + ** Inputs: cause: Release cause ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_release(int cause) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + +#ifdef NAS_UE + /* Update the EPS Connection Management status */ + _emm_data.ecm_status = ECM_IDLE; +#endif + + emm_sap.primitive = EMMREG_LOWERLAYER_RELEASE; + emm_sap.u.emm_reg.ueid = 0; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: lowerlayer_data_ind() ** + ** ** + ** Description: Notify the EPS Session Management entity that data have ** + ** been received from lower layers ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** data: Data transfered from lower layers ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_data_ind(unsigned int ueid, const OctetString* data) +{ + LOG_FUNC_IN; + + esm_sap_t esm_sap; + int rc; + + esm_sap.primitive = ESM_UNITDATA_IND; + esm_sap.is_standalone = TRUE; + esm_sap.ueid = ueid; + esm_sap.recv = data; + rc = esm_sap_send(&esm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: lowerlayer_data_req() ** + ** ** + ** Description: Notify the EPS Mobility Management entity that data have ** + ** to be transfered to lower layers ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** data: Data to be transfered to lower layers ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int lowerlayer_data_req(unsigned int ueid, const OctetString* data) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + emm_security_context_t *sctx = NULL; + struct emm_data_context_s *ctx = NULL; + + emm_sap.primitive = EMMAS_DATA_REQ; +#ifdef NAS_UE + emm_sap.u.emm_as.u.data.guti = _emm_data.guti; + emm_sap.u.emm_as.u.data.ueid = 0; + sctx = _emm_data.security; +#endif +#ifdef NAS_MME + emm_sap.u.emm_as.u.data.guti = NULL; + emm_sap.u.emm_as.u.data.ueid = ueid; +# if defined(EPC_BUILD) + if (ueid > 0) { + ctx = emm_data_context_get(&_emm_data, ueid); + } +# else + if (ueid < EMM_DATA_NB_UE_MAX) { + ctx = _emm_data.ctx[ueid]; + } +# endif + if (ctx) { + sctx = ctx->security; + } +#endif + emm_sap.u.emm_as.u.data.NASinfo = 0; + emm_sap.u.emm_as.u.data.NASmsg.length = data->length; + emm_sap.u.emm_as.u.data.NASmsg.value = data->value; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, sctx, FALSE, TRUE); + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * EMM procedure handlers + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_lowerlayer_initialize() ** + ** ** + ** Description: Initialize EMM procedure handler ** + ** ** + ** Inputs: success: EMM procedure executed when data have been ** + ** successfully delivered by lower layers ** + ** failure: EMM procedure executed upon transmission ** + ** failure reported by lower layers ** + ** release: EMM procedure executed when lower layers ** + ** report that NAS signalling connection has ** + ** been released ** + ** args: EMM procedure argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _lowerlayer_data ** + ** ** + ***************************************************************************/ +int emm_proc_lowerlayer_initialize(lowerlayer_success_callback_t success, + lowerlayer_failure_callback_t failure, + lowerlayer_release_callback_t release, + void* args) +{ + LOG_FUNC_IN; + + _lowerlayer_data.success = success; + _lowerlayer_data.failure = failure; + _lowerlayer_data.release = release; + _lowerlayer_data.args = args; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_lowerlayer_success() ** + ** ** + ** Description: Handles EMM procedure to be executed upon receiving noti- ** + ** fication that data have been successfully delivered to ** + ** the network. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_lowerlayer_success(void) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + lowerlayer_success_callback_t emm_callback = _lowerlayer_data.success; + + if (emm_callback) { + rc = (*emm_callback)(_lowerlayer_data.args); + _lowerlayer_data.success = NULL; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_lowerlayer_failure() ** + ** ** + ** Description: Handles EMM procedure to be executed upon receiving noti- ** + ** fication that data failed to be delivered to the network. ** + ** ** + ** Inputs: is_initial: TRUE if the NAS message that failed to be ** + ** transfered is an initial NAS message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_lowerlayer_failure(int is_initial) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + lowerlayer_failure_callback_t emm_callback = _lowerlayer_data.failure; + + if (emm_callback) { + rc = (*emm_callback)(is_initial, _lowerlayer_data.args); + _lowerlayer_data.failure = NULL; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_lowerlayer_release() ** + ** ** + ** Description: Handles EMM procedure to be executed upon receiving noti- ** + ** fication that NAS signalling connection has been released ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_lowerlayer_release(void) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + lowerlayer_release_callback_t emm_callback = _lowerlayer_data.release; + + if (emm_callback) { + rc = (*emm_callback)(_lowerlayer_data.args); + _lowerlayer_data.release = NULL; + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/**************************************************************************** + ** ** + ** Name: emm_as_set_security_data() ** + ** ** + ** Description: Setup security data according to the given EPS security ** + ** context when data transfer to lower layers is requested ** + ** ** + ** Inputs: args: EPS security context currently in use ** + ** is_new: Indicates whether a new security context ** + ** has just been taken into use ** + ** is_ciphered: Indicates whether the NAS message has to ** + ** be sent ciphered ** + ** Others: None ** + ** ** + ** Outputs: data: EPS NAS security data to be setup ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void emm_as_set_security_data(emm_as_security_data_t* data, const void* args, + int is_new, int is_ciphered) +{ + LOG_FUNC_IN; + + const emm_security_context_t* context = (emm_security_context_t*)(args); + + memset(data, 0, sizeof(emm_as_security_data_t)); + + if ( context && (context->type != EMM_KSI_NOT_AVAILABLE) ) { + /* 3GPP TS 24.301, sections 5.4.3.3 and 5.4.3.4 + * Once a valid EPS security context exists and has been taken + * into use, UE and MME shall cipher and integrity protect all + * NAS signalling messages with the selected NAS ciphering and + * NAS integrity algorithms */ + data->is_new = is_new; + data->ksi = context->eksi; + data->sqn = context->ul_count.seq_num; + data->count = *(UInt32_t*)(&context->ul_count); + /* NAS integrity and cyphering keys may not be available if the + * current security context is a partial EPS security context + * and not a full native EPS security context */ + data->k_int = &context->knas_int; + if (is_ciphered) { + /* 3GPP TS 24.301, sections 4.4.5 + * When the UE establishes a new NAS signalling connection, + * it shall send initial NAS messages integrity protected + * and unciphered */ + /* 3GPP TS 24.301, section 5.4.3.2 + * The MME shall send the SECURITY MODE COMMAND message integrity + * protected and unciphered */ + data->k_enc = &context->knas_enc; + } + } + else { + /* No valid EPS security context exists */ + data->ksi = EMM_AS_NO_KEY_AVAILABLE; + } + + LOG_FUNC_OUT; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.h b/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.h new file mode 100644 index 0000000000..9aa715b932 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/LowerLayer.h @@ -0,0 +1,73 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source lowerlayer.h + +Version 0.1 + +Date 2013/06/19 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines EMM procedures executed by the Non-Access Stratum + upon receiving notifications from lower layers so that data + transfer succeed or failed, or NAS signalling connection is + released, or ESM unit data has been received from under layer, + and to request ESM unit data transfer to under layer. + +*****************************************************************************/ +#ifndef __LOWERLAYER_H__ +#define __LOWERLAYER_H__ + +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * Type of EMM procedure callback function executed whenever data are + * successfully delivered to the network + */ +typedef int (*lowerlayer_success_callback_t)(void*); + +/* + * Type of EMM procedure callback function executed when data are not + * delivered to the network because a lower layer failure occurred + */ +typedef int (*lowerlayer_failure_callback_t)(int, void*); + +/* + * Type of EMM procedure callback function executed when NAS signalling + * connection is released + */ +typedef int (*lowerlayer_release_callback_t)(void*); +#endif + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int lowerlayer_success(unsigned int ueid); +int lowerlayer_failure(unsigned int ueid); +int lowerlayer_establish(void); +int lowerlayer_release(int cause); + +int lowerlayer_data_ind(unsigned int ueid, const OctetString* data); +int lowerlayer_data_req(unsigned int ueid, const OctetString* data); + +#endif /* __LOWERLAYER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/Makefile b/openair-cn/NAS/EURECOM-NAS/src/emm/Makefile new file mode 100644 index 0000000000..555164031d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/Makefile @@ -0,0 +1,213 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(USIMAPIDIR) -I$(MMEAPIDIR) \ + -I$(EMMSAPDIR) -I$(ESMSAPDIR) -I$(EMMMSGDIR) + +all: $(OBJS) + @$(CD) $(EMMMSGDIR) && $(MAKE) + @$(CD) $(EMMSAPDIR) && $(MAKE) + +clean: + $(RM) $(OBJS) *.bak *~ + @$(CD) $(EMMSAPDIR) && $(MAKE) $@ + +veryclean: clean + @$(CD) $(EMMSAPDIR) && $(MAKE) $@ + @$(CD) $(EMMMSGDIR) && $(MAKE) $@ + $(RM) $(TARGET) + +%.o: %.c Makefile $(PROJDIR)/Makerules $(PROJDIR)/Makefile.inc + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +Attach.o: emm_proc.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +Attach.o: /usr/include/stdint.h /usr/include/features.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Attach.o: LowerLayer.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +Attach.o: emmData.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +Attach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +Attach.o: /usr/include/string.h /usr/include/xlocale.h /usr/include/stdlib.h +Attach.o: /usr/include/alloca.h +Authentication.o: emm_proc.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +Authentication.o: /usr/include/stdint.h /usr/include/features.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Authentication.o: LowerLayer.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +Authentication.o: emmData.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +Authentication.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/usim/usim_api.h +Authentication.o: /usr/include/stdlib.h /usr/include/alloca.h +Authentication.o: /usr/include/string.h /usr/include/xlocale.h +Detach.o: emm_proc.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +Detach.o: /usr/include/stdint.h /usr/include/features.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Detach.o: LowerLayer.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +Detach.o: emmData.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +Detach.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +Detach.o: /usr/include/stdlib.h /usr/include/alloca.h +emm_data_ctx.o: /usr/include/stdlib.h /usr/include/features.h +emm_data_ctx.o: /usr/include/alloca.h /usr/include/string.h +emm_data_ctx.o: /usr/include/xlocale.h +emm_main.o: emm_main.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +emm_main.o: /usr/include/stdint.h /usr/include/features.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +emm_main.o: emmData.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/memory.h +emm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/usim/usim_api.h +emm_main.o: IdleMode.h /usr/include/string.h /usr/include/xlocale.h +emm_main.o: /usr/include/stdio.h /usr/include/libio.h +emm_main.o: /usr/include/_G_config.h /usr/include/wchar.h +emm_main.o: /usr/include/stdlib.h /usr/include/alloca.h +EmmStatusHdl.o: emm_proc.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +EmmStatusHdl.o: /usr/include/stdint.h /usr/include/features.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EmmStatusHdl.o: LowerLayer.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +EmmStatusHdl.o: emmData.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +EmmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +Identification.o: emm_proc.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +Identification.o: /usr/include/stdint.h /usr/include/features.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Identification.o: LowerLayer.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +Identification.o: emmData.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +Identification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +Identification.o: /usr/include/stdlib.h /usr/include/alloca.h +Identification.o: /usr/include/string.h /usr/include/xlocale.h +IdleMode.o: emm_proc.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +IdleMode.o: /usr/include/stdint.h /usr/include/features.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +IdleMode.o: LowerLayer.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +IdleMode.o: IdleMode.h emmData.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +IdleMode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +IdleMode.o: /usr/include/assert.h /usr/include/stdio.h /usr/include/libio.h +IdleMode.o: /usr/include/_G_config.h /usr/include/wchar.h +IdleMode.o: /usr/include/xlocale.h /usr/include/string.h +LowerLayer.o: LowerLayer.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LowerLayer.o: /usr/include/stdint.h /usr/include/features.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LowerLayer.o: emmData.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +LowerLayer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +LowerLayer.o: /usr/include/string.h /usr/include/xlocale.h +SecurityModeControl.o: emm_proc.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +SecurityModeControl.o: /usr/include/stdint.h /usr/include/features.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +SecurityModeControl.o: LowerLayer.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +SecurityModeControl.o: emmData.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +SecurityModeControl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +SecurityModeControl.o: /usr/include/stdlib.h /usr/include/alloca.h +SecurityModeControl.o: /usr/include/string.h /usr/include/xlocale.h +ServiceRequestHdl.o: emm_proc.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +ServiceRequestHdl.o: /usr/include/stdint.h /usr/include/features.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ServiceRequestHdl.o: LowerLayer.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +ServiceRequestHdl.o: emmData.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +ServiceRequestHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +TrackingAreaUpdate.o: emm_proc.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +TrackingAreaUpdate.o: /usr/include/stdint.h /usr/include/features.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TrackingAreaUpdate.o: LowerLayer.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +TrackingAreaUpdate.o: emmData.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +TrackingAreaUpdate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/SecurityModeControl.c b/openair-cn/NAS/EURECOM-NAS/src/emm/SecurityModeControl.c new file mode 100644 index 0000000000..292b317ccd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/SecurityModeControl.c @@ -0,0 +1,953 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source SecurityModeControl.c + +Version 0.1 + +Date 2013/04/22 + +Product NAS stack + +Subsystem Template body file + +Author Frederic Maurel + +Description Defines the security mode control EMM procedure executed by the + Non-Access Stratum. + + The purpose of the NAS security mode control procedure is to + take an EPS security context into use, and initialise and start + NAS signalling security between the UE and the MME with the + corresponding EPS NAS keys and EPS security algorithms. + + Furthermore, the network may also initiate a SECURITY MODE COM- + MAND in order to change the NAS security algorithms for a cur- + rent EPS security context already in use. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" +#include "emm_cause.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the security mode control procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +static int _security_kdf(const OctetString* kasme, OctetString* key, + UInt8_t algo_dist, UInt8_t algo_id); + +static int _security_knas_enc(const OctetString* kasme, OctetString* knas_enc, UInt8_t eia); +static int _security_knas_int(const OctetString* kasme, OctetString* knas_int, UInt8_t eea); +static int _security_kenb(const OctetString* kasme, OctetString* kenb, UInt32_t count); + +/* + * Internal data used for security mode control procedure + */ +static struct { + OctetString kenb; /* eNodeB security key */ +} _security_data; + +static void _security_release(emm_security_context_t* ctx); +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the security mode control procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _security_t3460_handler(void*); + +/* + * Function executed whenever the ongoing EMM procedure that initiated + * the security mode control procedure is aborted or the maximum value of the + * retransmission timer counter is exceed + */ +static int _security_abort(void*); + +/* + * Internal data used for security mode control procedure + */ +typedef struct { + unsigned int ueid; /* UE identifier */ +#define SECURITY_COUNTER_MAX 5 + unsigned int retransmission_count; /* Retransmission counter */ + int ksi; /* NAS key set identifier */ + int eea; /* Replayed EPS encryption algorithms */ + int eia; /* Replayed EPS integrity algorithms */ + int notify_failure; /* Indicates whether the security mode control + * procedure failure shall be notified to the + * ongoing EMM procedure */ +} security_data_t; + +static int _security_request(security_data_t* data, int is_new); +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Security mode control procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_proc_security_mode_command() ** + ** ** + ** Description: Performs the MME requested security mode control proce- ** + ** dure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.3.3 ** + ** Upon receiving the SECURITY MODE COMMAND message, the UE ** + ** shall check whether the message can be accepted or not. ** + ** If accepted the UE shall send a SECURITY MODE COMPLETE ** + ** message integrity protected with the selected NAS inte- ** + ** grity algorithm and ciphered with the selected NAS ciphe- ** + ** ring algorithm. ** + ** ** + ** Inputs: native_ksi: TRUE if the security context is of type ** + ** native (for KSIASME) ** + ** ksi: The NAS ket sey identifier ** + ** seea: Selected EPS cyphering algorithm ** + ** seia: Selected EPS integrity algorithm ** + ** reea: Replayed EPS cyphering algorithm ** + ** reia: Replayed EPS integrity algorithm ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_security_mode_command(int native_ksi, int ksi, + int seea, int seia, int reea, int reia) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int emm_cause = EMM_CAUSE_SUCCESS; + int security_context_is_new = FALSE; + + LOG_TRACE(INFO, "EMM-PROC - Security mode control requested (ksi=%d)", + ksi); + + /* Delete any previously stored RAND and RES and stop timer T3416 */ + (void) emm_proc_authentication_delete(); + + /* + * Check the replayed UE security capabilities + */ + UInt8_t eea = (0x80 >> _emm_data.security->capability.encryption); + UInt8_t eia = (0x80 >> _emm_data.security->capability.integrity); + if ( (reea != eea) || (reia != eia) ) { + LOG_TRACE(WARNING, "EMM-PROC - Replayed UE security capabilities " + "rejected"); + emm_cause = EMM_CAUSE_UE_SECURITY_MISMATCH; + + /* XXX - For testing purpose UE always accepts EIA0 + * The UE shall accept "null integrity protection algorithm" EIA0 only + * if a PDN connection for emergency bearer services is established or + * the UE is establishing a PDN connection for emergency bearer services + */ + } + /* + * Check the non-current EPS security context + */ + else if (_emm_data.non_current == NULL) { + LOG_TRACE(WARNING, "EMM-PROC - Non-current EPS security context " + "is not valid"); + emm_cause = EMM_CAUSE_SECURITY_MODE_REJECTED; + } + /* + * Update the non-current EPS security context + */ + else { + /* Update selected cyphering and integrity algorithms */ + _emm_data.non_current->capability.encryption = seea; + _emm_data.non_current->capability.integrity = seia; + + /* Derive the NAS cyphering key */ + if (_emm_data.non_current->knas_enc.value == NULL) { + _emm_data.non_current->knas_enc.value = + (uint8_t*)malloc(AUTH_KNAS_ENC_SIZE); + _emm_data.non_current->knas_enc.length = AUTH_KNAS_ENC_SIZE; + } + if (_emm_data.non_current->knas_enc.value != NULL) { + rc = _security_knas_enc(&_emm_data.non_current->kasme, + &_emm_data.non_current->knas_enc, seea); + } + /* Derive the NAS integrity key */ + if (_emm_data.non_current->knas_int.value == NULL) { + _emm_data.non_current->knas_int.value = + (uint8_t*)malloc(AUTH_KNAS_INT_SIZE); + _emm_data.non_current->knas_int.length = AUTH_KNAS_INT_SIZE; + } + if (_emm_data.non_current->knas_int.value != NULL) { + if (rc != RETURNerror) { + rc = _security_knas_int(&_emm_data.non_current->kasme, + &_emm_data.non_current->knas_int, seea); + } + } + /* Derive the eNodeB key */ + if (_security_data.kenb.value == NULL) { + _security_data.kenb.value = (uint8_t*)malloc(AUTH_KENB_SIZE); + _security_data.kenb.length = AUTH_KENB_SIZE; + } + if (_security_data.kenb.value != NULL) { + if (rc != RETURNerror) { + rc = _security_kenb(&_security_data.kenb, + &_emm_data.security->kasme, + *(UInt32_t*)(&_emm_data.non_current->ul_count)); + } + } + + /* + * NAS security mode command accepted by the UE + */ + if (rc != RETURNerror) { + /* Update the current EPS security context */ + if ( native_ksi && (_emm_data.security->type != EMM_KSI_NATIVE) ) { + /* The type of security context flag included in the SECURITY + * MODE COMMAND message is set to "native security context" and + * the UE has a mapped EPS security context as the current EPS + * security context */ + if ( (_emm_data.non_current->type == EMM_KSI_NATIVE) && + (_emm_data.non_current->eksi == ksi) ) { + /* The KSI matches the non-current native EPS security + * context; the UE shall take the non-current native EPS + * security context into use which then becomes the + * current native EPS security context and delete the + * mapped EPS security context */ + LOG_TRACE(INFO, + "EMM-PROC - Update Current security context"); + /* Release non-current security context */ + _security_release(_emm_data.security); + _emm_data.security = _emm_data.non_current; + /* Reset the uplink NAS COUNT counter */ + _emm_data.security->ul_count.overflow = 0; + _emm_data.security->ul_count.seq_num = 0; + /* Set new security context indicator */ + security_context_is_new = TRUE; + } + } + + if ( !native_ksi && (_emm_data.security->type != EMM_KSI_NATIVE) ) { + /* The type of security context flag included in the SECURITY + * MODE COMMAND message is set to "mapped security context" and + * the UE has a mapped EPS security context as the current EPS + * security context */ + if (ksi != _emm_data.security->eksi) { + /* The KSI does not match the current EPS security context; + * the UE shall reset the uplink NAS COUNT counter */ + LOG_TRACE(INFO, + "EMM-PROC - Reset uplink NAS COUNT counter"); + _emm_data.security->ul_count.overflow = 0; + _emm_data.security->ul_count.seq_num = 0; + } + } + } + /* + * NAS security mode command not accepted by the UE + */ + else { + /* Setup EMM cause code */ + emm_cause = EMM_CAUSE_SECURITY_MODE_REJECTED; + /* Release security mode control internal data */ + if (_security_data.kenb.value) { + free(_security_data.kenb.value); + _security_data.kenb.value = NULL; + _security_data.kenb.length = 0; + } + } + } + + /* Setup EMM procedure handler to be executed upon receiving + * lower layer notification */ + rc = emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "EMM-PROC - Failed to initialize EMM procedure handler"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Notify EMM-AS SAP that Security Mode response message has to be sent + * to the network + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMAS_SECURITY_RES; + emm_sap.u.emm_as.u.security.guti = _emm_data.guti; + emm_sap.u.emm_as.u.security.ueid = 0; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_SMC; + emm_sap.u.emm_as.u.security.emm_cause = emm_cause; + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + _emm_data.security, security_context_is_new, TRUE); + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Security mode control procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_proc_security_mode_control() ** + ** ** + ** Description: Initiates the security mode control procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.3.2 ** + ** The MME initiates the NAS security mode control procedure ** + ** by sending a SECURITY MODE COMMAND message to the UE and ** + ** starting timer T3460. The message shall be sent unciphe- ** + ** red but shall be integrity protected using the NAS inte- ** + ** grity key based on KASME. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** ksi: NAS key set identifier ** + ** eea: Replayed EPS encryption algorithms ** + ** eia: Replayed EPS integrity algorithms ** + ** success: Callback function executed when the secu- ** + ** rity mode control procedure successfully ** + ** completes ** + ** reject: Callback function executed when the secu- ** + ** rity mode control procedure fails or is ** + ** rejected ** + ** failure: Callback function executed whener a lower ** + ** layer failure occured before the security ** + ** mode control procedure comnpletes ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_security_mode_control(unsigned int ueid, int ksi, int eea, int eia, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int security_context_is_new = FALSE; + + LOG_TRACE(INFO, "EMM-PROC - Initiate security mode control procedure " + "KSI = %d", ksi); + + /* Get the UE context */ + emm_data_context_t* emm_ctx = NULL; + +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_ctx && emm_ctx->security) { + if (emm_ctx->security->type == EMM_KSI_NOT_AVAILABLE) { + /* The security mode control procedure is initiated to take into use + * the EPS security context created after a successful execution of + * the EPS authentication procedure */ + emm_ctx->security->type = EMM_KSI_NATIVE; + emm_ctx->security->eksi = ksi; + emm_ctx->security->dl_count.overflow = 0; + emm_ctx->security->dl_count.seq_num = 0; + + /* TODO !!! Compute Kasme, and NAS cyphering and integrity keys */ + + /* Set new security context indicator */ + security_context_is_new = TRUE; + } + } + else { + LOG_TRACE(WARNING, "EMM-PROC - No EPS security context exists"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Allocate parameters of the retransmission timer callback */ + security_data_t* data = + (security_data_t*)malloc(sizeof(security_data_t)); + + if (data != NULL) { + /* Setup ongoing EMM procedure callback functions */ + rc = emm_proc_common_initialize(ueid, success, reject, failure, + _security_abort, data); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "Failed to initialize EMM callback functions"); + free(data); + LOG_FUNC_RETURN (RETURNerror); + } + /* Set the UE identifier */ + data->ueid = ueid; + /* Reset the retransmission counter */ + data->retransmission_count = 0; + /* Set the key set identifier */ + data->ksi = ksi; + /* Set the EPS encryption algorithms to be replayed to the UE */ + data->eea = eea; + /* Set the EPS integrity algorithms to be replayed to the UE */ + data->eia = eia; + /* Set the failure notification indicator */ + data->notify_failure = FALSE; + /* Send security mode command message to the UE */ + rc = _security_request(data, security_context_is_new); + if (rc != RETURNerror) { + /* + * Notify EMM that common procedure has been initiated + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REQ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_security_mode_complete() ** + ** ** + ** Description: Performs the security mode control completion procedure ** + ** executed by the network. ** + ** ** + ** 3GPP TS 24.301, section 5.4.3.4 ** + ** Upon receiving the SECURITY MODE COMPLETE message, the ** + ** MME shall stop timer T3460. ** + ** From this time onward the MME shall integrity protect and ** + ** encipher all signalling messages with the selected NAS ** + ** integrity and ciphering algorithms. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_security_mode_complete(unsigned int ueid) +{ + emm_data_context_t* emm_ctx = NULL; + + int rc = RETURNerror; + emm_sap_t emm_sap; + + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMM-PROC - Security mode complete (ueid=%u)", ueid); + + /* Stop timer T3460 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3460 (%d)", T3460.id); + T3460.id = nas_timer_stop(T3460.id); + + /* Release retransmission timer paramaters */ + security_data_t* data = (security_data_t*)(emm_proc_common_get_args(ueid)); + if (data) free(data); + + /* Get the UE context */ +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + + if (emm_ctx && emm_ctx->security) { + /* + * Notify EMM that the authentication procedure successfully completed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_CNF; + emm_sap.u.emm_reg.ueid = ueid; + emm_sap.u.emm_reg.u.common.is_attached = emm_ctx->is_attached; + } + else { + LOG_TRACE(ERROR, "EMM-PROC - No EPS security context exists"); + /* + * Notify EMM that the authentication procedure failed + */ + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + } + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_proc_security_mode_reject() ** + ** ** + ** Description: Performs the security mode control not accepted by the UE ** + ** ** + ** 3GPP TS 24.301, section 5.4.3.5 ** + ** Upon receiving the SECURITY MODE REJECT message, the MME ** + ** shall stop timer T3460 and abort the ongoing procedure ** + ** that triggered the initiation of the NAS security mode ** + ** control procedure. ** + ** The MME shall apply the EPS security context in use befo- ** + ** re the initiation of the security mode control procedure, ** + ** if any, to protect any subsequent messages. ** + ** ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_proc_security_mode_reject(unsigned int ueid) +{ + emm_data_context_t* emm_ctx = NULL; + int rc = RETURNerror; + + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - Security mode command not accepted by the UE" + "(ueid=0x%08x)", ueid); + + /* Stop timer T3460 */ + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3460 (%d)", T3460.id); + T3460.id = nas_timer_stop(T3460.id); + + /* Release retransmission timer paramaters */ + security_data_t* data = (security_data_t*)(emm_proc_common_get_args(ueid)); + if (data) free(data); + + /* Get the UE context */ +#if defined(EPC_BUILD) + if (ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, ueid); + } +#else + if (ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[ueid]; + } +#endif + /* Set the key set identifier to its previous value */ + if (emm_ctx && emm_ctx->security) { + /* XXX - Usually, the MME should be able to maintain a current and + * a non-current EPS security context simultaneously as the UE do. + * This implementation choose to have only one security context by UE + * in the MME, thus security mode control procedure is only performed + * to take into use the first EPS security context created after a + * successful execution of the EPS authentication procedure */ + emm_ctx->security->type = EMM_KSI_NOT_AVAILABLE; + } + + /* + * Notify EMM that the authentication procedure failed + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * UE specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _security_release() ** + ** ** + ** Description: Releases the given EPS NAS security context ** + ** ** + ** Inputs: ctx: The EPS NAS security context to release ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _security_release(emm_security_context_t* ctx) +{ + LOG_FUNC_IN; + + if (ctx) { + /* Release Kasme security key */ + if (ctx->kasme.value) free(ctx->kasme.value); + /* Release NAS cyphering key */ + if (ctx->knas_enc.value) free(ctx->knas_enc.value); + /* Release NAS integrity key */ + if (ctx->knas_int.value) free(ctx->knas_int.value); + /* Release the NAS security context */ + free(ctx); + } + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: _security_knas_enc() ** + ** ** + ** Description: Algorithm Key generation function used for the derivation ** + ** of NAS encryption key Knas-enc from the Kasme. ** + ** ** + ** 3GPP TS 33.401, Annex A.7 ** + ** ** + ** Inputs: kasme: Key Access Security Management Entity ** + ** eea: Cyphering algorithm identity ** + ** Others: None ** + ** ** + ** Outputs: knas_enc: Derived key for NAS cyphering algorithm ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _security_knas_enc(const OctetString* kasme, OctetString* knas_enc, + UInt8_t eea) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_security_kdf(kasme, knas_enc, 0x01, eea)); +} + +/**************************************************************************** + ** ** + ** Name: _security_knas_int() ** + ** ** + ** Description: Algorithm Key generation function used for the derivation ** + ** of NAS integrity key Knas-int from the Kasme. ** + ** ** + ** 3GPP TS 33.401, Annex A.7 ** + ** ** + ** Inputs: kasme: Key Access Security Management Entity ** + ** eia: Integrity algorithm identity ** + ** Others: None ** + ** ** + ** Outputs: knas_int: Derived key for NAS integrity algorithm ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _security_knas_int(const OctetString* kasme, OctetString* knas_int, + UInt8_t eia) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_security_kdf(kasme, knas_int, 0x02, eia)); +} + +/**************************************************************************** + ** ** + ** Name: _security_kenb() ** + ** ** + ** Description: Computes the eNodeB key from Kasme and the given value of ** + ** uplink NAS counter. ** + ** ** + ** 3GPP TS 33.401, Annex A.3 ** + ** ** + ** Inputs: kasme: Key Access Security Management Entity ** + ** count: Uplink NAS counter value ** + ** Others: None ** + ** ** + ** Outputs: kenb: eNodeB security key ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _security_kenb(const OctetString* kasme, OctetString* kenb, + UInt32_t count) +{ + /* Compute the KDF input parameter + * S = FC(0x11) || UL NAS Count || 0x00 0x04 + */ + UInt8_t input[kasme->length]; + UInt16_t length = 4; + int offset = 0; + + input[offset] = 0x11; offset += 1; + input[offset] = count; offset += length; + input[offset] = length; + + /* TODO !!! Compute the derived key */ + // todo_hmac_256(key, input, kasme->value); + return (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _security_kdf() ** + ** ** + ** Description: Algorithm Key generation function used for the derivation ** + ** of keys for NAS integrity and NAS encryption algorithms ** + ** from Kasme, algorithm types and algorithm identities. ** + ** ** + ** 3GPP TS 33.401, Annex A.7 ** + ** ** + ** Inputs: kasme: Key Access Security Management Entity ** + ** algo_dist: Algorithm type distinguisher ** + ** algo_id: Algorithm identity ** + ** Others: None ** + ** ** + ** Outputs: key: Derived key for NAS security protection ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _security_kdf(const OctetString* kasme, OctetString* key, + UInt8_t algo_dist, UInt8_t algo_id) +{ + /* Compute the KDF input parameter + * S = FC(0x15) || Algorithm distinguisher || 0x00 0x01 + || Algorithm identity || 0x00 0x01 + */ + UInt8_t input[kasme->length]; + UInt16_t length = 1; + int offset = 0; + int size_of_length = sizeof(length); + + input[offset] = 0x15; offset += 1; + input[offset] = algo_dist; offset += length; + input[offset] = length; offset += size_of_length; + input[offset] = algo_id; offset += length; + input[offset] = length; + + /* TODO !!! Compute the derived key */ + // todo_hmac_256(key, input, kasme->value); + return (RETURNok); +} +#endif // NAS_UE + +#ifdef NAS_MME +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _security_t3460_handler() ** + ** ** + ** Description: T3460 timeout handler ** + ** Upon T3460 timer expiration, the security mode command ** + ** message is retransmitted and the timer restarted. When ** + ** retransmission counter is exceed, the MME shall abort the ** + ** security mode control procedure. ** + ** ** + ** 3GPP TS 24.301, section 5.4.3.7, case b ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _security_t3460_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + security_data_t* data = (security_data_t*)(args); + + /* Increment the retransmission counter */ + data->retransmission_count += 1; + + LOG_TRACE(WARNING, "EMM-PROC - T3460 timer expired, retransmission " + "counter = %d", data->retransmission_count); + + if (data->retransmission_count < SECURITY_COUNTER_MAX) { + /* Send security mode command message to the UE */ + rc = _security_request(data, FALSE); + } + else { + /* Set the failure notification indicator */ + data->notify_failure = TRUE; + /* Abort the security mode control procedure */ + rc = _security_abort(data); + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _security_request() ** + ** ** + ** Description: Sends SECURITY MODE COMMAND message and start timer T3460 ** + ** ** + ** Inputs: data: Security mode control internal data ** + ** is_new: Indicates whether a new security context ** + ** has just been taken into use ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3460 ** + ** ** + ***************************************************************************/ +int _security_request(security_data_t* data, int is_new) +{ + struct emm_data_context_s *emm_ctx = NULL; + + emm_sap_t emm_sap; + int rc; + + LOG_FUNC_IN; + + /* + * Notify EMM-AS SAP that Security Mode Command message has to be sent + * to the UE + */ + emm_sap.primitive = EMMAS_SECURITY_REQ; + emm_sap.u.emm_as.u.security.guti = NULL; + emm_sap.u.emm_as.u.security.ueid = data->ueid; + emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_SMC; + emm_sap.u.emm_as.u.security.ksi = data->ksi; + emm_sap.u.emm_as.u.security.eea = data->eea; + emm_sap.u.emm_as.u.security.eia = data->eia; + +#if defined(EPC_BUILD) + if (data->ueid > 0) { + emm_ctx = emm_data_context_get(&_emm_data, data->ueid); + } +#else + if (data->ueid < EMM_DATA_NB_UE_MAX) { + emm_ctx = _emm_data.ctx[data->ueid]; + } +#endif + + /* Setup EPS NAS security data */ + emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx, + emm_ctx->security, is_new, FALSE); + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + if (T3460.id != NAS_TIMER_INACTIVE_ID) { + /* Re-start T3460 timer */ + T3460.id = nas_timer_restart(T3460.id); + } else { + /* Start T3460 timer */ + T3460.id = nas_timer_start(T3460.sec, _security_t3460_handler, data); + } + LOG_TRACE(INFO,"EMM-PROC - Timer T3460 (%d) expires in %ld seconds", + T3460.id, T3460.sec); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _security_abort() ** + ** ** + ** Description: Aborts the security mode control procedure currently in ** + ** progress ** + ** ** + ** Inputs: args: Security mode control data to be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3460 ** + ** ** + ***************************************************************************/ +static int _security_abort(void* args) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + security_data_t* data = (security_data_t*)(args); + + if (data) + { + unsigned int ueid = data->ueid; + int notify_failure = data->notify_failure; + + LOG_TRACE(WARNING, "EMM-PROC - Abort security mode control procedure " + "(ueid=%u)", ueid); + + /* Stop timer T3460 */ + if (T3460.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "EMM-PROC - Stop timer T3460 (%d)", T3460.id); + T3460.id = nas_timer_stop(T3460.id); + } + /* Release retransmission timer paramaters */ + free(data); + + /* + * Notify EMM that the security mode control procedure failed + */ + if (notify_failure) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_COMMON_PROC_REJ; + emm_sap.u.emm_reg.ueid = ueid; + rc = emm_sap_send(&emm_sap); + } else { + rc = RETURNok; + } + } + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_MME + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/ServiceRequestHdl.c b/openair-cn/NAS/EURECOM-NAS/src/emm/ServiceRequestHdl.c new file mode 100644 index 0000000000..b7fbcd898a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/ServiceRequestHdl.c @@ -0,0 +1,110 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source ServiceRequest.c + +Version 0.1 + +Date 2013/05/07 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the service request EMM procedure executed by the + Non-Access Stratum. + + The purpose of the service request procedure is to transfer + the EMM mode from EMM-IDLE to EMM-CONNECTED mode and establish + the radio and S1 bearers when uplink user data or signalling + is to be sent. + + This procedure is used when the network has downlink signalling + pending, the UE has uplink signalling pending, the UE or the + network has user data pending and the UE is in EMM-IDLE mode. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the service request procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Timer handlers + */ +void* _emm_service_t3417_handler(void*); +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the service request procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_service_t3417_handler() ** + ** ** + ** Description: T3417 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.6.1.6 case c ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* _emm_service_t3417_handler(void* args) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - T3417 timer expired"); + + /* Stop timer T3417 */ + T3417.id = nas_timer_stop(T3417.id); + + LOG_FUNC_RETURN(NULL); +} + +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/TrackingAreaUpdate.c b/openair-cn/NAS/EURECOM-NAS/src/emm/TrackingAreaUpdate.c new file mode 100644 index 0000000000..05d4592e75 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/TrackingAreaUpdate.c @@ -0,0 +1,107 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source TrackingAreaUpdate.c + +Version 0.1 + +Date 2013/05/07 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the tracking area update EMM procedure executed by the + Non-Access Stratum. + + The tracking area updating procedure is always initiated by the + UE and is used to update the registration of the actual tracking + area of a UE in the network, to periodically notify the availa- + bility of the UE to the network, for MME load balancing, to up- + date certain UE specific parameters in the network. + +*****************************************************************************/ + +#include "emm_proc.h" +#include "nas_log.h" +#include "nas_timer.h" + +#include "emmData.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the tracking area update procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Timer handlers + */ +void* _emm_tau_t3430_handler(void*); +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the tracking area update procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_tau_t3430_handler() ** + ** ** + ** Description: T3430 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 5.5.3.2.6 case c ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* _emm_tau_t3430_handler(void* args) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "EMM-PROC - T3430 timer expired"); + + /* Stop timer T3430 */ + T3430.id = nas_timer_stop(T3430.id); + + LOG_FUNC_RETURN(NULL); +} + +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/emmData.h b/openair-cn/NAS/EURECOM-NAS/src/emm/emmData.h new file mode 100644 index 0000000000..d32d3557e5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/emmData.h @@ -0,0 +1,484 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emmData.h + +Version 0.1 + +Date 2012/10/18 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines internal private data handled by EPS Mobility + Management sublayer. + +*****************************************************************************/ +#ifndef __EMMDATA_H__ +#define __EMMDATA_H__ + +#include "commonDef.h" +#include "networkDef.h" +#include "securityDef.h" + +#include "OctetString.h" +#include "nas_timer.h" + +#ifdef NAS_MME +#include "emm_fsm.h" +#include "mme_api.h" +# if defined(EPC_BUILD) +# include "tree.h" +# endif +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * The name of the file used as non-volatile memory device to store + * persistent EMM data when the UE is switched off + */ +#define EMM_NVRAM_FILENAME ".ue_emm.nvram" + +/* + * The name of the environment variable which defines the directory + * where the EMM data file is located + */ +#define EMM_NVRAM_DIRNAME "NVRAM_DIR" + +/* Network selection modes of operation */ +#define EMM_DATA_PLMN_AUTO NET_PLMN_AUTO +#define EMM_DATA_PLMN_MANUAL NET_PLMN_MANUAL + +#endif // NAS_UE + +/* Checks Mobile Country Code equality */ +#define MCCS_ARE_EQUAL(n1, n2) (((n1).MCCdigit1 == (n2).MCCdigit1) && \ + ((n1).MCCdigit2 == (n2).MCCdigit2) && \ + ((n1).MCCdigit3 == (n2).MCCdigit3)) + +/* Checks Mobile Network Code equality */ +#define MNCS_ARE_EQUAL(n1, n2) (((n1).MNCdigit1 == (n2).MNCdigit1) && \ + ((n1).MNCdigit2 == (n2).MNCdigit2) && \ + ((n1).MNCdigit3 == (n2).MNCdigit3)) + +/* Checks PLMNs equality */ +#define PLMNS_ARE_EQUAL(p1, p2) ((MCCS_ARE_EQUAL((p1),(p2))) && \ + (MNCS_ARE_EQUAL((p1),(p2)))) + +/* Checks TAIs equality */ +#define TAIS_ARE_EQUAL(t1, t2) ((PLMNS_ARE_EQUAL((t1).plmn,(t2).plmn)) && \ + ((t1).tac == (t2).tac)) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * EPS NAS security context handled by EPS Mobility Management sublayer in + * the UE and in the MME + * -------------------------------------------------------------------------- + */ +/* Type of security context */ +typedef enum { + EMM_KSI_NOT_AVAILABLE = 0, + EMM_KSI_NATIVE, + EMM_KSI_MAPPED +} emm_ksi_t; + +/* EPS NAS security context structure */ +typedef struct { + emm_ksi_t type; /* Type of security context */ + int eksi; /* NAS key set identifier for E-UTRAN */ + OctetString kasme; /* ASME security key (native context) */ + //OctetString ksgsn; /* SGSN security key (mapped context) */ + OctetString knas_enc; /* NAS cyphering key */ + OctetString knas_int; /* NAS integrity key */ + struct { + UInt32_t spare:8; + UInt32_t overflow:16; + UInt32_t seq_num:8; + } dl_count, ul_count; /* Downlink and uplink count parameters */ + struct { + UInt8_t encryption:4; /* algorithm used for ciphering */ + UInt8_t integrity:4; /* algorithm used for integrity protection */ + } capability; /* UE network capability */ +} emm_security_context_t; + +/* + * -------------------------------------------------------------------------- + * EMM internal data handled by EPS Mobility Management sublayer in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * EPS update status + * ----------------- + * The EPS update status value is changed only after the execution of an attach + * or combined attach, network initiated detach, authentication, tracking area + * update or combined tracking area update, service request or paging for EPS + * services using IMSI procedure. + * + * EU1: The last attach or tracking area updating attempt was successful. + * EU2: The last attach, service request or tracking area updating attempt + * failed procedurally, i.e. no response or reject message was received + * from the MME. + * EU3: The last attach, service request or tracking area updating attempt + * was correctly performed, but the answer from the MME was negative + * (because of roaming or subscription restrictions). + */ +typedef enum { + EU1_UPDATED, + EU2_NOT_UPDATED, + EU3_ROAMING_NOT_ALLOWED +} emm_eps_update_t; + +/* + * EPS Connection Management states + * -------------------------------- + * ECM-IDLE: No NAS signalling connection between UE and network exists. + * No UE context exists in the network. + * ECM-CONNECTED: The signalling connection is established between the UE + * and the MME (RRC connection and S1_MME connection). + */ +typedef enum { + ECM_IDLE, + ECM_CONNECTED +} emm_ecm_state_t; + +/* + * Structure of the EMM parameters stored in the UE's non-volatile memory + * ---------------------------------------------------------------------- + * These EMM parameters can only be used if the IMSI from the USIM matches + * the IMSI stored in the non-volatile memory; else the UE shall delete the + * EMM parameters. + * + * - EPLMN: List of equivalent PLMNs - Updated at the end of each attach or + * combined attach or tracking area updating or combined tracking area + * updating procedure. Deleted if the USIM is removed or when the UE attached + * for emergency bearer services enters the state EMM-DEREGISTERED. + * These PLMNs shall be regarded by the UE as equivalent to each other + * for PLMN selection, cell selection/re-selection and handover. + * The maximum number of possible entries in the stored list is 16. + */ +typedef struct { + imsi_t imsi; + plmn_t rplmn; /* The registered PLMN */ + /* List of equivalent PLMNs */ +#define EMM_DATA_EPLMN_MAX 16 + PLMN_LIST_T(EMM_DATA_EPLMN_MAX) eplmn; +} emm_nvdata_t; + +/* + * Structure of the EMM data + * ------------------------- + */ +typedef struct { + int usim_is_valid; /* Indication of USIM data validity */ + + imei_t *imei; /* IMEI read from the UE's non-volatile memory */ + const imsi_t *imsi; /* The valid IMSI read from the USIM */ + GUTI_t *guti; /* The valid GUTI read from the USIM */ + tai_t *tai; /* Last visited registered Tracking Area Id */ + + emm_eps_update_t status; /* The current EPS update status */ + emm_ecm_state_t ecm_status; /* The EPS Connection Management status */ + int is_attached; /* Network attachment indicator */ + int is_emergency; /* Emergency bearer services indicator */ + + /* Tracking Areas list the UE is registered to + * Contains the list of TAIs that identify the tracking areas that + * the UE can enter without performing a tracking area updating + * procedure. The TAIs in a TAI list assigned by an MME to a UE + * pertain to the same MME area. + */ +#define EMM_DATA_TAI_MAX 16 + TAI_LIST_T(EMM_DATA_TAI_MAX) ltai; + + int plmn_mode; /* Network selection operating mode */ + int plmn_index; /* Manually selected PLMN */ + int plmn_rat; /* Manually selected Radio Access Technology */ + + plmn_t splmn; /* The currently selected PLMN */ + int is_rplmn; /* splmn is the registered PLMN */ + int is_eplmn; /* splmn is in the list of equivalent PLMNs */ + Stat_t stat; /* Current network registration status */ + tac_t tac; /* Tracking area code */ + ci_t ci; /* GERAN/UTRAN/E-UTRAN serving cell identifier */ + AcT_t rat; /* Radio Access Technology of the serving cell */ + + /* An octet string representation of operators present in the network */ + struct { +#define EMM_DATA_BUFFER_SIZE 2048 + char buffer[EMM_DATA_BUFFER_SIZE+1]; + } plist; + + /* + * Data used for PLMN selection procedure + * -------------------------------------- + */ + plmn_t hplmn; /* The Home PLMN derived from the IMSI */ + /* List of Forbidden PLMNs + * Contains the list of PLMN identities for which a Location + * Registration has been rejected with EMM cause code #11 (PLMN + * not allowed). A PLMN is removed from this list if, after a + * subsequent manual selection of that PLMN, there is a successful + * Location Request. */ +#define EMM_DATA_FPLMN_MAX 4 + PLMN_LIST_T(EMM_DATA_FPLMN_MAX) fplmn; + /* List of Forbidden PLMNs for GPRS service + * Contains the list of PLMN identities for which an Attach Request + * has been rejected with EMM cause code #14 (GPRS/EPS services not + * allowed in this PLMN). A PLMN is removed from this list if, after + * a subsequent manual selection of that PLMN, there is a successful + * GPRS attach or EPS attach. */ +#define EMM_DATA_FPLMN_GPRS_MAX 4 + PLMN_LIST_T(EMM_DATA_FPLMN_GPRS_MAX) fplmn_gprs; + /* List of Equivalent HPLMNs */ +#define EMM_DATA_EHPLMN_MAX 4 + PLMN_LIST_T(EMM_DATA_EHPLMN_MAX) ehplmn; + /* List of user controlled PLMNs */ +#define EMM_DATA_PLMN_MAX 4 + PLMN_LIST_T(EMM_DATA_PLMN_MAX) plmn; + UInt16_t userAcT[EMM_DATA_PLMN_MAX]; + /* List of operator controlled PLMNs */ +#define EMM_DATA_OPLMN_MAX 4 + PLMN_LIST_T(EMM_DATA_OPLMN_MAX) oplmn; + UInt16_t operAcT[EMM_DATA_OPLMN_MAX]; + /* List of operator network name records */ +#define EMM_DATA_OPNN_MAX 16 + UInt8_t n_opnns; + struct { + const plmn_t *plmn; + const char *fullname; + const char *shortname; + } opnn[EMM_DATA_OPNN_MAX]; + + /* + * Data used for roaming service + * ----------------------------- + */ + /* List of Forbidden Tracking Areas + * Contains the list of TAIs for which an attach request has been + * rejected with EMM cause code #12 (tracking area not allowed). + */ +#define EMM_DATA_FTAI_MAX 40 + TAI_LIST_T(EMM_DATA_FTAI_MAX) ftai; + /* List of Forbidden Tracking Areas for roaming + * Contains the list of TAIs for which an attach request has been + * rejected with EMM cause code #13 (roaming not allowed in this + * tracking area). + */ +#define EMM_DATA_FTAI_ROAMING_MAX 40 + TAI_LIST_T(EMM_DATA_FTAI_ROAMING_MAX) ftai_roaming; + + /* + * NAS configuration parameters + * ---------------------------- + * see "Non Access Stratum Configuration" in USIM API header file + */ + Byte_t NAS_SignallingPriority; + Byte_t NMO_I_Behaviour; + Byte_t AttachWithImsi; + Byte_t MinimumPeriodicSearchTimer; + Byte_t ExtendedAccessBarring; + Byte_t Timer_T3245_Behaviour; + + /* + * EMM data stored in the UE's memory + * ---------------------------------- + */ + emm_nvdata_t nvdata; + + /* + * EPS NAS security context + * ------------------------ + */ + emm_security_context_t* security; /* current security context */ + emm_security_context_t* non_current; /* non-current security context */ + +} emm_data_t; + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * EMM internal data handled by EPS Mobility Management sublayer in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Structure of the EMM context established by the network for a particular UE + * --------------------------------------------------------------------------- + */ +typedef struct emm_data_context_s { + unsigned int ueid; /* UE identifier */ + int is_dynamic; /* Dynamically allocated context indicator */ + int is_attached; /* Attachment indicator */ + int is_emergency; /* Emergency bearer services indicator */ + + imsi_t* imsi; /* The IMSI provided by the UE or the MME */ + imei_t* imei; /* The IMEI provided by the UE */ + int guti_is_new; /* New GUTI indicator */ + GUTI_t* guti; /* The GUTI assigned to the UE */ + GUTI_t* old_guti; /* The old GUTI */ + int n_tacs; /* Number of concecutive tracking areas the UE is + * registered to */ + tac_t tac; /* Code of the first tracking area the UE is + * registered to */ + + int ksi; /* Security key set identifier provided by the UE */ + int eea; /* EPS encryption algorithms supported by the UE */ + int eia; /* EPS integrity algorithms supported by the UE */ + auth_vector_t vector; /* EPS authentication vector */ + emm_security_context_t* security; /* Current EPS NAS security context */ + OctetString esm_msg; /* ESM message contained within the initial request */ + int emm_cause; /* EMM failure cause code */ + + emm_fsm_state_t _emm_fsm_status; + +#if defined(EPC_BUILD) + RB_ENTRY(emm_data_context_s) entries; +#endif +} emm_data_context_t; + +/* + * Structure of the EMM data + * ------------------------- + */ +typedef struct { + /* + * MME configuration + * ----------------- + */ + mme_api_emm_config_t conf; + /* + * EMM contexts + * ------------ + */ +# if defined(EPC_BUILD) + /* Use a tree for ue data context within MME */ + RB_HEAD(emm_data_context_map, emm_data_context_s) ctx_map; +# else +# define EMM_DATA_NB_UE_MAX (MME_API_NB_UE_MAX + 1) + emm_data_context_t* ctx [EMM_DATA_NB_UE_MAX]; +# endif +} emm_data_t; + +struct emm_data_context_s *emm_data_context_get( + emm_data_t *_emm_data, unsigned int _ueid); + +struct emm_data_context_s * emm_data_context_remove( + emm_data_t *_emm_data, struct emm_data_context_s *elm); + +void emm_data_context_add(emm_data_t *emm_data, struct emm_data_context_s *elm); + +#endif // NAS_MME + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * EPS mobility management data (used within EMM only) + * -------------------------------------------------------------------------- + */ +emm_data_t _emm_data; + +/* + * -------------------------------------------------------------------------- + * EPS mobility management timers – UE side + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +#define T3402_DEFAULT_VALUE 720 /* 12 minutes */ +#define T3410_DEFAULT_VALUE 15 /* 15 seconds */ +#define T3411_DEFAULT_VALUE 10 /* 10 seconds */ +#define T3412_DEFAULT_VALUE 3240 /* 54 minutes */ +#define T3416_DEFAULT_VALUE 30 /* 30 seconds */ +#define T3417_DEFAULT_VALUE 5 /* 5 seconds */ +#define T3417ext_DEFAULT_VALUE 10 /* 10 seconds */ +#define T3418_DEFAULT_VALUE 20 /* 20 seconds */ +#define T3420_DEFAULT_VALUE 15 /* 15 seconds */ +#define T3421_DEFAULT_VALUE 15 /* 15 seconds */ +#define T3423_DEFAULT_VALUE T3412_DEFAULT_VALUE +#define T3430_DEFAULT_VALUE 15 /* 15 seconds */ +#define T3440_DEFAULT_VALUE 10 /* 10 seconds */ + +struct nas_timer_t T3402; /* attach failure timer */ +struct nas_timer_t T3410; /* attach timer */ +struct nas_timer_t T3411; /* attach restart timer */ +struct nas_timer_t T3412; /* periodic tracking area update timer */ +struct nas_timer_t T3416; /* EPS authentication challenge timer */ +struct nas_timer_t T3417; /* Service request timer */ +struct nas_timer_t T3418; /* MAC authentication failure timer */ +struct nas_timer_t T3420; /* Synch authentication failure timer */ +struct nas_timer_t T3421; /* Detach timer */ +struct nas_timer_t T3430; /* tracking area update timer */ + +struct nas_timer_t T3423; /* E-UTRAN deactivate ISR timer */ +#endif + +/* + * -------------------------------------------------------------------------- + * EPS mobility management timers – Network side + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +#define T3450_DEFAULT_VALUE 6 /* 6 seconds */ +#define T3460_DEFAULT_VALUE 6 /* 6 seconds */ +#define T3470_DEFAULT_VALUE 6 /* 6 seconds */ + +struct nas_timer_t T3450; /* EMM message retransmission timer */ +struct nas_timer_t T3460; /* Authentication timer */ +struct nas_timer_t T3470; /* Identification timer */ + +/* + * mobile reachable timer + * ---------------------- + * The network supervises the periodic tracking area updating procedure + * of the UE by means of the mobile reachable timer. + * If the UE is not attached for emergency bearer services, the mobile + * reachable timer is 4 minutes greater than T3412. + * If the UE is attached for emergency bearer services, the MME shall + * set the mobile reachable timer with a value equal to T3412. When + * the mobile reachable timer expires, the MME shall locally detach the UE. + * + * The mobile reachable timer shall be reset and started, when the MME + * releases the NAS signalling connection for the UE. The mobile reachable + * timer shall be stopped when a NAS signalling connection is established + * for the UE. + */ + +/* + * implicit detach timer + * --------------------- + * If ISR is activated, the default value of the implicit detach timer is + * 4 minutes greater than T3423. + * If the implicit detach timer expires before the UE contacts the network, + * the network shall implicitly detach the UE. + * If the MME includes timer T3346 in the TRACKING AREA UPDATE REJECT message + * or the SERVICE REJECT message and T3346 is greater than T3412, the MME + * sets the mobile reachable timer and the implicit detach timer such that + * the sum of the timer values is greater than T3346. + * + * Upon expiry of the mobile reachable timer the network shall start the + * implicit detach timer. The implicit detach timer shall be stopped when + * a NAS signalling connection is established for the UE. + */ +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __EMMDATA_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/emm_data_ctx.c b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_data_ctx.c new file mode 100644 index 0000000000..91cf130c71 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_data_ctx.c @@ -0,0 +1,59 @@ + +#include <stdlib.h> +#include <string.h> + +#if defined(EPC_BUILD) && defined(NAS_MME) +#include "assertions.h" +#include "tree.h" +#include "emmData.h" + +static inline +int emm_data_ctxt_compare_ueid(struct emm_data_context_s *p1, + struct emm_data_context_s *p2); + +RB_PROTOTYPE(emm_data_context_map, emm_data_context_s, entries, + emm_data_ctxt_compare_ueid); + +/* Generate functions used for the MAP */ +RB_GENERATE(emm_data_context_map, emm_data_context_s, entries, + emm_data_ctxt_compare_ueid); + +static inline +int emm_data_ctxt_compare_ueid(struct emm_data_context_s *p1, + struct emm_data_context_s *p2) +{ + if (p1->ueid > p2->ueid) { + return 1; + } + if (p1->ueid < p2->ueid) { + return -1; + } + /* Matching reference -> return 0 */ + return 0; +} + +struct emm_data_context_s *emm_data_context_get( + emm_data_t *emm_data, unsigned int _ueid) +{ + struct emm_data_context_s reference; + + DevAssert(emm_data != NULL); + DevCheck(_ueid > 0, _ueid, 0, 0); + + memset(&reference, 0, sizeof(struct emm_data_context_s)); + reference.ueid = _ueid; + return RB_FIND(emm_data_context_map, &emm_data->ctx_map, &reference); +} + +struct emm_data_context_s * emm_data_context_remove( + emm_data_t *emm_data, struct emm_data_context_s *elm) +{ + return RB_REMOVE(emm_data_context_map, &emm_data->ctx_map, elm); +} + +void emm_data_context_add(emm_data_t *emm_data, struct emm_data_context_s *elm) +{ + RB_INSERT(emm_data_context_map, &emm_data->ctx_map, elm); +} + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.c b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.c new file mode 100644 index 0000000000..6c0ad1bba1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.c @@ -0,0 +1,1049 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_main.c + +Version 0.1 + +Date 2012/10/10 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EPS Mobility Management procedure call manager, + the main entry point for elementary EMM processing. + +*****************************************************************************/ + +#include "emm_main.h" +#include "nas_log.h" +#include "emmData.h" + +#ifdef NAS_UE +#include "memory.h" +#include "usim_api.h" +#include "IdleMode.h" + +#include <string.h> // memset, memcpy, strlen +#include <stdio.h> // sprintf +#include <stdlib.h> // malloc, free +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +static int _emm_main_get_imei(imei_t* imei, const char* imei_str); + +static int _emm_main_imsi_cmp(imsi_t* imsi1, imsi_t* imsi2); + +static const char* _emm_main_get_plmn(const plmn_t* plmn, int index, + int format, size_t* size); + +static int _emm_main_get_plmn_index(const char* plmn, int format); + +/* + * USIM application data + */ +static usim_data_t _usim_data; + +/* + * Callback executed whenever a change in the network has to be notified + * to the user application + */ +static emm_indication_callback_t _emm_main_user_callback; +static int _emm_main_callback(int); +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_main_initialize() ** + ** ** + ** Description: Initializes EMM internal data ** + ** ** + ** Inputs: cb: The user notification callback ** + ** imei: The IMEI read from the UE's non-volatile ** + ** memory ** + ** Others: _usim_data ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +void emm_main_initialize(emm_indication_callback_t cb, const char* imei) +{ + LOG_FUNC_IN; + + /* USIM validity indicator */ + _emm_data.usim_is_valid = FALSE; + /* The IMEI read from the UE's non-volatile memory */ + _emm_data.imei = (imei_t*)malloc(sizeof(imei_t)); + _emm_data.imei->length = _emm_main_get_imei(_emm_data.imei, imei); + /* The IMSI, valid only if USIM is present */ + _emm_data.imsi = NULL; + /* EPS location information */ + _emm_data.guti = NULL; + _emm_data.tai = NULL; + _emm_data.ltai.n_tais = 0; + /* EPS Connection Management status */ + _emm_data.ecm_status = ECM_IDLE; + /* Network selection mode of operation */ + _emm_data.plmn_mode = EMM_DATA_PLMN_AUTO; + /* Index of the PLMN manually selected by the user */ + _emm_data.plmn_index = -1; + /* Selected Radio Access Technology */ + _emm_data.plmn_rat = NET_ACCESS_UNAVAILABLE; + /* Selected PLMN */ + memset(&_emm_data.splmn, 0xFF, sizeof(plmn_t)); + _emm_data.is_rplmn = FALSE; + _emm_data.is_eplmn = FALSE; + /* Radio Access Technology of the serving cell */ + _emm_data.rat = NET_ACCESS_UNAVAILABLE; + /* Network registration status */ + _emm_data.stat = NET_REG_STATE_OFF; + _emm_data.is_attached = FALSE; + _emm_data.is_emergency = FALSE; + /* Location/Tracking area code */ + _emm_data.tac = 0; // two byte in hexadecimal format + /* Identifier of the serving cell */ + _emm_data.ci = 0; // four byte in hexadecimal format + /* List of operators present in the network */ + memset(_emm_data.plist.buffer, 0, EMM_DATA_BUFFER_SIZE + 1); + /* Home PLMN */ + memset(&_emm_data.hplmn, 0xFF, sizeof(plmn_t)); + /* List of Forbidden PLMNs */ + _emm_data.fplmn.n_plmns = 0; + /* List of Forbidden PLMNs for GPRS service */ + _emm_data.fplmn_gprs.n_plmns = 0; + /* List of Equivalent HPLMNs */ + _emm_data.ehplmn.n_plmns = 0; + /* List of user controlled PLMNs */ + _emm_data.plmn.n_plmns = 0; + /* List of operator controlled PLMNs */ + _emm_data.oplmn.n_plmns = 0; + /* List of operator network name records */ + _emm_data.n_opnns = 0; + /* List of Forbidden Tracking Areas */ + _emm_data.ftai.n_tais = 0; + /* List of Forbidden Tracking Areas for roaming */ + _emm_data.ftai_roaming.n_tais = 0; + + /* + * Get USIM application data + */ + if ( usim_api_read(&_usim_data) != RETURNok ) { + /* The USIM application may not be present or not valid */ + LOG_TRACE(WARNING, "EMM-MAIN - Failed to read USIM application data"); + } + else + { + int i; + + /* The USIM application is present and valid */ + LOG_TRACE(INFO, "EMM-MAIN - USIM application data successfully read"); + _emm_data.usim_is_valid = TRUE; + + /* Get the Home PLMN derived from the IMSI */ + _emm_data.hplmn.MCCdigit1 = _usim_data.imsi.u.num.digit1; + _emm_data.hplmn.MCCdigit2 = _usim_data.imsi.u.num.digit2; + _emm_data.hplmn.MCCdigit3 = _usim_data.imsi.u.num.digit3; + _emm_data.hplmn.MNCdigit1 = _usim_data.imsi.u.num.digit4; + _emm_data.hplmn.MNCdigit2 = _usim_data.imsi.u.num.digit5; + _emm_data.hplmn.MNCdigit3 = _usim_data.imsi.u.num.digit6; + + /* Get the list of forbidden PLMNs */ + for (i=0; (i < EMM_DATA_FPLMN_MAX) && (i < USIM_FPLMN_MAX); i++) { + if ( PLMN_IS_VALID(_usim_data.fplmn[i]) ) { + _emm_data.fplmn.plmn[i] = _usim_data.fplmn[i]; + _emm_data.fplmn.n_plmns += 1; + } + } + + /* Get the list of Equivalent HPLMNs */ + for (i=0; (i < EMM_DATA_EHPLMN_MAX) && (i < USIM_EHPLMN_MAX); i++) { + if ( PLMN_IS_VALID(_usim_data.ehplmn[i]) ) { + _emm_data.ehplmn.plmn[i] = _usim_data.ehplmn[i]; + _emm_data.ehplmn.n_plmns += 1; + } + } + + /* Get the list of User controlled PLMN Selector */ + for (i=0; (i < EMM_DATA_PLMN_MAX) && (i < USIM_PLMN_MAX); i++) { + if ( PLMN_IS_VALID(_usim_data.plmn[i].plmn) ) { + _emm_data.plmn.plmn[i] = _usim_data.plmn[i].plmn; + _emm_data.userAcT[i] = _usim_data.plmn[i].AcT; + _emm_data.plmn.n_plmns += 1; + } + } + + /* Get the list of Operator controlled PLMN Selector */ + for (i=0; (i < EMM_DATA_OPLMN_MAX) && (i < USIM_OPLMN_MAX); i++) { + if ( PLMN_IS_VALID(_usim_data.oplmn[i].plmn) ) { + _emm_data.oplmn.plmn[i] = _usim_data.oplmn[i].plmn; + _emm_data.operAcT[i] = _usim_data.oplmn[i].AcT; + _emm_data.oplmn.n_plmns += 1; + } + } + + /* Get the list of Operator network name records */ + for (i=0; (i < EMM_DATA_OPNN_MAX) && (i < USIM_OPL_MAX); i++) { + if ( PLMN_IS_VALID(_usim_data.opl[i].plmn) ) { + int pnn_id = _usim_data.opl[i].record_id; + _emm_data.opnn[i].plmn = &_usim_data.opl[i].plmn; + _emm_data.opnn[i].fullname = (char*)_usim_data.pnn[pnn_id].fullname.value; + _emm_data.opnn[i].shortname = (char*)_usim_data.pnn[pnn_id].shortname.value; + _emm_data.n_opnns += 1; + } + } + + /* TODO: Get the Higher Priority PLMN search period parameter */ + + /* Get the EPS location information */ + if (PLMN_IS_VALID(_usim_data.epsloci.guti.gummei.plmn)) { + _emm_data.guti = &_usim_data.epsloci.guti; + } + if (TAI_IS_VALID(_usim_data.epsloci.tai)) { + _emm_data.tai = &_usim_data.epsloci.tai; + } + _emm_data.status = _usim_data.epsloci.status; + + /* Get NAS configuration parameters */ + _emm_data.NAS_SignallingPriority = _usim_data.nasconfig.NAS_SignallingPriority.value[0]; + _emm_data.NMO_I_Behaviour = _usim_data.nasconfig.NMO_I_Behaviour.value[0]; + _emm_data.AttachWithImsi = _usim_data.nasconfig.AttachWithImsi.value[0]; + _emm_data.MinimumPeriodicSearchTimer = _usim_data.nasconfig.MinimumPeriodicSearchTimer.value[0]; + _emm_data.ExtendedAccessBarring = _usim_data.nasconfig.ExtendedAccessBarring.value[0]; + _emm_data.Timer_T3245_Behaviour = _usim_data.nasconfig.Timer_T3245_Behaviour.value[0]; + + /* + * Get EPS NAS security context + */ + /* Create NAS security context */ + _emm_data.security = + (emm_security_context_t*)malloc(sizeof(emm_security_context_t)); + if (_emm_data.security != NULL) { + memset(_emm_data.security, 0, sizeof(emm_security_context_t)); + /* Type of security context */ + if (_usim_data.securityctx.KSIasme.value[0] != + USIM_KSI_NOT_AVAILABLE) { + _emm_data.security->type = EMM_KSI_NATIVE; + } + else { + _emm_data.security->type = EMM_KSI_NOT_AVAILABLE; + } + /* EPS key set identifier */ + _emm_data.security->eksi = _usim_data.securityctx.KSIasme.value[0]; + /* ASME security key */ + _emm_data.security->kasme.length = + _usim_data.securityctx.Kasme.length; + _emm_data.security->kasme.value = + (uint8_t*)malloc(_emm_data.security->kasme.length); + if (_emm_data.security->kasme.value) { + memcpy(_emm_data.security->kasme.value, + _usim_data.securityctx.Kasme.value, + _emm_data.security->kasme.length); + } + /* Downlink count parameter */ + if (_usim_data.securityctx.dlNAScount.length <= sizeof(UInt32_t)) { + memcpy(&_emm_data.security->dl_count, + _usim_data.securityctx.dlNAScount.value, + _usim_data.securityctx.dlNAScount.length); + } + /* Uplink count parameter */ + if (_usim_data.securityctx.ulNAScount.length <= sizeof(UInt32_t)) { + memcpy(&_emm_data.security->ul_count, + _usim_data.securityctx.ulNAScount.value, + _usim_data.securityctx.ulNAScount.length); + } + /* Ciphering algorithm */ + _emm_data.security->capability.encryption = + ((_usim_data.securityctx.algorithmID.value[0] >> 4) & 0xf); + /* Identity protection algorithm */ + _emm_data.security->capability.integrity = + (_usim_data.securityctx.algorithmID.value[0] & 0xf); + /* NAS integrity and cyphering keys are not available */ + } + else { + LOG_TRACE(WARNING, + "EMM-PROC - Failed to create security context"); + } + + /* + * Get EMM data from the UE's non-volatile memory + */ + memset(&_emm_data.nvdata.rplmn, 0xFF, sizeof(plmn_t)); + _emm_data.nvdata.eplmn.n_plmns = 0; + /* Get EMM data pathname */ + char* path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); + if (path == NULL) { + LOG_TRACE(ERROR, "EMM-MAIN - Failed to get EMM data pathname"); + } + else { + /* Get EMM data stored in the non-volatile memory device */ + int rc = memory_read(path, &_emm_data.nvdata, sizeof(emm_nvdata_t)); + if (rc != RETURNok) { + LOG_TRACE(ERROR, "EMM-MAIN - Failed to read %s", path); + } + else { + /* Check the IMSI */ + LOG_TRACE(INFO, "EMM-MAIN - EMM data successfully read"); + _emm_data.imsi = &_usim_data.imsi; + int imsi_ok = _emm_main_imsi_cmp(&_emm_data.nvdata.imsi, + &_usim_data.imsi); + if (!imsi_ok) { + LOG_TRACE(WARNING, "EMM-MAIN - IMSI checking failed"); + memset(&_emm_data.nvdata.rplmn, 0xFF, sizeof(plmn_t)); + _emm_data.nvdata.eplmn.n_plmns = 0; + } + } + free(path); + } + } + + /* + * Initialize EMM timers + */ + T3410.id = NAS_TIMER_INACTIVE_ID; + T3410.sec = T3410_DEFAULT_VALUE; + T3411.id = NAS_TIMER_INACTIVE_ID; + T3411.sec = T3411_DEFAULT_VALUE; + T3402.id = NAS_TIMER_INACTIVE_ID; + T3402.sec = T3402_DEFAULT_VALUE; + T3416.id = NAS_TIMER_INACTIVE_ID; + T3416.sec = T3416_DEFAULT_VALUE; + T3417.id = NAS_TIMER_INACTIVE_ID; + T3417.sec = T3417_DEFAULT_VALUE; + T3418.id = NAS_TIMER_INACTIVE_ID; + T3418.sec = T3418_DEFAULT_VALUE; + T3420.id = NAS_TIMER_INACTIVE_ID; + T3420.sec = T3420_DEFAULT_VALUE; + T3421.id = NAS_TIMER_INACTIVE_ID; + T3421.sec = T3421_DEFAULT_VALUE; + T3423.id = NAS_TIMER_INACTIVE_ID; + T3423.sec = T3423_DEFAULT_VALUE; + T3430.id = NAS_TIMER_INACTIVE_ID; + T3430.sec = T3430_DEFAULT_VALUE; + + /* + * Initialize the user notification callback + */ + _emm_main_user_callback = *cb; + + /* + * Initialize EMM internal data used for UE in idle mode + */ + IdleMode_initialize(&_emm_main_callback); + + LOG_FUNC_OUT; +} +#endif +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_main_initialize() ** + ** ** + ** Description: Initializes EMM internal data ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +void emm_main_initialize(void) +{ + LOG_FUNC_IN; + + /* Retreive MME supported configuration data */ + if (mme_api_get_emm_config(&_emm_data.conf) != RETURNok) { + LOG_TRACE(ERROR, "EMM-MAIN - Failed to get MME configuration data"); + } + +#if defined(EPC_BUILD) + RB_INIT(&_emm_data.ctx_map); +#endif + + /* + * Initialize EMM timers + */ + T3450.id = NAS_TIMER_INACTIVE_ID; + T3450.sec = T3450_DEFAULT_VALUE; + T3460.id = NAS_TIMER_INACTIVE_ID; + T3460.sec = T3460_DEFAULT_VALUE; + T3470.id = NAS_TIMER_INACTIVE_ID; + T3470.sec = T3470_DEFAULT_VALUE; + + LOG_FUNC_OUT; +} +#endif + +/**************************************************************************** + ** ** + ** Name: emm_main_cleanup() ** + ** ** + ** Description: Performs the EPS Mobility Management clean up procedure ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void emm_main_cleanup(void) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + + if (_emm_data.usim_is_valid) { + /* + * TODO: Update USIM application data + */ +#if 0 + int i; + /* Update the list of Forbidden PLMNs */ + for (i=0; (i < _emm_data.fplmn.n_plmns) && (i < USIM_FPLMN_MAX); i++) + { + _usim_data.fplmn[i] = _emm_data.fplmn.plmn[i]; + } + /* Update the list of Equivalent HPLMNs */ + for (i=0; (i < _emm_data.ehplmn.n_plmns) && (i < USIM_EHPLMN_MAX); i++) + { + _usim_data.ehplmn[i] = _emm_data.ehplmn.plmn[i]; + } + /* Update the GUTI */ + if (_emm_data.guti) { + _usim_data.epsloci.guti = *(_emm_data.guti); + } + /* Update the last visited registered TAI */ + if (_emm_data.tai) { + _usim_data.epsloci.tai = *(_emm_data.tai); + } + /* Update the EPS location information */ + _usim_data.epsloci.status = _emm_data.status; + + if (_emm_data.security && (_emm_data.security->type == EMM_KSI_NATIVE)) + { + /* TODO: Update the EPS security context parameters from the full + * native EPS security context */ + } + + /* + * Store USIM application data + * - List of forbidden PLMNs + */ + if ( usim_api_write(&_usim_data) != RETURNok ) { + /* The USIM application may not be present or not valid */ + LOG_TRACE(WARNING, "EMM-MAIN - " + "Failed to write USIM application data"); + } +#endif + } + + /* + * Store EMM data into the UE's non-volatile memory + * - Registered PLMN + * - List of equivalent PLMNs + */ + char* path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); + if (path == NULL) { + LOG_TRACE(ERROR, "EMM-MAIN - Failed to get EMM data pathname"); + } + else { + int rc = memory_write(path, &_emm_data.nvdata, sizeof(emm_nvdata_t)); + if (rc != RETURNok) { + LOG_TRACE(ERROR, "EMM-MAIN - Failed to write %s", path); + } + } + + /* Release dynamically allocated memory */ + if (_emm_data.imei) { + free(_emm_data.imei); + _emm_data.imei = NULL; + } + if (_emm_data.security) { + emm_security_context_t* security = _emm_data.security; + if (security->kasme.value) free(security->kasme.value); + if (security->knas_enc.value) free(security->knas_enc.value); + if (security->knas_int.value) free(security->knas_int.value); + free(_emm_data.security); + _emm_data.security = NULL; + } + +#endif // NAS_UE + + LOG_FUNC_OUT; +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_main_get_imsi() ** + ** ** + ** Description: Get the International Mobile Subscriber Identity number ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: Pointer to the IMSI ** + ** Others: None ** + ** ** + ***************************************************************************/ +const imsi_t* emm_main_get_imsi(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (&_emm_data.nvdata.imsi); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_msisdn() ** + ** ** + ** Description: Get the Mobile Subscriber Dialing Number from the USIM ** + ** ** + ** Inputs: None ** + ** Others: _usim_data ** + ** ** + ** Outputs: None ** + ** Return: Pointer to the subscriber dialing number ** + ** Others: None ** + ** ** + ***************************************************************************/ +const msisdn_t* emm_main_get_msisdn(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (&_usim_data.msisdn.number); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_set_plmn_selection_mode() ** + ** ** + ** Description: Set the network selection mode of operation to the given ** + ** mode and update the manually selected network selection ** + ** data ** + ** ** + ** Inputs: mode: The specified network selection mode of ** + ** operation ** + ** format: The representation format of the PLMN ** + ** identifier ** + ** plmn: Identifier of the selected PLMN ** + ** rat: The selected Radio Access Techonology ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_data ** + ** ** + ***************************************************************************/ +int emm_main_set_plmn_selection_mode(int mode, int format, + const network_plmn_t* plmn, int rat) +{ + LOG_FUNC_IN; + + int index; + + LOG_TRACE(INFO, "EMM-MAIN - PLMN selection: mode=%d, format=%d, plmn=%s, " + "rat=%d", mode, format, (const char*)&plmn->id, rat); + + _emm_data.plmn_mode = mode; + + if (mode != EMM_DATA_PLMN_AUTO) { + /* Get the index of the PLMN in the list of available PLMNs */ + index = _emm_main_get_plmn_index((const char*)&plmn->id, format); + if (index < 0) { + LOG_TRACE(WARNING, "EMM-MAIN - PLMN %s not available", + (const char*)&plmn->id); + } + else { + /* Update the manually selected network selection data */ + _emm_data.plmn_index = index; + _emm_data.plmn_rat = rat; + } + } + else { + /* + * Get the index of the last PLMN the UE already tried to automatically + * register to when switched on; the equivalent PLMNs list shall not be + * applied to the user reselection in Automatic Network Selection Mode. + */ + index = IdleMode_get_hplmn_index(); + } + + LOG_FUNC_RETURN (index); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_selection_mode() ** + ** ** + ** Description: Get the current value of the network selection mode of ** + ** operation ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The value of the network selection mode ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_main_get_plmn_selection_mode(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.plmn_mode); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_list() ** + ** ** + ** Description: Get the list of available PLMNs ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: plist: Pointer to the list of available PLMNs ** + ** Return: The size of the list in bytes ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_main_get_plmn_list(const char** plist) +{ + LOG_FUNC_IN; + + int size = IdleMode_update_plmn_list(0); + *plist = _emm_data.plist.buffer; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_selected_plmn() ** + ** ** + ** Description: Get the identifier of the currently selected PLMN ** + ** ** + ** Inputs: format: The requested format of the string repre- ** + ** sentation of the PLMN identifier ** + ** Others: _emm_data ** + ** ** + ** Outputs: plmn: The selected PLMN identifier coded in the ** + ** requested format ** + ** Return: A pointer to the string representation of ** + ** the selected PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* emm_main_get_selected_plmn(network_plmn_t* plmn, int format) +{ + LOG_FUNC_IN; + + size_t size = 0; + /* + * Get the identifier of the selected PLMN in the list of available PLMNs + */ + int index = IdleMode_get_splmn_index(); + if ( !(index < 0) ) { + const char* name = _emm_main_get_plmn(&_emm_data.splmn, index, + format, &size); + if (size > 0) { + LOG_FUNC_RETURN ((char*) memcpy(&plmn->id, name, size)); + } + } + + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_registered_plmn() ** + ** ** + ** Description: Get the identifier of the currently registered PLMN ** + ** ** + ** Inputs: format: The requested format of the string repre- ** + ** sentation of the PLMN identifier ** + ** Others: _emm_data ** + ** ** + ** Outputs: plmn: The registered PLMN identifier coded in ** + ** the requested format ** + ** Return: A pointer to the string representation of ** + ** the registered PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* emm_main_get_registered_plmn(network_plmn_t* plmn, int format) +{ + LOG_FUNC_IN; + + size_t size = 0; + + /* + * Get the identifier of the registered PLMN in the list of available PLMNs + */ + int index = IdleMode_get_rplmn_index(); + if ( !(index < 0) ) { + const char* name = _emm_main_get_plmn(&_emm_data.nvdata.rplmn, + index, format, &size); + if (size > 0) { + LOG_FUNC_RETURN ((char*) memcpy(&plmn->id, name, size)); + } + } + + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_status() ** + ** ** + ** Description: Get the value of the network registration status which ** + ** shows whether the network has currently indicated the ** + ** registration of the UE ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The current network registration status ** + ** Others: None ** + ** ** + ***************************************************************************/ +Stat_t emm_main_get_plmn_status(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.stat); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_tac() ** + ** ** + ** Description: Get the code of the Tracking area the registered PLMN ** + ** belongs to ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The Location/Tracking area code ** + ** Others: None ** + ** ** + ***************************************************************************/ +tac_t emm_main_get_plmn_tac(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.tac); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_ci() ** + ** ** + ** Description: Get the identifier of the serving cell ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The serving cell identifier ** + ** Others: None ** + ** ** + ***************************************************************************/ +ci_t emm_main_get_plmn_ci(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.ci); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_rat() ** + ** ** + ** Description: Get the value of the Radio Access Technology of the ser- ** + ** ving cell ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: The value of the Radio Access Technology ** + ** of the serving cell ** + ** Others: None ** + ** ** + ***************************************************************************/ +AcT_t emm_main_get_plmn_rat(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.rat); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_is_attached() ** + ** ** + ** Description: Indicates whether the UE is currently attached to the ** + ** network for EPS services or emergency service only ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: TRUE if the UE is currently attached to ** + ** the network; FALSE otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_main_is_attached(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.is_attached); +} + +/**************************************************************************** + ** ** + ** Name: emm_main_get_plmn_rat() ** + ** ** + ** Description: Indicates whether the UE is currently attached to the ** + ** network for emergency bearer services ** + ** ** + ** Inputs: None ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: TRUE if the UE is currently attached or is ** + ** attempting to attach to the network for ** + ** emergency bearer services; FALSE otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_main_is_emergency(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN (_emm_data.is_attached && _emm_data.is_emergency); +} +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _emm_main_callback() ** + ** ** + ** Description: Forwards the network indication to the upper control la- ** + ** yer (user API) to notify that network registration and/or ** + ** location information has changed. ** + ** ** + ** Inputs: size: Size in byte of the list of operators ** + ** present in the network. The list has to be ** + ** displayed to the user application when ** + ** size > 0. ** + ** Others: _emm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_main_callback(int size) +{ + LOG_FUNC_IN; + + /* Forward the notification to the user API */ + int rc = (*_emm_main_user_callback)(_emm_data.stat, _emm_data.tac, + _emm_data.ci, _emm_data.rat, + _emm_data.plist.buffer, size); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_main_get_imei() ** + ** ** + ** Description: Returns the International Mobile Equipment Identity con- ** + ** tained in the given string representation ** + ** ** + ** Inputs: imei: The string representation of the IMEI ** + ** Others: None ** + ** ** + ** Outputs: imei: The IMEI of the UE ** + ** Return: The number of digits in the IMEI ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_main_get_imei(imei_t* imei, const char* imei_str) +{ + int len = strlen(imei_str); + if (len % 2) { + imei->u.num.parity = ODD_PARITY; + } else { + imei->u.num.parity = EVEN_PARITY; + } + imei->u.num.digit1 = imei_str[0] - '0'; + imei->u.num.digit2 = imei_str[1] - '0'; + imei->u.num.digit3 = imei_str[2] - '0'; + imei->u.num.digit4 = imei_str[3] - '0'; + imei->u.num.digit5 = imei_str[4] - '0'; + imei->u.num.digit6 = imei_str[5] - '0'; + imei->u.num.digit7 = imei_str[6] - '0'; + imei->u.num.digit8 = imei_str[7] - '0'; + imei->u.num.digit9 = imei_str[8] - '0'; + imei->u.num.digit10 = imei_str[9] - '0'; + imei->u.num.digit11 = imei_str[10] - '0'; + imei->u.num.digit12 = imei_str[11] - '0'; + imei->u.num.digit13 = imei_str[12] - '0'; + imei->u.num.digit14 = imei_str[13] - '0'; + imei->u.num.digit15 = imei_str[14] - '0'; + return (len); +} + +/**************************************************************************** + ** ** + ** Name: _emm_main_imsi_cmp() ** + ** ** + ** Description: Compares two International Mobile Subscriber Identifiers ** + ** ** + ** Inputs: imsi1: The first IMSI ** + ** imsi2: The second IMSI to compare to ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE if the first IMSI is found to match ** + ** the second; FALSE otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_main_imsi_cmp(imsi_t* imsi1, imsi_t* imsi2) +{ + if (imsi1->length != imsi2->length) { + return FALSE; + } + for (int i = 0; i < imsi1->length; i++) { + if (imsi1->u.value[i] != imsi2->u.value[i]) { + return FALSE; + } + } + return TRUE; +} + +/**************************************************************************** + ** ** + ** Name: _emm_main_get_plmn() ** + ** ** + ** Description: Get the identifier of the PLMN at the given index in the ** + ** list of available PLMNs. ** + ** ** + ** Inputs: plmn: The PLMN to search for ** + ** index: The index of the PLMN in the list of PLMNs ** + ** format: The requested representation format of the ** + ** PLMN identifier ** + ** Others: None ** + ** ** + ** Outputs: size: The size in bytes of the PLMN identifier ** + ** coded in the requested format ** + ** Return: A pointer to the identifier of the PLMN ** + ** Others: None ** + ** ** + ***************************************************************************/ +static const char* _emm_main_get_plmn(const plmn_t* plmn, int index, + int format, size_t* size) +{ + if ( PLMN_IS_VALID(*plmn) ) { + switch (format) + { + case NET_FORMAT_LONG: + /* Get the long alpha-numeric representation of the PLMN */ + return IdleMode_get_plmn_fullname(plmn, index, size); + break; + + case NET_FORMAT_SHORT: + /* Get the short alpha-numeric representation of the PLMN */ + return IdleMode_get_plmn_shortname(plmn, index, size); + break; + + case NET_FORMAT_NUM: + /* Get the numeric representation of the PLMN */ + return IdleMode_get_plmn_id(plmn, index, size); + break; + + default: + LOG_TRACE(WARNING, "EMM-MAIN - Format is not valid (%d)", + format); + *size = 0; + break; + } + } + return (NULL); +} + +/**************************************************************************** + ** ** + ** Name: _emm_main_get_plmn_index() ** + ** ** + ** Description: Get the index of the given PLMN in the ordered list of ** + ** available PLMNs ** + ** ** + ** Inputs: plmn: Identifier of the PLMN ** + ** format: The representation format of the PLMN ** + ** identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The index of the selected PLMN in the list ** + ** of available PLMNs; -1 if the PLMN is not ** + ** found ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_main_get_plmn_index(const char* plmn, int format) +{ + int index = -1; + switch (format) + { + case NET_FORMAT_LONG: + /* Get the index of the long alpha-numeric PLMN identifier */ + index = IdleMode_get_plmn_fullname_index(plmn); + break; + + case NET_FORMAT_SHORT: + /* Get the index of the short alpha-numeric PLMN identifier */ + index = IdleMode_get_plmn_shortname_index(plmn); + break; + + case NET_FORMAT_NUM: + /* Get the index of the numeric PLMN identifier */ + index = IdleMode_get_plmn_id_index(plmn); + break; + + default: + LOG_TRACE(WARNING, "EMM-MAIN - Format is not valid (%d)", format); + break; + } + return (index); +} +#endif // NAS_UE + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.h b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.h new file mode 100644 index 0000000000..668e1a76ca --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_main.h @@ -0,0 +1,79 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_main.h + +Version 0.1 + +Date 2012/10/10 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EPS Mobility Management procedure call manager, + the main entry point for elementary EMM processing. + +*****************************************************************************/ +#ifndef __EMM_MAIN_H__ +#define __EMM_MAIN_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +void emm_main_initialize(emm_indication_callback_t cb, const char* imei); +#endif +#ifdef NAS_MME +void emm_main_initialize(void); +#endif +void emm_main_cleanup(void); + +#ifdef NAS_UE + +/* User's getter of UE's identity */ +const imsi_t* emm_main_get_imsi(void); + +/* User's getter of the subscriber dialing number */ +const msisdn_t* emm_main_get_msisdn(void); + +/* User's getter/setter for network selection */ +int emm_main_set_plmn_selection_mode(int mode, int format, + const network_plmn_t* plmn, int rat); +int emm_main_get_plmn_selection_mode(void); +int emm_main_get_plmn_list(const char** plist); +const char* emm_main_get_selected_plmn(network_plmn_t* plmn, int format); + +/* User's getter for network registration */ +Stat_t emm_main_get_plmn_status(void); +tac_t emm_main_get_plmn_tac(void); +ci_t emm_main_get_plmn_ci(void); +AcT_t emm_main_get_plmn_rat(void); +const char* emm_main_get_registered_plmn(network_plmn_t* plmn, int format); + +/* User's getter for network attachment */ +int emm_main_is_attached(void); +int emm_main_is_emergency(void); + +#endif // NAS_UE + +#endif /* __EMM_MAIN_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/emm_proc.h b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_proc.h new file mode 100644 index 0000000000..a3d7ccf65d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/emm_proc.h @@ -0,0 +1,224 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_proc.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EPS Mobility Management procedures executed at + the EMM Service Access Points. + +*****************************************************************************/ +#ifndef __EMM_PROC_H__ +#define __EMM_PROC_H__ + +#include "commonDef.h" +#include "OctetString.h" + +#ifdef NAS_MME +#include "EmmCommon.h" +#include "emmData.h" +#endif + +#ifdef NAS_UE +#include "LowerLayer.h" +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Type of network attachment */ +typedef enum { + EMM_ATTACH_TYPE_EPS = 0, + EMM_ATTACH_TYPE_IMSI, + EMM_ATTACH_TYPE_EMERGENCY, + EMM_ATTACH_TYPE_RESERVED, +} emm_proc_attach_type_t; + +/* Type of network detach */ +typedef enum { + EMM_DETACH_TYPE_EPS = 0, + EMM_DETACH_TYPE_IMSI, + EMM_DETACH_TYPE_EPS_IMSI, + EMM_DETACH_TYPE_REATTACH, + EMM_DETACH_TYPE_NOT_REATTACH, + EMM_DETACH_TYPE_RESERVED, +} emm_proc_detach_type_t; + +/* Type of requested identity */ +typedef enum { + EMM_IDENT_TYPE_NOT_AVAILABLE = 0, + EMM_IDENT_TYPE_IMSI, + EMM_IDENT_TYPE_IMEI, + EMM_IDENT_TYPE_IMEISV, + EMM_IDENT_TYPE_TMSI +} emm_proc_identity_type_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + *--------------------------------------------------------------------------- + * EMM status procedure + *--------------------------------------------------------------------------- + */ +int emm_proc_status_ind(unsigned int ueid, int emm_cause); +int emm_proc_status(unsigned int ueid, int emm_cause); + +/* + *--------------------------------------------------------------------------- + * Lower layer procedure + *--------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_lowerlayer_initialize(lowerlayer_success_callback_t success, + lowerlayer_failure_callback_t failure, + lowerlayer_release_callback_t release, + void* args); +int emm_proc_lowerlayer_success(void); +int emm_proc_lowerlayer_failure(int is_initial); +int emm_proc_lowerlayer_release(void); +#endif + +/* + *--------------------------------------------------------------------------- + * UE's Idle mode procedure + *--------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_initialize(void); +int emm_proc_plmn_selection(int index); +int emm_proc_plmn_selection_end(int found, tac_t tac, ci_t ci, AcT_t rat); +#endif + +/* + * -------------------------------------------------------------------------- + * Attach procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_attach(emm_proc_attach_type_t type); +int emm_proc_attach_request(void* args); +int emm_proc_attach_accept(long T3412, long T3402, long T3423, int n_tais, tai_t* tai, GUTI_t* guti, int n_eplmns, plmn_t* eplmn, const OctetString* esm_msg); +int emm_proc_attach_reject(int emm_cause, const OctetString* esm_msg); +int emm_proc_attach_complete(void* args); +int emm_proc_attach_failure(int is_initial, void* args); +int emm_proc_attach_release(void* args); +int emm_proc_attach_restart(void); + +int emm_proc_attach_set_emergency(void); +int emm_proc_attach_set_detach(void); +#endif + +#ifdef NAS_MME +int emm_proc_attach_request(unsigned int ueid, emm_proc_attach_type_t type, int native_ksi, int ksi, int native_guti, GUTI_t* guti, imsi_t* imsi, imei_t* imei, tai_t* tai, int eea, int eia, const OctetString* esm_msg); +int emm_proc_attach_reject(unsigned int ueid, int emm_cause); +int emm_proc_attach_complete(unsigned int ueid, const OctetString* esm_msg); +#endif + +/* + * -------------------------------------------------------------------------- + * Detach procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_detach(emm_proc_detach_type_t type, int switch_off); +int emm_proc_detach_request(void* args); +int emm_proc_detach_accept(void); +int emm_proc_detach_failure(int is_initial, void* args); +int emm_proc_detach_release(void* args); +#endif + +#ifdef NAS_MME +int emm_proc_detach(unsigned int ueid, emm_proc_detach_type_t type); +int emm_proc_detach_request(unsigned int ueid, emm_proc_detach_type_t type, int switch_off, int native_ksi, int ksi, GUTI_t* guti, imsi_t* imsi, imei_t* imei); +#endif + +/* + * -------------------------------------------------------------------------- + * Identification procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_identification_request(emm_proc_identity_type_t type); +#endif + +#ifdef NAS_MME +int emm_proc_identification(unsigned int ueid, + emm_data_context_t *emm_ctx, + emm_proc_identity_type_t type, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure); +int emm_proc_identification_complete(unsigned int ueid, const imsi_t* imsi, const imei_t* imei, UInt32_t* tmsi); +#endif + +/* + * -------------------------------------------------------------------------- + * Authentication procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_authentication_request(int native_ksi, int ksi, const OctetString* rand, const OctetString* autn); +int emm_proc_authentication_reject(void); +int emm_proc_authentication_delete(void); +#endif + +#ifdef NAS_MME +int emm_proc_authentication(unsigned int ueid, int ksi, + const OctetString* rand, const OctetString* autn, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure); +int emm_proc_authentication_complete(unsigned int ueid, int emm_cause, const OctetString* res); +#endif + +/* + * -------------------------------------------------------------------------- + * Security mode control procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_security_mode_command(int native_ksi, int ksi, int seea, int seia, int reea, int reia); +#endif + +#ifdef NAS_MME +int emm_proc_security_mode_control(unsigned int ueid, int ksi, int eea, int eia, + emm_common_success_callback_t success, + emm_common_reject_callback_t reject, + emm_common_failure_callback_t failure); +int emm_proc_security_mode_complete(unsigned int ueid); +int emm_proc_security_mode_reject(unsigned int ueid); +#endif + +/* + *--------------------------------------------------------------------------- + * Network indication handlers + *--------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_proc_registration_notify(Stat_t status); +int emm_proc_location_notify(tac_t tac, ci_t ci, AcT_t rat); +int emm_proc_network_notify(int index); +#endif + +#endif /* __EMM_PROC_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.c new file mode 100644 index 0000000000..04a4e82b88 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.c @@ -0,0 +1,310 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AttachAccept.h" + +int decode_attach_accept(attach_accept_msg *attach_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ATTACH_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_eps_attach_result(&attach_accept->epsattachresult, 0, *(buffer + decoded), len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_gprs_timer(&attach_accept->t3412value, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_tracking_area_identity_list(&attach_accept->tailist, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_esm_message_container(&attach_accept->esmmessagecontainer, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ATTACH_ACCEPT_GUTI_IEI: + if ((decoded_result = + decode_eps_mobile_identity(&attach_accept->guti, + ATTACH_ACCEPT_GUTI_IEI, buffer + decoded, len - decoded)) + <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_GUTI_PRESENT; + break; + case ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI: + if ((decoded_result = + decode_location_area_identification(&attach_accept->locationareaidentification, + ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT; + break; + case ATTACH_ACCEPT_MS_IDENTITY_IEI: + if ((decoded_result = + decode_mobile_identity(&attach_accept->msidentity, + ATTACH_ACCEPT_MS_IDENTITY_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_MS_IDENTITY_PRESENT; + break; + case ATTACH_ACCEPT_EMM_CAUSE_IEI: + if ((decoded_result = decode_emm_cause(&attach_accept->emmcause, + ATTACH_ACCEPT_EMM_CAUSE_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_EMM_CAUSE_PRESENT; + break; + case ATTACH_ACCEPT_T3402_VALUE_IEI: + if ((decoded_result = + decode_gprs_timer(&attach_accept->t3402value, + ATTACH_ACCEPT_T3402_VALUE_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_T3402_VALUE_PRESENT; + break; + case ATTACH_ACCEPT_T3423_VALUE_IEI: + if ((decoded_result = + decode_gprs_timer(&attach_accept->t3423value, + ATTACH_ACCEPT_T3423_VALUE_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_T3423_VALUE_PRESENT; + break; + case ATTACH_ACCEPT_EQUIVALENT_PLMNS_IEI: + if ((decoded_result = + decode_plmn_list(&attach_accept->equivalentplmns, + ATTACH_ACCEPT_EQUIVALENT_PLMNS_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_EQUIVALENT_PLMNS_PRESENT; + break; + case ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_IEI: + if ((decoded_result = + decode_emergency_number_list(&attach_accept->emergencynumberlist, + ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT; + break; + case ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI: + if ((decoded_result = + decode_eps_network_feature_support(&attach_accept->epsnetworkfeaturesupport, + ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT; + break; + case ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI: + if ((decoded_result = + decode_additional_update_result(&attach_accept->additionalupdateresult, + ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_accept->presencemask |= ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_attach_accept(attach_accept_msg *attach_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ATTACH_ACCEPT_MINIMUM_LENGTH, len); + + *(buffer + encoded) = (encode_u8_eps_attach_result(&attach_accept->epsattachresult) & 0x0f); + encoded++; + if ((encode_result = encode_gprs_timer(&attach_accept->t3412value, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_tracking_area_identity_list(&attach_accept->tailist, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_esm_message_container(&attach_accept->esmmessagecontainer, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((attach_accept->presencemask & ATTACH_ACCEPT_GUTI_PRESENT) + == ATTACH_ACCEPT_GUTI_PRESENT) + { + if ((encode_result = encode_eps_mobile_identity(&attach_accept->guti, + ATTACH_ACCEPT_GUTI_IEI, buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT) + == ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT) + { + if ((encode_result = + encode_location_area_identification(&attach_accept->locationareaidentification, + ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_MS_IDENTITY_PRESENT) + == ATTACH_ACCEPT_MS_IDENTITY_PRESENT) + { + if ((encode_result = encode_mobile_identity(&attach_accept->msidentity, + ATTACH_ACCEPT_MS_IDENTITY_IEI, buffer + encoded, len - encoded)) < + 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_EMM_CAUSE_PRESENT) + == ATTACH_ACCEPT_EMM_CAUSE_PRESENT) + { + if ((encode_result = encode_emm_cause(&attach_accept->emmcause, + ATTACH_ACCEPT_EMM_CAUSE_IEI, buffer + encoded, len - encoded)) < + 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_T3402_VALUE_PRESENT) + == ATTACH_ACCEPT_T3402_VALUE_PRESENT) + { + if ((encode_result = encode_gprs_timer(&attach_accept->t3402value, + ATTACH_ACCEPT_T3402_VALUE_IEI, buffer + encoded, len - encoded)) < + 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_T3423_VALUE_PRESENT) + == ATTACH_ACCEPT_T3423_VALUE_PRESENT) + { + if ((encode_result = encode_gprs_timer(&attach_accept->t3423value, + ATTACH_ACCEPT_T3423_VALUE_IEI, buffer + encoded, len - encoded)) < + 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_EQUIVALENT_PLMNS_PRESENT) + == ATTACH_ACCEPT_EQUIVALENT_PLMNS_PRESENT) + { + if ((encode_result = encode_plmn_list(&attach_accept->equivalentplmns, + ATTACH_ACCEPT_EQUIVALENT_PLMNS_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT) + == ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT) + { + if ((encode_result = + encode_emergency_number_list(&attach_accept->emergencynumberlist, + ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT) + == ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT) + { + if ((encode_result = + encode_eps_network_feature_support(&attach_accept->epsnetworkfeaturesupport, + ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_accept->presencemask & ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT) + == ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT) + { + if ((encode_result = + encode_additional_update_result(&attach_accept->additionalupdateresult, + ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h new file mode 100644 index 0000000000..112ff53b17 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h @@ -0,0 +1,110 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EpsAttachResult.h" +#include "GprsTimer.h" +#include "TrackingAreaIdentityList.h" +#include "EsmMessageContainer.h" +#include "EpsMobileIdentity.h" +#include "LocationAreaIdentification.h" +#include "MobileIdentity.h" +#include "EmmCause.h" +#include "PlmnList.h" +#include "EmergencyNumberList.h" +#include "EpsNetworkFeatureSupport.h" +#include "AdditionalUpdateResult.h" + +#ifndef ATTACH_ACCEPT_H_ +#define ATTACH_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ATTACH_ACCEPT_MINIMUM_LENGTH ( \ + EPS_ATTACH_RESULT_MINIMUM_LENGTH + \ + GPRS_TIMER_MINIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_LIST_MINIMUM_LENGTH + \ + ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ATTACH_ACCEPT_MAXIMUM_LENGTH ( \ + EPS_ATTACH_RESULT_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_LIST_MAXIMUM_LENGTH + \ + ESM_MESSAGE_CONTAINER_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + LOCATION_AREA_IDENTIFICATION_MAXIMUM_LENGTH + \ + MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + EMM_CAUSE_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + PLMN_LIST_MAXIMUM_LENGTH + \ + EMERGENCY_NUMBER_LIST_MAXIMUM_LENGTH + \ + EPS_NETWORK_FEATURE_SUPPORT_MAXIMUM_LENGTH + \ + ADDITIONAL_UPDATE_RESULT_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ATTACH_ACCEPT_GUTI_PRESENT (1<<0) +# define ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT (1<<1) +# define ATTACH_ACCEPT_MS_IDENTITY_PRESENT (1<<2) +# define ATTACH_ACCEPT_EMM_CAUSE_PRESENT (1<<3) +# define ATTACH_ACCEPT_T3402_VALUE_PRESENT (1<<4) +# define ATTACH_ACCEPT_T3423_VALUE_PRESENT (1<<5) +# define ATTACH_ACCEPT_EQUIVALENT_PLMNS_PRESENT (1<<6) +# define ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT (1<<7) +# define ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT (1<<8) +# define ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT (1<<9) + +typedef enum attach_accept_iei_tag { + ATTACH_ACCEPT_GUTI_IEI = 0x50, /* 0x50 = 80 */ + ATTACH_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI = 0x13, /* 0x13 = 19 */ + ATTACH_ACCEPT_MS_IDENTITY_IEI = 0x23, /* 0x23 = 35 */ + ATTACH_ACCEPT_EMM_CAUSE_IEI = 0x53, /* 0x53 = 83 */ + ATTACH_ACCEPT_T3402_VALUE_IEI = 0x17, /* 0x17 = 23 */ + ATTACH_ACCEPT_T3423_VALUE_IEI = 0x59, /* 0x59 = 89 */ + ATTACH_ACCEPT_EQUIVALENT_PLMNS_IEI = 0x4A, /* 0x4A = 74 */ + ATTACH_ACCEPT_EMERGENCY_NUMBER_LIST_IEI = 0x34, /* 0x34 = 52 */ + ATTACH_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI = 0x64, /* 0x64 = 100 */ + ATTACH_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI = 0xF0, /* 0xF0 = 240 */ +} attach_accept_iei; + +/* + * Message name: Attach accept + * Description: This message is sent by the network to the UE to indicate that the corresponding attach request has been accepted. See table 8.2.1.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct attach_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EpsAttachResult epsattachresult; + GprsTimer t3412value; + TrackingAreaIdentityList tailist; + EsmMessageContainer esmmessagecontainer; + /* Optional fields */ + uint32_t presencemask; + EpsMobileIdentity guti; + LocationAreaIdentification locationareaidentification; + MobileIdentity msidentity; + EmmCause emmcause; + GprsTimer t3402value; + GprsTimer t3423value; + PlmnList equivalentplmns; + EmergencyNumberList emergencynumberlist; + EpsNetworkFeatureSupport epsnetworkfeaturesupport; + AdditionalUpdateResult additionalupdateresult; +} attach_accept_msg; + +int decode_attach_accept(attach_accept_msg *attachaccept, uint8_t *buffer, uint32_t len); + +int encode_attach_accept(attach_accept_msg *attachaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ATTACH_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.c new file mode 100644 index 0000000000..5c78516943 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AttachComplete.h" + +int decode_attach_complete(attach_complete_msg *attach_complete, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ATTACH_COMPLETE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_message_container(&attach_complete->esmmessagecontainer, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_attach_complete(attach_complete_msg *attach_complete, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ATTACH_COMPLETE_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_message_container(&attach_complete->esmmessagecontainer, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h new file mode 100644 index 0000000000..a00fca3865 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EsmMessageContainer.h" + +#ifndef ATTACH_COMPLETE_H_ +#define ATTACH_COMPLETE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ATTACH_COMPLETE_MINIMUM_LENGTH ( \ + ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ATTACH_COMPLETE_MAXIMUM_LENGTH ( \ + ESM_MESSAGE_CONTAINER_MAXIMUM_LENGTH ) + + +/* + * Message name: Attach complete + * Description: This message is sent by the UE to the network in response to an ATTACH ACCEPT message. See table 8.2.2.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct attach_complete_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EsmMessageContainer esmmessagecontainer; +} attach_complete_msg; + +int decode_attach_complete(attach_complete_msg *attachcomplete, uint8_t *buffer, uint32_t len); + +int encode_attach_complete(attach_complete_msg *attachcomplete, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ATTACH_COMPLETE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.c new file mode 100644 index 0000000000..e0d28539ec --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.c @@ -0,0 +1,81 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AttachReject.h" + +int decode_attach_reject(attach_reject_msg *attach_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ATTACH_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&attach_reject->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ATTACH_REJECT_ESM_MESSAGE_CONTAINER_IEI: + if ((decoded_result = + decode_esm_message_container(&attach_reject->esmmessagecontainer, + ATTACH_REJECT_ESM_MESSAGE_CONTAINER_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_reject->presencemask |= ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_attach_reject(attach_reject_msg *attach_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ATTACH_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = encode_emm_cause(&attach_reject->emmcause, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((attach_reject->presencemask & ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT) + == ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT) + { + if ((encode_result = + encode_esm_message_container(&attach_reject->esmmessagecontainer, + ATTACH_REJECT_ESM_MESSAGE_CONTAINER_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h new file mode 100644 index 0000000000..1d32834ae4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" +#include "EsmMessageContainer.h" + +#ifndef ATTACH_REJECT_H_ +#define ATTACH_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ATTACH_REJECT_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ATTACH_REJECT_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH + \ + ESM_MESSAGE_CONTAINER_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT (1<<0) + +typedef enum attach_reject_iei_tag { + ATTACH_REJECT_ESM_MESSAGE_CONTAINER_IEI = 0x78, /* 0x78 = 120 */ +} attach_reject_iei; + +/* + * Message name: Attach reject + * Description: This message is sent by the network to the UE to indicate that the corresponding attach request has been rejected. See table 8.2.3.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct attach_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; + /* Optional fields */ + uint32_t presencemask; + EsmMessageContainer esmmessagecontainer; +} attach_reject_msg; + +int decode_attach_reject(attach_reject_msg *attachreject, uint8_t *buffer, uint32_t len); + +int encode_attach_reject(attach_reject_msg *attachreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ATTACH_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.c new file mode 100644 index 0000000000..7af0af3851 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.c @@ -0,0 +1,423 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include "nas_log.h" + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AttachRequest.h" + +int decode_attach_request(attach_request_msg *attach_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + LOG_FUNC_IN; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ATTACH_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_eps_attach_type(&attach_request->epsattachtype, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) { +// return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + + if ((decoded_result = decode_u8_nas_key_set_identifier(&attach_request->naskeysetidentifier, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + + decoded++; + + if ((decoded_result = decode_eps_mobile_identity(&attach_request->oldgutiorimsi, 0, buffer + decoded, len - decoded)) < 0) { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + else + decoded += decoded_result; + + if ((decoded_result = decode_ue_network_capability(&attach_request->uenetworkcapability, 0, buffer + decoded, len - decoded)) < 0) { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + else + decoded += decoded_result; + + if ((decoded_result = decode_esm_message_container(&attach_request->esmmessagecontainer, 0, buffer + decoded, len - decoded)) < 0) { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_IEI: + if ((decoded_result = + decode_p_tmsi_signature(&attach_request->oldptmsisignature, + ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_IEI, buffer + decoded, + len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT; + break; + case ATTACH_REQUEST_ADDITIONAL_GUTI_IEI: + if ((decoded_result = + decode_eps_mobile_identity(&attach_request->additionalguti, + ATTACH_REQUEST_ADDITIONAL_GUTI_IEI, buffer + decoded, len - + decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_ADDITIONAL_GUTI_PRESENT; + break; + case ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI: + if ((decoded_result = + decode_tracking_area_identity(&attach_request->lastvisitedregisteredtai, + ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI, buffer + + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT; + break; + case ATTACH_REQUEST_DRX_PARAMETER_IEI: + if ((decoded_result = + decode_drx_parameter(&attach_request->drxparameter, + ATTACH_REQUEST_DRX_PARAMETER_IEI, buffer + decoded, len - + decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_DRX_PARAMETER_PRESENT; + break; + case ATTACH_REQUEST_MS_NETWORK_CAPABILITY_IEI: + if ((decoded_result = + decode_ms_network_capability(&attach_request->msnetworkcapability, + ATTACH_REQUEST_MS_NETWORK_CAPABILITY_IEI, buffer + decoded, + len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT; + break; + case ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI: + if ((decoded_result = + decode_location_area_identification(&attach_request->oldlocationareaidentification, + ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI, buffer + + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT; + break; + case ATTACH_REQUEST_TMSI_STATUS_IEI: + if ((decoded_result = + decode_tmsi_status(&attach_request->tmsistatus, + ATTACH_REQUEST_TMSI_STATUS_IEI, buffer + decoded, len - + decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_TMSI_STATUS_PRESENT; + break; + case ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI: + if ((decoded_result = + decode_mobile_station_classmark_2(&attach_request->mobilestationclassmark2, + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI, buffer + + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT; + break; + case ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI: + if ((decoded_result = + decode_mobile_station_classmark_3(&attach_request->mobilestationclassmark3, + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI, buffer + + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT; + break; + case ATTACH_REQUEST_SUPPORTED_CODECS_IEI: + if ((decoded_result = + decode_supported_codec_list(&attach_request->supportedcodecs, + ATTACH_REQUEST_SUPPORTED_CODECS_IEI, buffer + decoded, len + - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_SUPPORTED_CODECS_PRESENT; + break; + case ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI: + if ((decoded_result = + decode_additional_update_type(&attach_request->additionalupdatetype, + ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI, buffer + + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT; + break; + + case ATTACH_REQUEST_OLD_GUTI_TYPE_IEI: + if ((decoded_result = + decode_guti_type(&attach_request->oldgutitype, + ATTACH_REQUEST_OLD_GUTI_TYPE_IEI, + buffer + decoded, len - decoded)) <= 0) + { + // return decoded_result; + LOG_FUNC_RETURN(decoded_result); + } + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + attach_request->presencemask |= ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT; + break; + + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + { +// return TLV_DECODE_UNEXPECTED_IEI; + LOG_FUNC_RETURN(TLV_DECODE_UNEXPECTED_IEI); + } + } + } + + LOG_FUNC_RETURN(decoded); +} + +int encode_attach_request(attach_request_msg *attach_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ATTACH_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_nas_key_set_identifier(&attach_request->naskeysetidentifier) & 0x0f) << 4) | (encode_u8_eps_attach_type(&attach_request->epsattachtype) & 0x0f); + encoded++; + + if ((encode_result = + encode_eps_mobile_identity(&attach_request->oldgutiorimsi, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_ue_network_capability(&attach_request->uenetworkcapability, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_esm_message_container(&attach_request->esmmessagecontainer, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((attach_request->presencemask & ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT) + == ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT) + { + if ((encode_result = + encode_p_tmsi_signature(&attach_request->oldptmsisignature, + ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_ADDITIONAL_GUTI_PRESENT) + == ATTACH_REQUEST_ADDITIONAL_GUTI_PRESENT) + { + if ((encode_result = + encode_eps_mobile_identity(&attach_request->additionalguti, + ATTACH_REQUEST_ADDITIONAL_GUTI_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) + == ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) + { + if ((encode_result = + encode_tracking_area_identity(&attach_request->lastvisitedregisteredtai, + ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_DRX_PARAMETER_PRESENT) + == ATTACH_REQUEST_DRX_PARAMETER_PRESENT) + { + if ((encode_result = encode_drx_parameter(&attach_request->drxparameter, + ATTACH_REQUEST_DRX_PARAMETER_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT) + == ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT) + { + if ((encode_result = + encode_ms_network_capability(&attach_request->msnetworkcapability, + ATTACH_REQUEST_MS_NETWORK_CAPABILITY_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT) + == ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT) + { + if ((encode_result = + encode_location_area_identification(&attach_request->oldlocationareaidentification, + ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_TMSI_STATUS_PRESENT) + == ATTACH_REQUEST_TMSI_STATUS_PRESENT) + { + if ((encode_result = encode_tmsi_status(&attach_request->tmsistatus, + ATTACH_REQUEST_TMSI_STATUS_IEI, buffer + encoded, len - encoded)) + < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT) + == ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT) + { + if ((encode_result = + encode_mobile_station_classmark_2(&attach_request->mobilestationclassmark2, + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT) + == ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT) + { + if ((encode_result = + encode_mobile_station_classmark_3(&attach_request->mobilestationclassmark3, + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_SUPPORTED_CODECS_PRESENT) + == ATTACH_REQUEST_SUPPORTED_CODECS_PRESENT) + { + if ((encode_result = + encode_supported_codec_list(&attach_request->supportedcodecs, + ATTACH_REQUEST_SUPPORTED_CODECS_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT) + == ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT) + { + if ((encode_result = + encode_additional_update_type(&attach_request->additionalupdatetype, + ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((attach_request->presencemask & ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT) + == ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT) + { + if ((encode_result = + encode_guti_type(&attach_request->oldgutitype, + ATTACH_REQUEST_OLD_GUTI_TYPE_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h new file mode 100644 index 0000000000..5bf18d98a1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h @@ -0,0 +1,125 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EpsAttachType.h" +#include "NasKeySetIdentifier.h" +#include "EpsMobileIdentity.h" +#include "UeNetworkCapability.h" +#include "EsmMessageContainer.h" +#include "PTmsiSignature.h" +#include "TrackingAreaIdentity.h" +#include "DrxParameter.h" +#include "MsNetworkCapability.h" +#include "LocationAreaIdentification.h" +#include "TmsiStatus.h" +#include "MobileStationClassmark2.h" +#include "MobileStationClassmark3.h" +#include "SupportedCodecList.h" +#include "AdditionalUpdateType.h" +#include "GutiType.h" + +#ifndef ATTACH_REQUEST_H_ +#define ATTACH_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ATTACH_REQUEST_MINIMUM_LENGTH ( \ + EPS_ATTACH_TYPE_MINIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MINIMUM_LENGTH + \ + UE_NETWORK_CAPABILITY_MINIMUM_LENGTH + \ + ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ATTACH_REQUEST_MAXIMUM_LENGTH ( \ + EPS_ATTACH_TYPE_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + UE_NETWORK_CAPABILITY_MAXIMUM_LENGTH + \ + ESM_MESSAGE_CONTAINER_MAXIMUM_LENGTH + \ + P_TMSI_SIGNATURE_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_MAXIMUM_LENGTH + \ + DRX_PARAMETER_MAXIMUM_LENGTH + \ + MS_NETWORK_CAPABILITY_MAXIMUM_LENGTH + \ + LOCATION_AREA_IDENTIFICATION_MAXIMUM_LENGTH + \ + TMSI_STATUS_MAXIMUM_LENGTH + \ + MOBILE_STATION_CLASSMARK_2_MAXIMUM_LENGTH + \ + MOBILE_STATION_CLASSMARK_3_MAXIMUM_LENGTH + \ + SUPPORTED_CODEC_LIST_MAXIMUM_LENGTH + \ + ADDITIONAL_UPDATE_TYPE_MAXIMUM_LENGTH + \ + GUTI_TYPE_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT (1<<0) +# define ATTACH_REQUEST_ADDITIONAL_GUTI_PRESENT (1<<1) +# define ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT (1<<2) +# define ATTACH_REQUEST_DRX_PARAMETER_PRESENT (1<<3) +# define ATTACH_REQUEST_MS_NETWORK_CAPABILITY_PRESENT (1<<4) +# define ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT (1<<5) +# define ATTACH_REQUEST_TMSI_STATUS_PRESENT (1<<6) +# define ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT (1<<7) +# define ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT (1<<8) +# define ATTACH_REQUEST_SUPPORTED_CODECS_PRESENT (1<<9) +# define ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT (1<<10) +# define ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT (1<<11) + +typedef enum attach_request_iei_tag { + ATTACH_REQUEST_OLD_PTMSI_SIGNATURE_IEI = 0x19, /* 0x19 = 25 */ + ATTACH_REQUEST_ADDITIONAL_GUTI_IEI = 0x50, /* 0x50 = 80 */ + ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI = 0x52, /* 0x52 = 82 */ + ATTACH_REQUEST_DRX_PARAMETER_IEI = 0x5C, /* 0x5C = 92 */ + ATTACH_REQUEST_MS_NETWORK_CAPABILITY_IEI = 0x31, /* 0x31 = 49 */ + ATTACH_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI = 0x13, /* 0x13 = 19 */ + ATTACH_REQUEST_TMSI_STATUS_IEI = 0x90, /* 0x90 = 144 */ + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI = 0x11, /* 0x11 = 17 */ + ATTACH_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI = 0x20, /* 0x20 = 32 */ + ATTACH_REQUEST_SUPPORTED_CODECS_IEI = 0x40, /* 0x40 = 64 */ + ATTACH_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI = 0xF0, /* 0xF0 = 240 */ + ATTACH_REQUEST_OLD_GUTI_TYPE_IEI = 0xE0, /* 0xE0 = 224 */ +} attach_request_iei; + +/* + * Message name: Attach request + * Description: This message is sent by the UE to the network in order to perform an attach procedure. See table 8.2.4.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct attach_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EpsAttachType epsattachtype; + NasKeySetIdentifier naskeysetidentifier; + EpsMobileIdentity oldgutiorimsi; + UeNetworkCapability uenetworkcapability; + EsmMessageContainer esmmessagecontainer; + /* Optional fields */ + uint32_t presencemask; + PTmsiSignature oldptmsisignature; + EpsMobileIdentity additionalguti; + TrackingAreaIdentity lastvisitedregisteredtai; + DrxParameter drxparameter; + MsNetworkCapability msnetworkcapability; + LocationAreaIdentification oldlocationareaidentification; + TmsiStatus tmsistatus; + MobileStationClassmark2 mobilestationclassmark2; + MobileStationClassmark3 mobilestationclassmark3; + SupportedCodecList supportedcodecs; + AdditionalUpdateType additionalupdatetype; + GutiType oldgutitype; +} attach_request_msg; + +int decode_attach_request(attach_request_msg *attachrequest, uint8_t *buffer, uint32_t len); + +int encode_attach_request(attach_request_msg *attachrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ATTACH_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.c new file mode 100644 index 0000000000..92306a7d4d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.c @@ -0,0 +1,81 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationFailure.h" + +int decode_authentication_failure(authentication_failure_msg *authentication_failure, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, AUTHENTICATION_FAILURE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&authentication_failure->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_IEI: + if ((decoded_result = + decode_authentication_failure_parameter(&authentication_failure->authenticationfailureparameter, + AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + authentication_failure->presencemask |= AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_authentication_failure(authentication_failure_msg *authentication_failure, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_FAILURE_MINIMUM_LENGTH, len); + + if ((encode_result = encode_emm_cause(&authentication_failure->emmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((authentication_failure->presencemask & AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT) + == AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT) + { + if ((encode_result = + encode_authentication_failure_parameter(&authentication_failure->authenticationfailureparameter, + AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h new file mode 100644 index 0000000000..13d4b5dd56 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" +#include "AuthenticationFailureParameter.h" + +#ifndef AUTHENTICATION_FAILURE_H_ +#define AUTHENTICATION_FAILURE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define AUTHENTICATION_FAILURE_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define AUTHENTICATION_FAILURE_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH + \ + AUTHENTICATION_FAILURE_PARAMETER_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT (1<<0) + +typedef enum authentication_failure_iei_tag { + AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_IEI = 0x30, /* 0x30 = 48 */ +} authentication_failure_iei; + +/* + * Message name: Authentication failure + * Description: This message is sent by the UE to the network to indicate that authentication of the network has failed. See table 8.2.5.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct authentication_failure_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; + /* Optional fields */ + uint32_t presencemask; + AuthenticationFailureParameter authenticationfailureparameter; +} authentication_failure_msg; + +int decode_authentication_failure(authentication_failure_msg *authenticationfailure, uint8_t *buffer, uint32_t len); + +int encode_authentication_failure(authentication_failure_msg *authenticationfailure, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(AUTHENTICATION_FAILURE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.c new file mode 100644 index 0000000000..6d7d96173e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationReject.h" + +int decode_authentication_reject(authentication_reject_msg *authentication_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, AUTHENTICATION_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + return decoded; +} + +int encode_authentication_reject(authentication_reject_msg *authentication_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_REJECT_MINIMUM_LENGTH, len); + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h new file mode 100644 index 0000000000..97f07dcdad --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" + +#ifndef AUTHENTICATION_REJECT_H_ +#define AUTHENTICATION_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define AUTHENTICATION_REJECT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define AUTHENTICATION_REJECT_MAXIMUM_LENGTH (0) + +/* + * Message name: Authentication reject + * Description: This message is sent by the network to the UE to indicate that the authentication procedure has failed and that the UE shall abort all activities. See table 8.2.6.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct authentication_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; +} authentication_reject_msg; + +int decode_authentication_reject(authentication_reject_msg *authenticationreject, uint8_t *buffer, uint32_t len); + +int encode_authentication_reject(authentication_reject_msg *authenticationreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(AUTHENTICATION_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.c new file mode 100644 index 0000000000..47e8a76051 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationRequest.h" + +int decode_authentication_request(authentication_request_msg *authentication_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, AUTHENTICATION_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_nas_key_set_identifier(&authentication_request->naskeysetidentifierasme, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_authentication_parameter_rand(&authentication_request->authenticationparameterrand, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_authentication_parameter_autn(&authentication_request->authenticationparameterautn, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_authentication_request(authentication_request_msg *authentication_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_nas_key_set_identifier(&authentication_request->naskeysetidentifierasme) & 0x0f) << 4) | 0x00; + encoded++; + if ((encode_result = + encode_authentication_parameter_rand(&authentication_request->authenticationparameterrand, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_authentication_parameter_autn(&authentication_request->authenticationparameterautn, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h new file mode 100644 index 0000000000..a357340db1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "NasKeySetIdentifier.h" +#include "AuthenticationParameterRand.h" +#include "AuthenticationParameterAutn.h" + +#ifndef AUTHENTICATION_REQUEST_H_ +#define AUTHENTICATION_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define AUTHENTICATION_REQUEST_MINIMUM_LENGTH ( \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + AUTHENTICATION_PARAMETER_RAND_MINIMUM_LENGTH + \ + AUTHENTICATION_PARAMETER_AUTN_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define AUTHENTICATION_REQUEST_MAXIMUM_LENGTH ( \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + AUTHENTICATION_PARAMETER_RAND_MAXIMUM_LENGTH + \ + AUTHENTICATION_PARAMETER_AUTN_MAXIMUM_LENGTH ) + + +/* + * Message name: Authentication request + * Description: This message is sent by the network to the UE to initiate authentication of the UE identity. See table 8.2.7.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct authentication_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + NasKeySetIdentifier naskeysetidentifierasme; + AuthenticationParameterRand authenticationparameterrand; + AuthenticationParameterAutn authenticationparameterautn; +} authentication_request_msg; + +int decode_authentication_request(authentication_request_msg *authenticationrequest, uint8_t *buffer, uint32_t len); + +int encode_authentication_request(authentication_request_msg *authenticationrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(AUTHENTICATION_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.c new file mode 100644 index 0000000000..305cb513ee --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationResponse.h" + +int decode_authentication_response(authentication_response_msg *authentication_response, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, AUTHENTICATION_RESPONSE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_authentication_response_parameter(&authentication_response->authenticationresponseparameter, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_authentication_response(authentication_response_msg *authentication_response, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_RESPONSE_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_authentication_response_parameter(&authentication_response->authenticationresponseparameter, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h new file mode 100644 index 0000000000..b2f8533f5f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "AuthenticationResponseParameter.h" + +#ifndef AUTHENTICATION_RESPONSE_H_ +#define AUTHENTICATION_RESPONSE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define AUTHENTICATION_RESPONSE_MINIMUM_LENGTH ( \ + AUTHENTICATION_RESPONSE_PARAMETER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define AUTHENTICATION_RESPONSE_MAXIMUM_LENGTH ( \ + AUTHENTICATION_RESPONSE_PARAMETER_MAXIMUM_LENGTH ) + + +/* + * Message name: Authentication response + * Description: This message is sent by the UE to the network to deliver a calculated authentication response to the network. See table 8.2.8.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct authentication_response_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + AuthenticationResponseParameter authenticationresponseparameter; +} authentication_response_msg; + +int decode_authentication_response(authentication_response_msg *authenticationresponse, uint8_t *buffer, uint32_t len); + +int encode_authentication_response(authentication_response_msg *authenticationresponse, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(AUTHENTICATION_RESPONSE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.c new file mode 100644 index 0000000000..0c34aa2d59 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.c @@ -0,0 +1,148 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "CsServiceNotification.h" + +int decode_cs_service_notification(cs_service_notification_msg *cs_service_notification, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, CS_SERVICE_NOTIFICATION_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_paging_identity(&cs_service_notification->pagingidentity, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case CS_SERVICE_NOTIFICATION_CLI_IEI: + if ((decoded_result = decode_cli(&cs_service_notification->cli, + CS_SERVICE_NOTIFICATION_CLI_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + cs_service_notification->presencemask |= CS_SERVICE_NOTIFICATION_CLI_PRESENT; + break; + case CS_SERVICE_NOTIFICATION_SS_CODE_IEI: + if ((decoded_result = + decode_ss_code(&cs_service_notification->sscode, + CS_SERVICE_NOTIFICATION_SS_CODE_IEI, buffer + decoded, len + - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + cs_service_notification->presencemask |= CS_SERVICE_NOTIFICATION_SS_CODE_PRESENT; + break; + case CS_SERVICE_NOTIFICATION_LCS_INDICATOR_IEI: + if ((decoded_result = + decode_lcs_indicator(&cs_service_notification->lcsindicator, + CS_SERVICE_NOTIFICATION_LCS_INDICATOR_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + cs_service_notification->presencemask |= CS_SERVICE_NOTIFICATION_LCS_INDICATOR_PRESENT; + break; + case CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_IEI: + if ((decoded_result = + decode_lcs_client_identity(&cs_service_notification->lcsclientidentity, + CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + cs_service_notification->presencemask |= CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_cs_service_notification(cs_service_notification_msg *cs_service_notification, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, CS_SERVICE_NOTIFICATION_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_paging_identity(&cs_service_notification->pagingidentity, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((cs_service_notification->presencemask & CS_SERVICE_NOTIFICATION_CLI_PRESENT) + == CS_SERVICE_NOTIFICATION_CLI_PRESENT) + { + if ((encode_result = encode_cli(&cs_service_notification->cli, + CS_SERVICE_NOTIFICATION_CLI_IEI, buffer + encoded, len - encoded)) + < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((cs_service_notification->presencemask & CS_SERVICE_NOTIFICATION_SS_CODE_PRESENT) + == CS_SERVICE_NOTIFICATION_SS_CODE_PRESENT) + { + if ((encode_result = encode_ss_code(&cs_service_notification->sscode, + CS_SERVICE_NOTIFICATION_SS_CODE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((cs_service_notification->presencemask & CS_SERVICE_NOTIFICATION_LCS_INDICATOR_PRESENT) + == CS_SERVICE_NOTIFICATION_LCS_INDICATOR_PRESENT) + { + if ((encode_result = + encode_lcs_indicator(&cs_service_notification->lcsindicator, + CS_SERVICE_NOTIFICATION_LCS_INDICATOR_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((cs_service_notification->presencemask & CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_PRESENT) + == CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_PRESENT) + { + if ((encode_result = + encode_lcs_client_identity(&cs_service_notification->lcsclientidentity, + CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h new file mode 100644 index 0000000000..1338a50448 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "PagingIdentity.h" +#include "Cli.h" +#include "SsCode.h" +#include "LcsIndicator.h" +#include "LcsClientIdentity.h" + +#ifndef CS_SERVICE_NOTIFICATION_H_ +#define CS_SERVICE_NOTIFICATION_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define CS_SERVICE_NOTIFICATION_MINIMUM_LENGTH ( \ + PAGING_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define CS_SERVICE_NOTIFICATION_MAXIMUM_LENGTH ( \ + PAGING_IDENTITY_MAXIMUM_LENGTH + \ + CLI_MAXIMUM_LENGTH + \ + SS_CODE_MAXIMUM_LENGTH + \ + LCS_INDICATOR_MAXIMUM_LENGTH + \ + LCS_CLIENT_IDENTITY_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define CS_SERVICE_NOTIFICATION_CLI_PRESENT (1<<0) +# define CS_SERVICE_NOTIFICATION_SS_CODE_PRESENT (1<<1) +# define CS_SERVICE_NOTIFICATION_LCS_INDICATOR_PRESENT (1<<2) +# define CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_PRESENT (1<<3) + +typedef enum cs_service_notification_iei_tag { + CS_SERVICE_NOTIFICATION_CLI_IEI = 0x60, /* 0x60 = 96 */ + CS_SERVICE_NOTIFICATION_SS_CODE_IEI = 0x61, /* 0x61 = 97 */ + CS_SERVICE_NOTIFICATION_LCS_INDICATOR_IEI = 0x62, /* 0x62 = 98 */ + CS_SERVICE_NOTIFICATION_LCS_CLIENT_IDENTITY_IEI = 0x63, /* 0x63 = 99 */ +} cs_service_notification_iei; + +/* + * Message name: CS service notification + * Description: This message is sent by the network when a paging request with CS call indicator was received via SGs for a UE, and a NAS signalling connection is already established for the UE. See table 8.2.9.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct cs_service_notification_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + PagingIdentity pagingidentity; + /* Optional fields */ + uint32_t presencemask; + Cli cli; + SsCode sscode; + LcsIndicator lcsindicator; + LcsClientIdentity lcsclientidentity; +} cs_service_notification_msg; + +int decode_cs_service_notification(cs_service_notification_msg *csservicenotification, uint8_t *buffer, uint32_t len); + +int encode_cs_service_notification(cs_service_notification_msg *csservicenotification, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(CS_SERVICE_NOTIFICATION_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.c new file mode 100644 index 0000000000..666cb61bab --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DetachAccept.h" + +int decode_detach_accept(detach_accept_msg *detach_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DETACH_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + return decoded; +} + +int encode_detach_accept(detach_accept_msg *detach_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DETACH_ACCEPT_MINIMUM_LENGTH, len); + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h new file mode 100644 index 0000000000..0370e4a0b1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" + +#ifndef DETACH_ACCEPT_H_ +#define DETACH_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define DETACH_ACCEPT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define DETACH_ACCEPT_MAXIMUM_LENGTH (0) + +/* + * Message name: Detach accept + * Description: This message is sent by the network to indicate that the detach procedure has been completed. See table 8.2.10.1.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct detach_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; +} detach_accept_msg; + +int decode_detach_accept(detach_accept_msg *detachaccept, uint8_t *buffer, uint32_t len); + +int encode_detach_accept(detach_accept_msg *detachaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(DETACH_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.c new file mode 100644 index 0000000000..520597a529 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.c @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DetachRequest.h" + +int decode_detach_request(detach_request_msg *detach_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DETACH_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_detach_type(&detach_request->detachtype, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + if ((decoded_result = decode_u8_nas_key_set_identifier(&detach_request->naskeysetidentifier, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_eps_mobile_identity(&detach_request->gutiorimsi, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_detach_request(detach_request_msg *detach_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DETACH_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_nas_key_set_identifier(&detach_request->naskeysetidentifier) << 4) | (encode_u8_detach_type(&detach_request->detachtype) & 0x0f)); + encoded++; + + if ((encode_result = encode_eps_mobile_identity(&detach_request->gutiorimsi, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h new file mode 100644 index 0000000000..af80fe7152 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "DetachType.h" +#include "NasKeySetIdentifier.h" +#include "EpsMobileIdentity.h" + +#ifndef DETACH_REQUEST_H_ +#define DETACH_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define DETACH_REQUEST_MINIMUM_LENGTH ( \ + DETACH_TYPE_MINIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define DETACH_REQUEST_MAXIMUM_LENGTH ( \ + DETACH_TYPE_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH ) + + +/* + * Message name: Detach request + * Description: This message is sent by the UE to request the release of an EMM context. See table 8.2.11.1.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct detach_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + DetachType detachtype; + NasKeySetIdentifier naskeysetidentifier; + EpsMobileIdentity gutiorimsi; +} detach_request_msg; + +int decode_detach_request(detach_request_msg *detachrequest, uint8_t *buffer, uint32_t len); + +int encode_detach_request(detach_request_msg *detachrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(DETACH_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.c new file mode 100644 index 0000000000..0d5778bf8a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DownlinkNasTransport.h" + +int decode_downlink_nas_transport(downlink_nas_transport_msg *downlink_nas_transport, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DOWNLINK_NAS_TRANSPORT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_nas_message_container(&downlink_nas_transport->nasmessagecontainer, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_downlink_nas_transport(downlink_nas_transport_msg *downlink_nas_transport, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DOWNLINK_NAS_TRANSPORT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_nas_message_container(&downlink_nas_transport->nasmessagecontainer, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h new file mode 100644 index 0000000000..76b8713275 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "NasMessageContainer.h" + +#ifndef DOWNLINK_NAS_TRANSPORT_H_ +#define DOWNLINK_NAS_TRANSPORT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define DOWNLINK_NAS_TRANSPORT_MINIMUM_LENGTH ( \ + NAS_MESSAGE_CONTAINER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define DOWNLINK_NAS_TRANSPORT_MAXIMUM_LENGTH ( \ + NAS_MESSAGE_CONTAINER_MAXIMUM_LENGTH ) + + +/* + * Message name: Downlink NAS Transport + * Description: This message is sent by the network to the UE in order to carry an SMS message in encapsulated format. See table 8.2.12.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct downlink_nas_transport_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + NasMessageContainer nasmessagecontainer; +} downlink_nas_transport_msg; + +int decode_downlink_nas_transport(downlink_nas_transport_msg *downlinknastransport, uint8_t *buffer, uint32_t len); + +int encode_downlink_nas_transport(downlink_nas_transport_msg *downlinknastransport, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(DOWNLINK_NAS_TRANSPORT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.c new file mode 100644 index 0000000000..60fa174eb1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.c @@ -0,0 +1,161 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EmmInformation.h" + +int decode_emm_information(emm_information_msg *emm_information, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EMM_INFORMATION_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case EMM_INFORMATION_FULL_NAME_FOR_NETWORK_IEI: + if ((decoded_result = + decode_network_name(&emm_information->fullnamefornetwork, + EMM_INFORMATION_FULL_NAME_FOR_NETWORK_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + emm_information->presencemask |= EMM_INFORMATION_FULL_NAME_FOR_NETWORK_PRESENT; + break; + case EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_IEI: + if ((decoded_result = + decode_network_name(&emm_information->shortnamefornetwork, + EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + emm_information->presencemask |= EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_PRESENT; + break; + case EMM_INFORMATION_LOCAL_TIME_ZONE_IEI: + if ((decoded_result = + decode_time_zone(&emm_information->localtimezone, + EMM_INFORMATION_LOCAL_TIME_ZONE_IEI, buffer + decoded, len + - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + emm_information->presencemask |= EMM_INFORMATION_LOCAL_TIME_ZONE_PRESENT; + break; + case EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI: + if ((decoded_result = + decode_time_zone_and_time(&emm_information->universaltimeandlocaltimezone, + EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + emm_information->presencemask |= EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT; + break; + case EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_IEI: + if ((decoded_result = + decode_daylight_saving_time(&emm_information->networkdaylightsavingtime, + EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + emm_information->presencemask |= EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_emm_information(emm_information_msg *emm_information, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EMM_INFORMATION_MINIMUM_LENGTH, len); + + if ((emm_information->presencemask & EMM_INFORMATION_FULL_NAME_FOR_NETWORK_PRESENT) + == EMM_INFORMATION_FULL_NAME_FOR_NETWORK_PRESENT) + { + if ((encode_result = + encode_network_name(&emm_information->fullnamefornetwork, + EMM_INFORMATION_FULL_NAME_FOR_NETWORK_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((emm_information->presencemask & EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_PRESENT) + == EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_PRESENT) + { + if ((encode_result = + encode_network_name(&emm_information->shortnamefornetwork, + EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((emm_information->presencemask & EMM_INFORMATION_LOCAL_TIME_ZONE_PRESENT) + == EMM_INFORMATION_LOCAL_TIME_ZONE_PRESENT) + { + if ((encode_result = encode_time_zone(&emm_information->localtimezone, + EMM_INFORMATION_LOCAL_TIME_ZONE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((emm_information->presencemask & EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT) + == EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT) + { + if ((encode_result = + encode_time_zone_and_time(&emm_information->universaltimeandlocaltimezone, + EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((emm_information->presencemask & EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT) + == EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT) + { + if ((encode_result = + encode_daylight_saving_time(&emm_information->networkdaylightsavingtime, + EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h new file mode 100644 index 0000000000..3b0150eb70 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "NetworkName.h" +#include "TimeZone.h" +#include "TimeZoneAndTime.h" +#include "DaylightSavingTime.h" + +#ifndef EMM_INFORMATION_H_ +#define EMM_INFORMATION_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define EMM_INFORMATION_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define EMM_INFORMATION_MAXIMUM_LENGTH ( \ + NETWORK_NAME_MAXIMUM_LENGTH + \ + NETWORK_NAME_MAXIMUM_LENGTH + \ + TIME_ZONE_MAXIMUM_LENGTH + \ + TIME_ZONE_AND_TIME_MAXIMUM_LENGTH + \ + DAYLIGHT_SAVING_TIME_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define EMM_INFORMATION_FULL_NAME_FOR_NETWORK_PRESENT (1<<0) +# define EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_PRESENT (1<<1) +# define EMM_INFORMATION_LOCAL_TIME_ZONE_PRESENT (1<<2) +# define EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_PRESENT (1<<3) +# define EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_PRESENT (1<<4) + +typedef enum emm_information_iei_tag { + EMM_INFORMATION_FULL_NAME_FOR_NETWORK_IEI = 0x43, /* 0x43 = 67 */ + EMM_INFORMATION_SHORT_NAME_FOR_NETWORK_IEI = 0x45, /* 0x45 = 69 */ + EMM_INFORMATION_LOCAL_TIME_ZONE_IEI = 0x46, /* 0x46 = 70 */ + EMM_INFORMATION_UNIVERSAL_TIME_AND_LOCAL_TIME_ZONE_IEI = 0x47, /* 0x47 = 71 */ + EMM_INFORMATION_NETWORK_DAYLIGHT_SAVING_TIME_IEI = 0x49, /* 0x49 = 73 */ +} emm_information_iei; + +/* + * Message name: EMM information + * Description: This message is sent by the network at any time during EMM context is established to send certain information to the UE. See table 8.2.13.1. + * Significance: local + * Direction: network to UE + */ + +typedef struct emm_information_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + NetworkName fullnamefornetwork; + NetworkName shortnamefornetwork; + TimeZone localtimezone; + TimeZoneAndTime universaltimeandlocaltimezone; + DaylightSavingTime networkdaylightsavingtime; +} emm_information_msg; + +int decode_emm_information(emm_information_msg *emminformation, uint8_t *buffer, uint32_t len); + +int encode_emm_information(emm_information_msg *emminformation, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(EMM_INFORMATION_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.c new file mode 100644 index 0000000000..a268f03e62 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EmmStatus.h" + +int decode_emm_status(emm_status_msg *emm_status, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EMM_STATUS_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&emm_status->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_emm_status(emm_status_msg *emm_status, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EMM_STATUS_MINIMUM_LENGTH, len); + + if ((encode_result = encode_emm_cause(&emm_status->emmcause, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h new file mode 100644 index 0000000000..93bd00d91d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" + +#ifndef EMM_STATUS_H_ +#define EMM_STATUS_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define EMM_STATUS_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define EMM_STATUS_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH ) + + +/* + * Message name: EMM status + * Description: This message is sent by the UE or by the network at any time to report certain error conditions listed in clause 7. See table 8.2.14.1. + * Significance: local + * Direction: both + */ + +typedef struct emm_status_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; +} emm_status_msg; + +int decode_emm_status(emm_status_msg *emmstatus, uint8_t *buffer, uint32_t len); + +int encode_emm_status(emm_status_msg *emmstatus, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(EMM_STATUS_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.c new file mode 100644 index 0000000000..7facac168d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ExtendedServiceRequest.h" + +int decode_extended_service_request(extended_service_request_msg *extended_service_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EXTENDED_SERVICE_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_service_type(&extended_service_request->servicetype, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + if ((decoded_result = decode_u8_nas_key_set_identifier(&extended_service_request->naskeysetidentifier, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_mobile_identity(&extended_service_request->mtmsi, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_extended_service_request(extended_service_request_msg *extended_service_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EXTENDED_SERVICE_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_service_type(&extended_service_request->servicetype) & 0x0f) << 4) | (encode_u8_nas_key_set_identifier(&extended_service_request->naskeysetidentifier) & 0x0f); + encoded++; + if ((encode_result = + encode_mobile_identity(&extended_service_request->mtmsi, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_csfb_response(&extended_service_request->csfbresponse, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h new file mode 100644 index 0000000000..42337d95f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "ServiceType.h" +#include "NasKeySetIdentifier.h" +#include "MobileIdentity.h" +#include "CsfbResponse.h" + +#ifndef EXTENDED_SERVICE_REQUEST_H_ +#define EXTENDED_SERVICE_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define EXTENDED_SERVICE_REQUEST_MINIMUM_LENGTH ( \ + SERVICE_TYPE_MINIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + MOBILE_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define EXTENDED_SERVICE_REQUEST_MAXIMUM_LENGTH ( \ + SERVICE_TYPE_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + CSFB_RESPONSE_MAXIMUM_LENGTH ) + + +/* + * Message name: Extended service request + * Description: This message is sent by the UE to the network to initiate a CS fallback call or respond to a mobile terminated CS fallback request from the network. See table 8.2.15.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct extended_service_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + ServiceType servicetype; + NasKeySetIdentifier naskeysetidentifier; + MobileIdentity mtmsi; + /* Optional fields */ + uint32_t presencemask; + CsfbResponse csfbresponse; +} extended_service_request_msg; + +int decode_extended_service_request(extended_service_request_msg *extendedservicerequest, uint8_t *buffer, uint32_t len); + +int encode_extended_service_request(extended_service_request_msg *extendedservicerequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(EXTENDED_SERVICE_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.c new file mode 100644 index 0000000000..430c851900 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "GutiReallocationCommand.h" + +int decode_guti_reallocation_command(guti_reallocation_command_msg *guti_reallocation_command, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, GUTI_REALLOCATION_COMMAND_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_eps_mobile_identity(&guti_reallocation_command->guti, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case GUTI_REALLOCATION_COMMAND_TAI_LIST_IEI: + if ((decoded_result = + decode_tracking_area_identity_list(&guti_reallocation_command->tailist, + GUTI_REALLOCATION_COMMAND_TAI_LIST_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + guti_reallocation_command->presencemask |= GUTI_REALLOCATION_COMMAND_TAI_LIST_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_guti_reallocation_command(guti_reallocation_command_msg *guti_reallocation_command, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, GUTI_REALLOCATION_COMMAND_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_eps_mobile_identity(&guti_reallocation_command->guti, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((guti_reallocation_command->presencemask & GUTI_REALLOCATION_COMMAND_TAI_LIST_PRESENT) + == GUTI_REALLOCATION_COMMAND_TAI_LIST_PRESENT) + { + if ((encode_result = + encode_tracking_area_identity_list(&guti_reallocation_command->tailist, + GUTI_REALLOCATION_COMMAND_TAI_LIST_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h new file mode 100644 index 0000000000..b7945e8191 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h @@ -0,0 +1,55 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EpsMobileIdentity.h" +#include "TrackingAreaIdentityList.h" + +#ifndef GUTI_REALLOCATION_COMMAND_H_ +#define GUTI_REALLOCATION_COMMAND_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define GUTI_REALLOCATION_COMMAND_MINIMUM_LENGTH ( \ + EPS_MOBILE_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define GUTI_REALLOCATION_COMMAND_MAXIMUM_LENGTH ( \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_LIST_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define GUTI_REALLOCATION_COMMAND_TAI_LIST_PRESENT (1<<0) + +typedef enum guti_reallocation_command_iei_tag { + GUTI_REALLOCATION_COMMAND_TAI_LIST_IEI = 0x54, /* 0x54 = 84 */ +} guti_reallocation_command_iei; + +/* + * Message name: GUTI reallocation command + * Description: This message is sent by the network to the UE to reallocate a GUTI and optionally to provide a new TAI list. See table 8.2.16.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct guti_reallocation_command_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EpsMobileIdentity guti; + /* Optional fields */ + uint32_t presencemask; + TrackingAreaIdentityList tailist; +} guti_reallocation_command_msg; + +int decode_guti_reallocation_command(guti_reallocation_command_msg *gutireallocationcommand, uint8_t *buffer, uint32_t len); + +int encode_guti_reallocation_command(guti_reallocation_command_msg *gutireallocationcommand, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(GUTI_REALLOCATION_COMMAND_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.c new file mode 100644 index 0000000000..1ec78e21d2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "GutiReallocationComplete.h" + +int decode_guti_reallocation_complete(guti_reallocation_complete_msg *guti_reallocation_complete, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, GUTI_REALLOCATION_COMPLETE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + return decoded; +} + +int encode_guti_reallocation_complete(guti_reallocation_complete_msg *guti_reallocation_complete, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, GUTI_REALLOCATION_COMPLETE_MINIMUM_LENGTH, len); + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h new file mode 100644 index 0000000000..daaca0572a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" + +#ifndef GUTI_REALLOCATION_COMPLETE_H_ +#define GUTI_REALLOCATION_COMPLETE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define GUTI_REALLOCATION_COMPLETE_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define GUTI_REALLOCATION_COMPLETE_MAXIMUM_LENGTH (0) + +/* + * Message name: GUTI reallocation complete + * Description: This message is sent by the UE to the network to indicate that reallocation of a GUTI has taken place. See table 8.2.17.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct guti_reallocation_complete_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; +} guti_reallocation_complete_msg; + +int decode_guti_reallocation_complete(guti_reallocation_complete_msg *gutireallocationcomplete, uint8_t *buffer, uint32_t len); + +int encode_guti_reallocation_complete(guti_reallocation_complete_msg *gutireallocationcomplete, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(GUTI_REALLOCATION_COMPLETE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.c new file mode 100644 index 0000000000..7371e6b49c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.c @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "IdentityRequest.h" + +int decode_identity_request(identity_request_msg *identity_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, IDENTITY_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_identity_type_2(&identity_request->identitytype, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + return decoded; +} + +int encode_identity_request(identity_request_msg *identity_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, IDENTITY_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = encode_u8_identity_type_2(&identity_request->identitytype) & 0x0f; + encoded++; + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h new file mode 100644 index 0000000000..fc867566e5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "IdentityType2.h" + +#ifndef IDENTITY_REQUEST_H_ +#define IDENTITY_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define IDENTITY_REQUEST_MINIMUM_LENGTH ( \ + IDENTITY_TYPE_2_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define IDENTITY_REQUEST_MAXIMUM_LENGTH ( \ + IDENTITY_TYPE_2_MAXIMUM_LENGTH ) + + +/* + * Message name: Identity request + * Description: This message is sent by the network to the UE to request the UE to provide the specified identity. See table 8.2.18.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct identity_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + IdentityType2 identitytype; +} identity_request_msg; + +int decode_identity_request(identity_request_msg *identityrequest, uint8_t *buffer, uint32_t len); + +int encode_identity_request(identity_request_msg *identityrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(IDENTITY_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.c new file mode 100644 index 0000000000..eb9141725a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "IdentityResponse.h" + +int decode_identity_response(identity_response_msg *identity_response, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, IDENTITY_RESPONSE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_mobile_identity(&identity_response->mobileidentity, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_identity_response(identity_response_msg *identity_response, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, IDENTITY_RESPONSE_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_mobile_identity(&identity_response->mobileidentity, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h new file mode 100644 index 0000000000..3f04f57046 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "MobileIdentity.h" + +#ifndef IDENTITY_RESPONSE_H_ +#define IDENTITY_RESPONSE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define IDENTITY_RESPONSE_MINIMUM_LENGTH ( \ + MOBILE_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define IDENTITY_RESPONSE_MAXIMUM_LENGTH ( \ + MOBILE_IDENTITY_MAXIMUM_LENGTH ) + + +/* + * Message name: Identity response + * Description: This message is sent by the UE to the network in response to an IDENTITY REQUEST message and provides the requested identity. See table 8.2.19.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct identity_response_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + MobileIdentity mobileidentity; +} identity_response_msg; + +int decode_identity_response(identity_response_msg *identityresponse, uint8_t *buffer, uint32_t len); + +int encode_identity_response(identity_response_msg *identityresponse, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(IDENTITY_RESPONSE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/Makefile b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/Makefile new file mode 100644 index 0000000000..10f3cda68b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/Makefile @@ -0,0 +1,41 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) + +TARGET = $(LIBEMMMSG) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c %.h Makefile $(LIBDIR)/$(LIBIES).a $(UTILDIR)/TLVEncoder.h $(UTILDIR)/TLVDecoder.h + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +clean: + $(RM) $(OBJS) .bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.c new file mode 100644 index 0000000000..c32dec1550 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.c @@ -0,0 +1,145 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SecurityModeCommand.h" + +int decode_security_mode_command(security_mode_command_msg *security_mode_command, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SECURITY_MODE_COMMAND_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_nas_security_algorithms(&security_mode_command->selectednassecurityalgorithms, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_u8_nas_key_set_identifier(&security_mode_command->naskeysetidentifier, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_ue_security_capability(&security_mode_command->replayeduesecuritycapabilities, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case SECURITY_MODE_COMMAND_IMEISV_REQUEST_IEI: + if ((decoded_result = + decode_imeisv_request(&security_mode_command->imeisvrequest, + SECURITY_MODE_COMMAND_IMEISV_REQUEST_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + security_mode_command->presencemask |= SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT; + break; + case SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_IEI: + if ((decoded_result = + decode_nonce(&security_mode_command->replayednonceue, + SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + security_mode_command->presencemask |= SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_PRESENT; + break; + case SECURITY_MODE_COMMAND_NONCEMME_IEI: + if ((decoded_result = + decode_nonce(&security_mode_command->noncemme, + SECURITY_MODE_COMMAND_NONCEMME_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + security_mode_command->presencemask |= SECURITY_MODE_COMMAND_NONCEMME_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_security_mode_command(security_mode_command_msg *security_mode_command, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SECURITY_MODE_COMMAND_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_nas_security_algorithms(&security_mode_command->selectednassecurityalgorithms, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + *(buffer + encoded) = (encode_u8_nas_key_set_identifier(&security_mode_command->naskeysetidentifier) & 0x0f); + encoded++; + if ((encode_result = + encode_ue_security_capability(&security_mode_command->replayeduesecuritycapabilities, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((security_mode_command->presencemask & SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT) + == SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT) + { + if ((encode_result = + encode_imeisv_request(&security_mode_command->imeisvrequest, + SECURITY_MODE_COMMAND_IMEISV_REQUEST_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((security_mode_command->presencemask & SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_PRESENT) + == SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_PRESENT) + { + if ((encode_result = + encode_nonce(&security_mode_command->replayednonceue, + SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((security_mode_command->presencemask & SECURITY_MODE_COMMAND_NONCEMME_PRESENT) + == SECURITY_MODE_COMMAND_NONCEMME_PRESENT) + { + if ((encode_result = encode_nonce(&security_mode_command->noncemme, + SECURITY_MODE_COMMAND_NONCEMME_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h new file mode 100644 index 0000000000..1b322fce05 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "NasSecurityAlgorithms.h" +#include "NasKeySetIdentifier.h" +#include "UeSecurityCapability.h" +#include "ImeisvRequest.h" +#include "Nonce.h" + +#ifndef SECURITY_MODE_COMMAND_H_ +#define SECURITY_MODE_COMMAND_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define SECURITY_MODE_COMMAND_MINIMUM_LENGTH ( \ + NAS_SECURITY_ALGORITHMS_MINIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + UE_SECURITY_CAPABILITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define SECURITY_MODE_COMMAND_MAXIMUM_LENGTH ( \ + NAS_SECURITY_ALGORITHMS_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + UE_SECURITY_CAPABILITY_MAXIMUM_LENGTH + \ + IMEISV_REQUEST_MAXIMUM_LENGTH + \ + NONCE_MAXIMUM_LENGTH + \ + NONCE_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define SECURITY_MODE_COMMAND_IMEISV_REQUEST_PRESENT (1<<0) +# define SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_PRESENT (1<<1) +# define SECURITY_MODE_COMMAND_NONCEMME_PRESENT (1<<2) + +typedef enum security_mode_command_iei_tag { + SECURITY_MODE_COMMAND_IMEISV_REQUEST_IEI = 0xC0, /* 0xC0 = 192 */ + SECURITY_MODE_COMMAND_REPLAYED_NONCEUE_IEI = 0x55, /* 0x55 = 85 */ + SECURITY_MODE_COMMAND_NONCEMME_IEI = 0x56, /* 0x56 = 86 */ +} security_mode_command_iei; + +/* + * Message name: Security mode command + * Description: This message is sent by the network to the UE to establish NAS signalling security. See table 8.2.20.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct security_mode_command_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + NasSecurityAlgorithms selectednassecurityalgorithms; + NasKeySetIdentifier naskeysetidentifier; + UeSecurityCapability replayeduesecuritycapabilities; + /* Optional fields */ + uint32_t presencemask; + ImeisvRequest imeisvrequest; + Nonce replayednonceue; + Nonce noncemme; +} security_mode_command_msg; + +int decode_security_mode_command(security_mode_command_msg *securitymodecommand, uint8_t *buffer, uint32_t len); + +int encode_security_mode_command(security_mode_command_msg *securitymodecommand, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(SECURITY_MODE_COMMAND_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.c new file mode 100644 index 0000000000..d58216407f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SecurityModeComplete.h" + +int decode_security_mode_complete(security_mode_complete_msg *security_mode_complete, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SECURITY_MODE_COMPLETE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case SECURITY_MODE_COMPLETE_IMEISV_IEI: + if ((decoded_result = + decode_mobile_identity(&security_mode_complete->imeisv, + SECURITY_MODE_COMPLETE_IMEISV_IEI, buffer + decoded, len - + decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + security_mode_complete->presencemask |= SECURITY_MODE_COMPLETE_IMEISV_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_security_mode_complete(security_mode_complete_msg *security_mode_complete, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SECURITY_MODE_COMPLETE_MINIMUM_LENGTH, len); + + if ((security_mode_complete->presencemask & SECURITY_MODE_COMPLETE_IMEISV_PRESENT) + == SECURITY_MODE_COMPLETE_IMEISV_PRESENT) + { + if ((encode_result = + encode_mobile_identity(&security_mode_complete->imeisv, + SECURITY_MODE_COMPLETE_IMEISV_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h new file mode 100644 index 0000000000..94da408063 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "MobileIdentity.h" + +#ifndef SECURITY_MODE_COMPLETE_H_ +#define SECURITY_MODE_COMPLETE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define SECURITY_MODE_COMPLETE_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define SECURITY_MODE_COMPLETE_MAXIMUM_LENGTH ( \ + MOBILE_IDENTITY_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define SECURITY_MODE_COMPLETE_IMEISV_PRESENT (1<<0) + +typedef enum security_mode_complete_iei_tag { + SECURITY_MODE_COMPLETE_IMEISV_IEI = 0x23, /* 0x23 = 35 */ +} security_mode_complete_iei; + +/* + * Message name: Security mode complete + * Description: This message is sent by the UE to the network in response to a SECURITY MODE COMMAND message. See table 8.2.21.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct security_mode_complete_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + MobileIdentity imeisv; +} security_mode_complete_msg; + +int decode_security_mode_complete(security_mode_complete_msg *securitymodecomplete, uint8_t *buffer, uint32_t len); + +int encode_security_mode_complete(security_mode_complete_msg *securitymodecomplete, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(SECURITY_MODE_COMPLETE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.c new file mode 100644 index 0000000000..5088511a31 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SecurityModeReject.h" + +int decode_security_mode_reject(security_mode_reject_msg *security_mode_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SECURITY_MODE_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&security_mode_reject->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_security_mode_reject(security_mode_reject_msg *security_mode_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SECURITY_MODE_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = encode_emm_cause(&security_mode_reject->emmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h new file mode 100644 index 0000000000..c182eb585d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" + +#ifndef SECURITY_MODE_REJECT_H_ +#define SECURITY_MODE_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define SECURITY_MODE_REJECT_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define SECURITY_MODE_REJECT_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH ) + + +/* + * Message name: Security mode reject + * Description: This message is sent by the UE to the network to indicate that the corresponding security mode command has been rejected. See table 8.2.22.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct security_mode_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; +} security_mode_reject_msg; + +int decode_security_mode_reject(security_mode_reject_msg *securitymodereject, uint8_t *buffer, uint32_t len); + +int encode_security_mode_reject(security_mode_reject_msg *securitymodereject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(SECURITY_MODE_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.c new file mode 100644 index 0000000000..2e49a670cc --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.c @@ -0,0 +1,50 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ServiceReject.h" + +int decode_service_reject(service_reject_msg *service_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SERVICE_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&service_reject->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_service_reject(service_reject_msg *service_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SERVICE_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = encode_emm_cause(&service_reject->emmcause, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = encode_gprs_timer(&service_reject->t3442value, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h new file mode 100644 index 0000000000..775c9322c4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" +#include "GprsTimer.h" + +#ifndef SERVICE_REJECT_H_ +#define SERVICE_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define SERVICE_REJECT_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define SERVICE_REJECT_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH ) + + +/* + * Message name: Service reject + * Description: This message is sent by the network to the UE in order to reject the service request procedure. See table 8.2.24.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct service_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; + /* Optional fields */ + uint32_t presencemask; + GprsTimer t3442value; +} service_reject_msg; + +int decode_service_reject(service_reject_msg *servicereject, uint8_t *buffer, uint32_t len); + +int encode_service_reject(service_reject_msg *servicereject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(SERVICE_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.c new file mode 100644 index 0000000000..564a40619f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ServiceRequest.h" + +int decode_service_request(service_request_msg *service_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SERVICE_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_ksi_and_sequence_number(&service_request->ksiandsequencenumber, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_short_mac(&service_request->messageauthenticationcode, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_service_request(service_request_msg *service_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SERVICE_REQUEST_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_ksi_and_sequence_number(&service_request->ksiandsequencenumber, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_short_mac(&service_request->messageauthenticationcode, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h new file mode 100644 index 0000000000..734060b693 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "KsiAndSequenceNumber.h" +#include "ShortMac.h" + +#ifndef SERVICE_REQUEST_H_ +#define SERVICE_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define SERVICE_REQUEST_MINIMUM_LENGTH ( \ + KSI_AND_SEQUENCE_NUMBER_MINIMUM_LENGTH + \ + SHORT_MAC_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define SERVICE_REQUEST_MAXIMUM_LENGTH ( \ + KSI_AND_SEQUENCE_NUMBER_MAXIMUM_LENGTH + \ + SHORT_MAC_MAXIMUM_LENGTH ) + + +/* + * Message name: Service request + * Description: This message is sent by the UE to the network to request the establishment of a NAS signalling connection and of the radio and S1 bearers. Its structure does not follow the structure of a standard layer 3 message. See table 8.2.25.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct service_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + KsiAndSequenceNumber ksiandsequencenumber; + ShortMac messageauthenticationcode; +} service_request_msg; + +int decode_service_request(service_request_msg *servicerequest, uint8_t *buffer, uint32_t len); + +int encode_service_request(service_request_msg *servicerequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(SERVICE_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.c new file mode 100644 index 0000000000..1090a4bcd3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.c @@ -0,0 +1,352 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaUpdateAccept.h" + +int decode_tracking_area_update_accept(tracking_area_update_accept_msg *tracking_area_update_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, TRACKING_AREA_UPDATE_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_eps_update_result(&tracking_area_update_accept->epsupdateresult, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_IEI: + if ((decoded_result = + decode_gprs_timer(&tracking_area_update_accept->t3412value, + TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_GUTI_IEI: + if ((decoded_result = + decode_eps_mobile_identity(&tracking_area_update_accept->guti, + TRACKING_AREA_UPDATE_ACCEPT_GUTI_IEI, buffer + decoded, len + - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_GUTI_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_IEI: + if ((decoded_result = + decode_tracking_area_identity_list(&tracking_area_update_accept->tailist, + TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_IEI: + if ((decoded_result = + decode_eps_bearer_context_status(&tracking_area_update_accept->epsbearercontextstatus, + TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI: + if ((decoded_result = + decode_location_area_identification(&tracking_area_update_accept->locationareaidentification, + TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_IEI: + if ((decoded_result = + decode_mobile_identity(&tracking_area_update_accept->msidentity, + TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_IEI: + if ((decoded_result = + decode_emm_cause(&tracking_area_update_accept->emmcause, + TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_IEI: + if ((decoded_result = + decode_gprs_timer(&tracking_area_update_accept->t3402value, + TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_IEI: + if ((decoded_result = + decode_gprs_timer(&tracking_area_update_accept->t3423value, + TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_IEI: + if ((decoded_result = + decode_plmn_list(&tracking_area_update_accept->equivalentplmns, + TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_IEI: + if ((decoded_result = + decode_emergency_number_list(&tracking_area_update_accept->emergencynumberlist, + TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI: + if ((decoded_result = + decode_eps_network_feature_support(&tracking_area_update_accept->epsnetworkfeaturesupport, + TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT; + break; + case TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI: + if ((decoded_result = + decode_additional_update_result(&tracking_area_update_accept->additionalupdateresult, + TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_accept->presencemask |= TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_tracking_area_update_accept(tracking_area_update_accept_msg *tracking_area_update_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_UPDATE_ACCEPT_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_eps_update_result(&tracking_area_update_accept->epsupdateresult) & 0x0f) << 4) | 0x00; + encoded++; + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT) + { + if ((encode_result = + encode_gprs_timer(&tracking_area_update_accept->t3412value, + TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_GUTI_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_GUTI_PRESENT) + { + if ((encode_result = + encode_eps_mobile_identity(&tracking_area_update_accept->guti, + TRACKING_AREA_UPDATE_ACCEPT_GUTI_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT) + { + if ((encode_result = + encode_tracking_area_identity_list(&tracking_area_update_accept->tailist, + TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT) + { + if ((encode_result = + encode_eps_bearer_context_status(&tracking_area_update_accept->epsbearercontextstatus, + TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT) + { + if ((encode_result = + encode_location_area_identification(&tracking_area_update_accept->locationareaidentification, + TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_PRESENT) + { + if ((encode_result = + encode_mobile_identity(&tracking_area_update_accept->msidentity, + TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_PRESENT) + { + if ((encode_result = + encode_emm_cause(&tracking_area_update_accept->emmcause, + TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT) + { + if ((encode_result = + encode_gprs_timer(&tracking_area_update_accept->t3402value, + TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT) + { + if ((encode_result = + encode_gprs_timer(&tracking_area_update_accept->t3423value, + TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_IEI, buffer + encoded, len + - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_PRESENT) + { + if ((encode_result = + encode_plmn_list(&tracking_area_update_accept->equivalentplmns, + TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT) + { + if ((encode_result = + encode_emergency_number_list(&tracking_area_update_accept->emergencynumberlist, + TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT) + { + if ((encode_result = + encode_eps_network_feature_support(&tracking_area_update_accept->epsnetworkfeaturesupport, + TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_accept->presencemask & TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT) + == TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT) + { + if ((encode_result = + encode_additional_update_result(&tracking_area_update_accept->additionalupdateresult, + TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h new file mode 100644 index 0000000000..bf57b471dd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h @@ -0,0 +1,113 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EpsUpdateResult.h" +#include "GprsTimer.h" +#include "EpsMobileIdentity.h" +#include "TrackingAreaIdentityList.h" +#include "EpsBearerContextStatus.h" +#include "LocationAreaIdentification.h" +#include "MobileIdentity.h" +#include "EmmCause.h" +#include "PlmnList.h" +#include "EmergencyNumberList.h" +#include "EpsNetworkFeatureSupport.h" +#include "AdditionalUpdateResult.h" + +#ifndef TRACKING_AREA_UPDATE_ACCEPT_H_ +#define TRACKING_AREA_UPDATE_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define TRACKING_AREA_UPDATE_ACCEPT_MINIMUM_LENGTH ( \ + EPS_UPDATE_RESULT_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define TRACKING_AREA_UPDATE_ACCEPT_MAXIMUM_LENGTH ( \ + EPS_UPDATE_RESULT_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_LIST_MAXIMUM_LENGTH + \ + EPS_BEARER_CONTEXT_STATUS_MAXIMUM_LENGTH + \ + LOCATION_AREA_IDENTIFICATION_MAXIMUM_LENGTH + \ + MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + EMM_CAUSE_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + GPRS_TIMER_MAXIMUM_LENGTH + \ + PLMN_LIST_MAXIMUM_LENGTH + \ + EMERGENCY_NUMBER_LIST_MAXIMUM_LENGTH + \ + EPS_NETWORK_FEATURE_SUPPORT_MAXIMUM_LENGTH + \ + ADDITIONAL_UPDATE_RESULT_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_PRESENT (1<<0) +# define TRACKING_AREA_UPDATE_ACCEPT_GUTI_PRESENT (1<<1) +# define TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_PRESENT (1<<2) +# define TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_PRESENT (1<<3) +# define TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_PRESENT (1<<4) +# define TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_PRESENT (1<<5) +# define TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_PRESENT (1<<6) +# define TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_PRESENT (1<<7) +# define TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_PRESENT (1<<8) +# define TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_PRESENT (1<<9) +# define TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_PRESENT (1<<10) +# define TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_PRESENT (1<<11) +# define TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_PRESENT (1<<12) + +typedef enum tracking_area_update_accept_iei_tag { + TRACKING_AREA_UPDATE_ACCEPT_T3412_VALUE_IEI = 0x5A, /* 0x5A = 90 */ + TRACKING_AREA_UPDATE_ACCEPT_GUTI_IEI = 0x50, /* 0x50 = 80 */ + TRACKING_AREA_UPDATE_ACCEPT_TAI_LIST_IEI = 0x54, /* 0x54 = 84 */ + TRACKING_AREA_UPDATE_ACCEPT_EPS_BEARER_CONTEXT_STATUS_IEI = 0x57, /* 0x57 = 87 */ + TRACKING_AREA_UPDATE_ACCEPT_LOCATION_AREA_IDENTIFICATION_IEI = 0x13, /* 0x13 = 19 */ + TRACKING_AREA_UPDATE_ACCEPT_MS_IDENTITY_IEI = 0x23, /* 0x23 = 35 */ + TRACKING_AREA_UPDATE_ACCEPT_EMM_CAUSE_IEI = 0x53, /* 0x53 = 83 */ + TRACKING_AREA_UPDATE_ACCEPT_T3402_VALUE_IEI = 0x17, /* 0x17 = 23 */ + TRACKING_AREA_UPDATE_ACCEPT_T3423_VALUE_IEI = 0x59, /* 0x59 = 89 */ + TRACKING_AREA_UPDATE_ACCEPT_EQUIVALENT_PLMNS_IEI = 0x4A, /* 0x4A = 74 */ + TRACKING_AREA_UPDATE_ACCEPT_EMERGENCY_NUMBER_LIST_IEI = 0x34, /* 0x34 = 52 */ + TRACKING_AREA_UPDATE_ACCEPT_EPS_NETWORK_FEATURE_SUPPORT_IEI = 0x64, /* 0x64 = 100 */ + TRACKING_AREA_UPDATE_ACCEPT_ADDITIONAL_UPDATE_RESULT_IEI = 0xF0, /* 0xF0 = 240 */ +} tracking_area_update_accept_iei; + +/* + * Message name: Tracking area update accept + * Description: This message is sent by the network to the UE to provide the UE with EPS mobility management related data in response to a tracking area update request message. See table 8.2.26.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct tracking_area_update_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EpsUpdateResult epsupdateresult; + /* Optional fields */ + uint32_t presencemask; + GprsTimer t3412value; + EpsMobileIdentity guti; + TrackingAreaIdentityList tailist; + EpsBearerContextStatus epsbearercontextstatus; + LocationAreaIdentification locationareaidentification; + MobileIdentity msidentity; + EmmCause emmcause; + GprsTimer t3402value; + GprsTimer t3423value; + PlmnList equivalentplmns; + EmergencyNumberList emergencynumberlist; + EpsNetworkFeatureSupport epsnetworkfeaturesupport; + AdditionalUpdateResult additionalupdateresult; +} tracking_area_update_accept_msg; + +int decode_tracking_area_update_accept(tracking_area_update_accept_msg *trackingareaupdateaccept, uint8_t *buffer, uint32_t len); + +int encode_tracking_area_update_accept(tracking_area_update_accept_msg *trackingareaupdateaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(TRACKING_AREA_UPDATE_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.c new file mode 100644 index 0000000000..3a1e38c617 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaUpdateComplete.h" + +int decode_tracking_area_update_complete(tracking_area_update_complete_msg *tracking_area_update_complete, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, TRACKING_AREA_UPDATE_COMPLETE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + return decoded; +} + +int encode_tracking_area_update_complete(tracking_area_update_complete_msg *tracking_area_update_complete, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_UPDATE_COMPLETE_MINIMUM_LENGTH, len); + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h new file mode 100644 index 0000000000..deb0f0c2bf --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" + +#ifndef TRACKING_AREA_UPDATE_COMPLETE_H_ +#define TRACKING_AREA_UPDATE_COMPLETE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define TRACKING_AREA_UPDATE_COMPLETE_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define TRACKING_AREA_UPDATE_COMPLETE_MAXIMUM_LENGTH (0) + +/* + * Message name: Tracking area update complete + * Description: This message shall be sent by the UE to the network in response to a tracking area update accept message if a GUTI has been changed or a new TMSI has been assigned. See table 8.2.27.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct tracking_area_update_complete_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; +} tracking_area_update_complete_msg; + +int decode_tracking_area_update_complete(tracking_area_update_complete_msg *trackingareaupdatecomplete, uint8_t *buffer, uint32_t len); + +int encode_tracking_area_update_complete(tracking_area_update_complete_msg *trackingareaupdatecomplete, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(TRACKING_AREA_UPDATE_COMPLETE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.c new file mode 100644 index 0000000000..be92b254e8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaUpdateReject.h" + +int decode_tracking_area_update_reject(tracking_area_update_reject_msg *tracking_area_update_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, TRACKING_AREA_UPDATE_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_emm_cause(&tracking_area_update_reject->emmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_tracking_area_update_reject(tracking_area_update_reject_msg *tracking_area_update_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_UPDATE_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_emm_cause(&tracking_area_update_reject->emmcause, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h new file mode 100644 index 0000000000..d0052b1fbb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EmmCause.h" + +#ifndef TRACKING_AREA_UPDATE_REJECT_H_ +#define TRACKING_AREA_UPDATE_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define TRACKING_AREA_UPDATE_REJECT_MINIMUM_LENGTH ( \ + EMM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define TRACKING_AREA_UPDATE_REJECT_MAXIMUM_LENGTH ( \ + EMM_CAUSE_MAXIMUM_LENGTH ) + + +/* + * Message name: Tracking area update reject + * Description: This message is sent by the network to the UE in order to reject the tracking area updating procedure. See table 8.2.28.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct tracking_area_update_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EmmCause emmcause; +} tracking_area_update_reject_msg; + +int decode_tracking_area_update_reject(tracking_area_update_reject_msg *trackingareaupdatereject, uint8_t *buffer, uint32_t len); + +int encode_tracking_area_update_reject(tracking_area_update_reject_msg *trackingareaupdatereject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(TRACKING_AREA_UPDATE_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.c new file mode 100644 index 0000000000..d78ec28188 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.c @@ -0,0 +1,484 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaUpdateRequest.h" + +int decode_tracking_area_update_request(tracking_area_update_request_msg *tracking_area_update_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, TRACKING_AREA_UPDATE_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_eps_update_type(&tracking_area_update_request->epsupdatetype, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + if ((decoded_result = decode_u8_nas_key_set_identifier(&tracking_area_update_request->naskeysetidentifier, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_eps_mobile_identity(&tracking_area_update_request->oldguti, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_IEI: + if ((decoded_result = + decode_nas_key_set_identifier(&tracking_area_update_request->noncurrentnativenaskeysetidentifier, + TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_IEI: + if ((decoded_result = + decode_ciphering_key_sequence_number(&tracking_area_update_request->gprscipheringkeysequencenumber, + TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_IEI: + if ((decoded_result = + decode_p_tmsi_signature(&tracking_area_update_request->oldptmsisignature, + TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_IEI: + if ((decoded_result = + decode_eps_mobile_identity(&tracking_area_update_request->additionalguti, + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_NONCEUE_IEI: + if ((decoded_result = + decode_nonce(&tracking_area_update_request->nonceue, + TRACKING_AREA_UPDATE_REQUEST_NONCEUE_IEI, buffer + decoded, + len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_NONCEUE_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_IEI: + if ((decoded_result = + decode_ue_network_capability(&tracking_area_update_request->uenetworkcapability, + TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI: + if ((decoded_result = + decode_tracking_area_identity(&tracking_area_update_request->lastvisitedregisteredtai, + TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_IEI: + if ((decoded_result = + decode_drx_parameter(&tracking_area_update_request->drxparameter, + TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_IEI: + if ((decoded_result = + decode_ue_radio_capability_information_update_needed(&tracking_area_update_request->ueradiocapabilityinformationupdateneeded, + TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_IEI: + if ((decoded_result = + decode_eps_bearer_context_status(&tracking_area_update_request->epsbearercontextstatus, + TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_IEI: + if ((decoded_result = + decode_ms_network_capability(&tracking_area_update_request->msnetworkcapability, + TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI: + if ((decoded_result = + decode_location_area_identification(&tracking_area_update_request->oldlocationareaidentification, + TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_IEI: + if ((decoded_result = + decode_tmsi_status(&tracking_area_update_request->tmsistatus, + TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI: + if ((decoded_result = + decode_mobile_station_classmark_2(&tracking_area_update_request->mobilestationclassmark2, + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI: + if ((decoded_result = + decode_mobile_station_classmark_3(&tracking_area_update_request->mobilestationclassmark3, + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_IEI: + if ((decoded_result = + decode_supported_codec_list(&tracking_area_update_request->supportedcodecs, + TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_PRESENT; + break; + case TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI: + if ((decoded_result = + decode_additional_update_type(&tracking_area_update_request->additionalupdatetype, + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT; + break; + + case TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_IEI: + if ((decoded_result = + decode_guti_type(&tracking_area_update_request->oldgutitype, + TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + tracking_area_update_request->presencemask |= TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_PRESENT; + break; + + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_tracking_area_update_request(tracking_area_update_request_msg *tracking_area_update_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_UPDATE_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_eps_update_type(&tracking_area_update_request->epsupdatetype) & 0x0f) << 4) | (encode_u8_nas_key_set_identifier(&tracking_area_update_request->naskeysetidentifier) & 0x0f); + encoded++; + if ((encode_result = + encode_eps_mobile_identity(&tracking_area_update_request->oldguti, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_nas_key_set_identifier(&tracking_area_update_request->noncurrentnativenaskeysetidentifier, + TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_PRESENT) + { + if ((encode_result = + encode_ciphering_key_sequence_number(&tracking_area_update_request->gprscipheringkeysequencenumber, + TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT) + { + if ((encode_result = + encode_p_tmsi_signature(&tracking_area_update_request->oldptmsisignature, + TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_PRESENT) + { + if ((encode_result = + encode_eps_mobile_identity(&tracking_area_update_request->additionalguti, + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_NONCEUE_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_NONCEUE_PRESENT) + { + if ((encode_result = + encode_nonce(&tracking_area_update_request->nonceue, + TRACKING_AREA_UPDATE_REQUEST_NONCEUE_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT) + { + if ((encode_result = + encode_ue_network_capability(&tracking_area_update_request->uenetworkcapability, + TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) + { + if ((encode_result = + encode_tracking_area_identity(&tracking_area_update_request->lastvisitedregisteredtai, + TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_PRESENT) + { + if ((encode_result = + encode_drx_parameter(&tracking_area_update_request->drxparameter, + TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_PRESENT) + { + if ((encode_result = + encode_ue_radio_capability_information_update_needed(&tracking_area_update_request->ueradiocapabilityinformationupdateneeded, + TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT) + { + if ((encode_result = + encode_eps_bearer_context_status(&tracking_area_update_request->epsbearercontextstatus, + TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT) + { + if ((encode_result = + encode_ms_network_capability(&tracking_area_update_request->msnetworkcapability, + TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT) + { + if ((encode_result = + encode_location_area_identification(&tracking_area_update_request->oldlocationareaidentification, + TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_PRESENT) + { + if ((encode_result = + encode_tmsi_status(&tracking_area_update_request->tmsistatus, + TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT) + { + if ((encode_result = + encode_mobile_station_classmark_2(&tracking_area_update_request->mobilestationclassmark2, + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT) + { + if ((encode_result = + encode_mobile_station_classmark_3(&tracking_area_update_request->mobilestationclassmark3, + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_PRESENT) + { + if ((encode_result = + encode_supported_codec_list(&tracking_area_update_request->supportedcodecs, + TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT) + { + if ((encode_result = + encode_additional_update_type(&tracking_area_update_request->additionalupdatetype, + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((tracking_area_update_request->presencemask & TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_PRESENT) + == TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_PRESENT) + { + if ((encode_result = + encode_guti_type(&tracking_area_update_request->oldgutitype, + TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h new file mode 100644 index 0000000000..bea87ecadc --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h @@ -0,0 +1,145 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "EpsUpdateType.h" +#include "NasKeySetIdentifier.h" +#include "EpsMobileIdentity.h" +#include "CipheringKeySequenceNumber.h" +#include "PTmsiSignature.h" +#include "Nonce.h" +#include "UeNetworkCapability.h" +#include "TrackingAreaIdentity.h" +#include "DrxParameter.h" +#include "UeRadioCapabilityInformationUpdateNeeded.h" +#include "EpsBearerContextStatus.h" +#include "MsNetworkCapability.h" +#include "LocationAreaIdentification.h" +#include "TmsiStatus.h" +#include "MobileStationClassmark2.h" +#include "MobileStationClassmark3.h" +#include "SupportedCodecList.h" +#include "AdditionalUpdateType.h" +#include "GutiType.h" + +#ifndef TRACKING_AREA_UPDATE_REQUEST_H_ +#define TRACKING_AREA_UPDATE_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define TRACKING_AREA_UPDATE_REQUEST_MINIMUM_LENGTH ( \ + EPS_UPDATE_TYPE_MINIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define TRACKING_AREA_UPDATE_REQUEST_MAXIMUM_LENGTH ( \ + EPS_UPDATE_TYPE_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH + \ + CIPHERING_KEY_SEQUENCE_NUMBER_MAXIMUM_LENGTH + \ + P_TMSI_SIGNATURE_MAXIMUM_LENGTH + \ + EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH + \ + NONCE_MAXIMUM_LENGTH + \ + UE_NETWORK_CAPABILITY_MAXIMUM_LENGTH + \ + TRACKING_AREA_IDENTITY_MAXIMUM_LENGTH + \ + DRX_PARAMETER_MAXIMUM_LENGTH + \ + UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_MAXIMUM_LENGTH + \ + EPS_BEARER_CONTEXT_STATUS_MAXIMUM_LENGTH + \ + MS_NETWORK_CAPABILITY_MAXIMUM_LENGTH + \ + LOCATION_AREA_IDENTIFICATION_MAXIMUM_LENGTH + \ + TMSI_STATUS_MAXIMUM_LENGTH + \ + MOBILE_STATION_CLASSMARK_2_MAXIMUM_LENGTH + \ + MOBILE_STATION_CLASSMARK_3_MAXIMUM_LENGTH + \ + SUPPORTED_CODEC_LIST_MAXIMUM_LENGTH + \ + ADDITIONAL_UPDATE_TYPE_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_PRESENT (1<<0) +# define TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_PRESENT (1<<1) +# define TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_PRESENT (1<<2) +# define TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_PRESENT (1<<3) +# define TRACKING_AREA_UPDATE_REQUEST_NONCEUE_PRESENT (1<<4) +# define TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_PRESENT (1<<5) +# define TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT (1<<6) +# define TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_PRESENT (1<<7) +# define TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_PRESENT (1<<8) +# define TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_PRESENT (1<<9) +# define TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_PRESENT (1<<10) +# define TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_PRESENT (1<<11) +# define TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_PRESENT (1<<12) +# define TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_PRESENT (1<<13) +# define TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_PRESENT (1<<14) +# define TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_PRESENT (1<<15) +# define TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_PRESENT (1<<16) +# define TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_PRESENT (1<<17) + +typedef enum tracking_area_update_request_iei_tag { + TRACKING_AREA_UPDATE_REQUEST_NONCURRENT_NATIVE_NAS_KEY_SET_IDENTIFIER_IEI = 0xB0, /* 0xB0 = 176 */ + TRACKING_AREA_UPDATE_REQUEST_GPRS_CIPHERING_KEY_SEQUENCE_NUMBER_IEI = 0x80, /* 0x80 = 128 */ + TRACKING_AREA_UPDATE_REQUEST_OLD_PTMSI_SIGNATURE_IEI = 0x19, /* 0x19 = 25 */ + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_GUTI_IEI = 0x50, /* 0x50 = 80 */ + TRACKING_AREA_UPDATE_REQUEST_NONCEUE_IEI = 0x55, /* 0x55 = 85 */ + TRACKING_AREA_UPDATE_REQUEST_UE_NETWORK_CAPABILITY_IEI = 0x58, /* 0x58 = 88 */ + TRACKING_AREA_UPDATE_REQUEST_LAST_VISITED_REGISTERED_TAI_IEI = 0x52, /* 0x52 = 82 */ + TRACKING_AREA_UPDATE_REQUEST_DRX_PARAMETER_IEI = 0x5C, /* 0x5C = 92 */ + TRACKING_AREA_UPDATE_REQUEST_UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_IEI = 0xA0, /* 0xA0 = 160 */ + TRACKING_AREA_UPDATE_REQUEST_EPS_BEARER_CONTEXT_STATUS_IEI = 0x57, /* 0x57 = 87 */ + TRACKING_AREA_UPDATE_REQUEST_MS_NETWORK_CAPABILITY_IEI = 0x31, /* 0x31 = 49 */ + TRACKING_AREA_UPDATE_REQUEST_OLD_LOCATION_AREA_IDENTIFICATION_IEI = 0x13, /* 0x13 = 19 */ + TRACKING_AREA_UPDATE_REQUEST_TMSI_STATUS_IEI = 0x90, /* 0x90 = 144 */ + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_2_IEI = 0x11, /* 0x11 = 17 */ + TRACKING_AREA_UPDATE_REQUEST_MOBILE_STATION_CLASSMARK_3_IEI = 0x20, /* 0x20 = 32 */ + TRACKING_AREA_UPDATE_REQUEST_SUPPORTED_CODECS_IEI = 0x40, /* 0x40 = 64 */ + TRACKING_AREA_UPDATE_REQUEST_ADDITIONAL_UPDATE_TYPE_IEI = 0xF0, /* 0xF0 = 240 */ + TRACKING_AREA_UPDATE_REQUEST_OLD_GUTI_TYPE_IEI = 0xE0, /* 0xE0 = 224 */ +} tracking_area_update_request_iei; + +/* + * Message name: Tracking area update request + * Description: The purposes of sending the tracking area update request by the UE to the network are described in subclause 5.5.3.1. See table 8.2.29.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct tracking_area_update_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + EpsUpdateType epsupdatetype; + NasKeySetIdentifier naskeysetidentifier; + EpsMobileIdentity oldguti; + /* Optional fields */ + uint32_t presencemask; + NasKeySetIdentifier noncurrentnativenaskeysetidentifier; + CipheringKeySequenceNumber gprscipheringkeysequencenumber; + PTmsiSignature oldptmsisignature; + EpsMobileIdentity additionalguti; + Nonce nonceue; + UeNetworkCapability uenetworkcapability; + TrackingAreaIdentity lastvisitedregisteredtai; + DrxParameter drxparameter; + UeRadioCapabilityInformationUpdateNeeded ueradiocapabilityinformationupdateneeded; + EpsBearerContextStatus epsbearercontextstatus; + MsNetworkCapability msnetworkcapability; + LocationAreaIdentification oldlocationareaidentification; + TmsiStatus tmsistatus; + MobileStationClassmark2 mobilestationclassmark2; + MobileStationClassmark3 mobilestationclassmark3; + SupportedCodecList supportedcodecs; + AdditionalUpdateType additionalupdatetype; + GutiType oldgutitype; +} tracking_area_update_request_msg; + +int decode_tracking_area_update_request(tracking_area_update_request_msg *trackingareaupdaterequest, uint8_t *buffer, uint32_t len); + +int encode_tracking_area_update_request(tracking_area_update_request_msg *trackingareaupdaterequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(TRACKING_AREA_UPDATE_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.c new file mode 100644 index 0000000000..3c24a82a0b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "UplinkNasTransport.h" + +int decode_uplink_nas_transport(uplink_nas_transport_msg *uplink_nas_transport, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, UPLINK_NAS_TRANSPORT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_nas_message_container(&uplink_nas_transport->nasmessagecontainer, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_uplink_nas_transport(uplink_nas_transport_msg *uplink_nas_transport, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, UPLINK_NAS_TRANSPORT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_nas_message_container(&uplink_nas_transport->nasmessagecontainer, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h new file mode 100644 index 0000000000..e491ada91a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "SecurityHeaderType.h" +#include "MessageType.h" +#include "NasMessageContainer.h" + +#ifndef UPLINK_NAS_TRANSPORT_H_ +#define UPLINK_NAS_TRANSPORT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define UPLINK_NAS_TRANSPORT_MINIMUM_LENGTH ( \ + NAS_MESSAGE_CONTAINER_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define UPLINK_NAS_TRANSPORT_MAXIMUM_LENGTH ( \ + NAS_MESSAGE_CONTAINER_MAXIMUM_LENGTH ) + + +/* + * Message name: Uplink NAS Transport + * Description: This message is sent by the UE to the network in order to carry an SMS message in encapsulated format. See table 8.2.30.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct uplink_nas_transport_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + SecurityHeaderType securityheadertype:4; + MessageType messagetype; + NasMessageContainer nasmessagecontainer; +} uplink_nas_transport_msg; + +int decode_uplink_nas_transport(uplink_nas_transport_msg *uplinknastransport, uint8_t *buffer, uint32_t len); + +int encode_uplink_nas_transport(uplink_nas_transport_msg *uplinknastransport, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(UPLINK_NAS_TRANSPORT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h new file mode 100644 index 0000000000..8d7dc3cbe8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h @@ -0,0 +1,107 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_cause.h + +Version 0.1 + +Date 2013/01/30 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines error cause code returned upon receiving unknown, + unforeseen, and erroneous EPS mobility management protocol + data. + +*****************************************************************************/ +#ifndef __EMM_CAUSE_H__ +#define __EMM_CAUSE_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Cause code used to notify that the EPS mobility management procedure + * has been successfully processed + */ +#define EMM_CAUSE_SUCCESS (-1) + +/* + * Causes related to UE identification (TS 24.301 - Annex A1) + */ +#define EMM_CAUSE_IMSI_UNKNOWN_IN_HSS 2 +#define EMM_CAUSE_ILLEGAL_UE 3 +#define EMM_CAUSE_ILLEGAL_ME 6 +#define EMM_CAUSE_INVALID_UE 9 +#define EMM_CAUSE_IMPLICITLY_DETACHED 10 + +/* + * Causes related to subscription options (TS 24.301 - Annex A2) + */ +#define EMM_CAUSE_IMEI_NOT_ACCEPTED 5 +#define EMM_CAUSE_EPS_NOT_ALLOWED 7 +#define EMM_CAUSE_BOTH_NOT_ALLOWED 8 +#define EMM_CAUSE_PLMN_NOT_ALLOWED 11 +#define EMM_CAUSE_TA_NOT_ALLOWED 12 +#define EMM_CAUSE_ROAMING_NOT_ALLOWED 13 +#define EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN 14 +#define EMM_CAUSE_NO_SUITABLE_CELLS 15 +#define EMM_CAUSE_CSG_NOT_AUTHORIZED 25 +#define EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN 35 +#define EMM_CAUSE_NO_EPS_BEARER_CTX_ACTIVE 40 + +/* + * Causes related to PLMN specific network failures and congestion/ + * authentication failures (TS 24.301 - Annex A3) + */ +#define EMM_CAUSE_MSC_NOT_REACHABLE 16 +#define EMM_CAUSE_NETWORK_FAILURE 17 +#define EMM_CAUSE_CS_DOMAIN_NOT_AVAILABLE 18 +#define EMM_CAUSE_ESM_FAILURE 19 +#define EMM_CAUSE_MAC_FAILURE 20 +#define EMM_CAUSE_SYNCH_FAILURE 21 +#define EMM_CAUSE_CONGESTION 22 +#define EMM_CAUSE_UE_SECURITY_MISMATCH 23 +#define EMM_CAUSE_SECURITY_MODE_REJECTED 24 +#define EMM_CAUSE_NON_EPS_AUTH_UNACCEPTABLE 26 +#define EMM_CAUSE_CS_SERVICE_NOT_AVAILABLE 39 + +/* + * Causes related to invalid messages (TS 24.301 - Annex A5) + */ +#define EMM_CAUSE_SEMANTICALLY_INCORRECT 95 +#define EMM_CAUSE_INVALID_MANDATORY_INFO 96 +#define EMM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED 97 +#define EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE 98 +#define EMM_CAUSE_IE_NOT_IMPLEMENTED 99 +#define EMM_CAUSE_CONDITIONAL_IE_ERROR 100 +#define EMM_CAUSE_MESSAGE_NOT_COMPATIBLE 101 +#define EMM_CAUSE_PROTOCOL_ERROR 111 + +/* + * TS 24.301 - Table 9.9.3.9.1 + * Any other value received by the mobile station shall be treated as cause + * code #111 "protocol error, unspecified". + * Any other value received by the network shall be treated as cause code #111 + * "protocol error, unspecified". + */ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __EMM_CAUSE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.c b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.c new file mode 100644 index 0000000000..c6c6e555fe --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.c @@ -0,0 +1,409 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_msg.c + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel, Sebastien Roux + +Description Defines EPS Mobility Management messages + +*****************************************************************************/ + +#include "emm_msg.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "TLVDecoder.h" +#include "TLVEncoder.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static int _emm_msg_decode_header(emm_msg_header_t *header, const uint8_t *buffer, uint32_t len); +static int _emm_msg_encode_header(const emm_msg_header_t *header, uint8_t *buffer, uint32_t len); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_msg_decode() ** + ** ** + ** Description: Decode EPS Mobility Management messages ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the EMM ** + ** message data ** + ** len: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: The EMM message structure to be filled ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_msg_decode(EMM_msg *msg, uint8_t *buffer, uint32_t len) +{ + LOG_FUNC_IN; + + int header_result; + int decode_result; + + /* First decode the EMM message header */ + header_result = _emm_msg_decode_header(&msg->header, buffer, len); + if (header_result < 0) { + LOG_TRACE(ERROR, "EMM-MSG - Failed to decode EMM message header " + "(%d)", header_result); + LOG_FUNC_RETURN(header_result); + } + + buffer += header_result; + len -= header_result; + + LOG_TRACE(INFO, "EMM-MSG - Message Type %02x", msg->header.message_type); + + switch(msg->header.message_type) + { + case EMM_INFORMATION: + decode_result = decode_emm_information(&msg->emm_information, buffer, len); + break; + case UPLINK_NAS_TRANSPORT: + decode_result = decode_uplink_nas_transport(&msg->uplink_nas_transport, buffer, len); + break; + case AUTHENTICATION_REJECT: + decode_result = decode_authentication_reject(&msg->authentication_reject, buffer, len); + break; + case AUTHENTICATION_FAILURE: + decode_result = decode_authentication_failure(&msg->authentication_failure, buffer, len); + break; + case DETACH_ACCEPT: + decode_result = decode_detach_accept(&msg->detach_accept, buffer, len); + break; + case SERVICE_REJECT: + decode_result = decode_service_reject(&msg->service_reject, buffer, len); + break; + case AUTHENTICATION_REQUEST: + decode_result = decode_authentication_request(&msg->authentication_request, buffer, len); + break; + case TRACKING_AREA_UPDATE_REQUEST: + decode_result = decode_tracking_area_update_request(&msg->tracking_area_update_request, buffer, len); + break; + case ATTACH_REQUEST: + decode_result = decode_attach_request(&msg->attach_request, buffer, len); + break; + case EMM_STATUS: + decode_result = decode_emm_status(&msg->emm_status, buffer, len); + break; + case IDENTITY_RESPONSE: + decode_result = decode_identity_response(&msg->identity_response, buffer, len); + break; + case IDENTITY_REQUEST: + decode_result = decode_identity_request(&msg->identity_request, buffer, len); + break; + case GUTI_REALLOCATION_COMMAND: + decode_result = decode_guti_reallocation_command(&msg->guti_reallocation_command, buffer, len); + break; + case TRACKING_AREA_UPDATE_REJECT: + decode_result = decode_tracking_area_update_reject(&msg->tracking_area_update_reject, buffer, len); + break; + case ATTACH_ACCEPT: + decode_result = decode_attach_accept(&msg->attach_accept, buffer, len); + break; + case SECURITY_MODE_COMPLETE: + decode_result = decode_security_mode_complete(&msg->security_mode_complete, buffer, len); + break; + case TRACKING_AREA_UPDATE_ACCEPT: + decode_result = decode_tracking_area_update_accept(&msg->tracking_area_update_accept, buffer, len); + break; + case ATTACH_REJECT: + decode_result = decode_attach_reject(&msg->attach_reject, buffer, len); + break; + case ATTACH_COMPLETE: + decode_result = decode_attach_complete(&msg->attach_complete, buffer, len); + break; + case TRACKING_AREA_UPDATE_COMPLETE: + decode_result = decode_tracking_area_update_complete(&msg->tracking_area_update_complete, buffer, len); + break; + case CS_SERVICE_NOTIFICATION: + decode_result = decode_cs_service_notification(&msg->cs_service_notification, buffer, len); + break; + case SECURITY_MODE_REJECT: + decode_result = decode_security_mode_reject(&msg->security_mode_reject, buffer, len); + break; + case DETACH_REQUEST: + decode_result = decode_detach_request(&msg->detach_request, buffer, len); + break; + case GUTI_REALLOCATION_COMPLETE: + decode_result = decode_guti_reallocation_complete(&msg->guti_reallocation_complete, buffer, len); + break; + case SECURITY_MODE_COMMAND: + decode_result = decode_security_mode_command(&msg->security_mode_command, buffer, len); + break; + case DOWNLINK_NAS_TRANSPORT: + decode_result = decode_downlink_nas_transport(&msg->downlink_nas_transport, buffer, len); + break; + case EXTENDED_SERVICE_REQUEST: + decode_result = decode_extended_service_request(&msg->extended_service_request, buffer, len); + break; + case AUTHENTICATION_RESPONSE: + decode_result = decode_authentication_response(&msg->authentication_response, buffer, len); + break; + default: + LOG_TRACE(ERROR, "EMM-MSG - Unexpected message type: 0x%x", + msg->header.message_type); + decode_result = TLV_DECODE_WRONG_MESSAGE_TYPE; + /* TODO: Handle not standard layer 3 messages: SERVICE_REQUEST */ + } + + if (decode_result < 0) { + LOG_TRACE(ERROR, "EMM-MSG - Failed to decode L3 EMM message 0x%x " + "(%d)", msg->header.message_type, decode_result); + LOG_FUNC_RETURN (decode_result); + } + LOG_FUNC_RETURN (header_result + decode_result); +} + +/**************************************************************************** + ** ** + ** Name: emm_msg_encode() ** + ** ** + ** Description: Encode EPS Mobility Management messages ** + ** ** + ** Inputs: msg: The EMM message structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_msg_encode(EMM_msg *msg, uint8_t *buffer, uint32_t len) +{ + LOG_FUNC_IN; + + int header_result; + int encode_result; + + /* First encode the EMM message header */ + header_result = _emm_msg_encode_header(&msg->header, buffer, len); + if (header_result < 0) { + LOG_TRACE(ERROR, "EMM-MSG - Failed to encode EMM message header " + "(%d)", header_result); + LOG_FUNC_RETURN(header_result); + } + + buffer += header_result; + len -= header_result; + + switch(msg->header.message_type) + { + case EMM_INFORMATION: + encode_result = encode_emm_information(&msg->emm_information, buffer, len); + break; + case UPLINK_NAS_TRANSPORT: + encode_result = encode_uplink_nas_transport(&msg->uplink_nas_transport, buffer, len); + break; + case AUTHENTICATION_REJECT: + encode_result = encode_authentication_reject(&msg->authentication_reject, buffer, len); + break; + case AUTHENTICATION_FAILURE: + encode_result = encode_authentication_failure(&msg->authentication_failure, buffer, len); + break; + case DETACH_ACCEPT: + encode_result = encode_detach_accept(&msg->detach_accept, buffer, len); + break; + case SERVICE_REJECT: + encode_result = encode_service_reject(&msg->service_reject, buffer, len); + break; + case AUTHENTICATION_REQUEST: + encode_result = encode_authentication_request(&msg->authentication_request, buffer, len); + break; + case TRACKING_AREA_UPDATE_REQUEST: + encode_result = encode_tracking_area_update_request(&msg->tracking_area_update_request, buffer, len); + break; + case ATTACH_REQUEST: + encode_result = encode_attach_request(&msg->attach_request, buffer, len); + break; + case EMM_STATUS: + encode_result = encode_emm_status(&msg->emm_status, buffer, len); + break; + case IDENTITY_RESPONSE: + encode_result = encode_identity_response(&msg->identity_response, buffer, len); + break; + case IDENTITY_REQUEST: + encode_result = encode_identity_request(&msg->identity_request, buffer, len); + break; + case GUTI_REALLOCATION_COMMAND: + encode_result = encode_guti_reallocation_command(&msg->guti_reallocation_command, buffer, len); + break; + case TRACKING_AREA_UPDATE_REJECT: + encode_result = encode_tracking_area_update_reject(&msg->tracking_area_update_reject, buffer, len); + break; + case ATTACH_ACCEPT: + encode_result = encode_attach_accept(&msg->attach_accept, buffer, len); + break; + case SECURITY_MODE_COMPLETE: + encode_result = encode_security_mode_complete(&msg->security_mode_complete, buffer, len); + break; + case TRACKING_AREA_UPDATE_ACCEPT: + encode_result = encode_tracking_area_update_accept(&msg->tracking_area_update_accept, buffer, len); + break; + case ATTACH_REJECT: + encode_result = encode_attach_reject(&msg->attach_reject, buffer, len); + break; + case ATTACH_COMPLETE: + encode_result = encode_attach_complete(&msg->attach_complete, buffer, len); + break; + case TRACKING_AREA_UPDATE_COMPLETE: + encode_result = encode_tracking_area_update_complete(&msg->tracking_area_update_complete, buffer, len); + break; + case CS_SERVICE_NOTIFICATION: + encode_result = encode_cs_service_notification(&msg->cs_service_notification, buffer, len); + break; + case SECURITY_MODE_REJECT: + encode_result = encode_security_mode_reject(&msg->security_mode_reject, buffer, len); + break; + case DETACH_REQUEST: + encode_result = encode_detach_request(&msg->detach_request, buffer, len); + break; + case GUTI_REALLOCATION_COMPLETE: + encode_result = encode_guti_reallocation_complete(&msg->guti_reallocation_complete, buffer, len); + break; + case SECURITY_MODE_COMMAND: + encode_result = encode_security_mode_command(&msg->security_mode_command, buffer, len); + break; + case DOWNLINK_NAS_TRANSPORT: + encode_result = encode_downlink_nas_transport(&msg->downlink_nas_transport, buffer, len); + break; + case EXTENDED_SERVICE_REQUEST: + encode_result = encode_extended_service_request(&msg->extended_service_request, buffer, len); + break; + case AUTHENTICATION_RESPONSE: + encode_result = encode_authentication_response(&msg->authentication_response, buffer, len); + break; + case SERVICE_REQUEST: + encode_result = encode_service_request(&msg->service_request, buffer, len); + break; + default: + LOG_TRACE(ERROR, "EMM-MSG - Unexpected message type: 0x%x", + msg->header.message_type); + encode_result = TLV_ENCODE_WRONG_MESSAGE_TYPE; + /* TODO: Handle not standard layer 3 messages: SERVICE_REQUEST */ + } + + if (encode_result < 0) { + LOG_TRACE(ERROR, "EMM-MSG - Failed to encode L3 EMM message 0x%x " + "(%d)", msg->header.message_type, encode_result); + } + LOG_FUNC_RETURN (header_result + encode_result); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _emm_msg_decode_header() ** + ** ** + ** Description: Decode header of EPS Mobility Management message. ** + ** The protocol discriminator and the security header type ** + ** have already been decoded. ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the EMM ** + ** message ** + ** len: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: header: The EMM message header to be filled ** + ** Return: The size of the header if data have been ** + ** successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_msg_decode_header(emm_msg_header_t *header, + const uint8_t *buffer, uint32_t len) +{ + int size = 0; + + /* Check the buffer length */ + if (len < sizeof(emm_msg_header_t)) { + return (TLV_DECODE_BUFFER_TOO_SHORT); + } + /* Decode the security header type and the protocol discriminator */ + DECODE_U8(buffer + size, *(uint8_t*)(header), size); + /* Decode the message type */ + DECODE_U8(buffer + size, header->message_type, size); + + /* Check the protocol discriminator */ + if (header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE) { + LOG_TRACE(ERROR, "ESM-MSG - Unexpected protocol discriminator: 0x%x", + header->protocol_discriminator); + return (TLV_DECODE_PROTOCOL_NOT_SUPPORTED); + } + + return (size); +} + +/**************************************************************************** + ** ** + ** Name: _emm_msg_encode_header() ** + ** ** + ** The protocol discriminator and the security header type ** + ** have already been encoded. ** + ** ** + ** Inputs: header: The EMM message header to encode ** + ** len: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_msg_encode_header(const emm_msg_header_t *header, + uint8_t *buffer, uint32_t len) +{ + int size = 0; + + /* Check the buffer length */ + if (len < sizeof(emm_msg_header_t)) { + return (TLV_ENCODE_BUFFER_TOO_SHORT); + } + /* Check the protocol discriminator */ + if (header->protocol_discriminator != EPS_MOBILITY_MANAGEMENT_MESSAGE) { + LOG_TRACE(ERROR, "ESM-MSG - Unexpected protocol discriminator: 0x%x", + header->protocol_discriminator); + return (TLV_ENCODE_PROTOCOL_NOT_SUPPORTED); + } + + /* Encode the security header type and the protocol discriminator */ + ENCODE_U8(buffer + size, *(uint8_t*)(header), size); + /* Encode the message type */ + ENCODE_U8(buffer + size, header->message_type, size); + + return (size); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h new file mode 100644 index 0000000000..e72e35a193 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h @@ -0,0 +1,116 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_msg.h + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines EPS Mobility Management messages and functions used + to encode and decode + +*****************************************************************************/ +#ifndef __EMM_MSG_H__ +#define __EMM_MSG_H__ + +#include "emm_msgDef.h" + +#include "AttachRequest.h" +#include "AttachAccept.h" +#include "AttachComplete.h" +#include "AttachReject.h" +#include "DetachRequest.h" +#include "DetachAccept.h" +#include "TrackingAreaUpdateRequest.h" +#include "TrackingAreaUpdateAccept.h" +#include "TrackingAreaUpdateComplete.h" +#include "TrackingAreaUpdateReject.h" +#include "ExtendedServiceRequest.h" +#include "ServiceRequest.h" +#include "ServiceReject.h" +#include "GutiReallocationCommand.h" +#include "GutiReallocationComplete.h" +#include "AuthenticationRequest.h" +#include "AuthenticationResponse.h" +#include "AuthenticationReject.h" +#include "AuthenticationFailure.h" +#include "IdentityRequest.h" +#include "IdentityResponse.h" +#include "SecurityModeCommand.h" +#include "SecurityModeComplete.h" +#include "SecurityModeReject.h" +#include "EmmStatus.h" +#include "EmmInformation.h" +#include "DownlinkNasTransport.h" +#include "UplinkNasTransport.h" +#include "CsServiceNotification.h" + +#include <stdint.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Structure of EMM plain NAS message + * ---------------------------------- + */ +typedef union { + emm_msg_header_t header; + attach_request_msg attach_request; + attach_accept_msg attach_accept; + attach_complete_msg attach_complete; + attach_reject_msg attach_reject; + detach_request_msg detach_request; + detach_accept_msg detach_accept; + tracking_area_update_request_msg tracking_area_update_request; + tracking_area_update_accept_msg tracking_area_update_accept; + tracking_area_update_complete_msg tracking_area_update_complete; + tracking_area_update_reject_msg tracking_area_update_reject; + extended_service_request_msg extended_service_request; + service_request_msg service_request; + service_reject_msg service_reject; + guti_reallocation_command_msg guti_reallocation_command; + guti_reallocation_complete_msg guti_reallocation_complete; + authentication_request_msg authentication_request; + authentication_response_msg authentication_response; + authentication_reject_msg authentication_reject; + authentication_failure_msg authentication_failure; + identity_request_msg identity_request; + identity_response_msg identity_response; + security_mode_command_msg security_mode_command; + security_mode_complete_msg security_mode_complete; + security_mode_reject_msg security_mode_reject; + emm_status_msg emm_status; + emm_information_msg emm_information; + downlink_nas_transport_msg downlink_nas_transport; + uplink_nas_transport_msg uplink_nas_transport; + cs_service_notification_msg cs_service_notification; +} EMM_msg; + + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int emm_msg_decode(EMM_msg *msg, uint8_t *buffer, uint32_t len); + +int emm_msg_encode(EMM_msg *msg, uint8_t *buffer, uint32_t len); + +#endif /* __EMM_MSG_H__ */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h new file mode 100644 index 0000000000..50efcadbda --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h @@ -0,0 +1,116 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel, Sebastien Roux + +Description Defines identifiers of the EPS Mobility Management messages. + +*****************************************************************************/ +#ifndef __EMM_MSGDEF_H__ +#define __EMM_MSGDEF_H__ + +#include <stdint.h> +#include <asm/byteorder.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Header length boundaries of EPS Mobility Management messages */ +#define EMM_HEADER_LENGTH sizeof(emm_msg_header_t) +#define EMM_HEADER_MINIMUM_LENGTH EMM_HEADER_LENGTH +#define EMM_HEADER_MAXIMUM_LENGTH EMM_HEADER_LENGTH + +/* Protocol discriminator identifier for EPS Mobility Management */ +#define EPS_MOBILITY_MANAGEMENT_MESSAGE 0x7 + +/* EPS Mobility Management Security header type */ +#define SECURITY_HEADER_TYPE_NOT_PROTECTED 0b0000 +#define SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED 0b0001 +#define SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED 0b0010 +#define SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_NEW 0b0011 +#define SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED_NEW 0b0100 +#define SECURITY_HEADER_TYPE_SERVICE_REQUEST 0b1100 + +/* Message identifiers for EPS Mobility Management */ +# define ATTACH_REQUEST 0b01000001 /* 65 = 0x41 */ +# define ATTACH_ACCEPT 0b01000010 /* 66 = 0x42 */ +# define ATTACH_COMPLETE 0b01000011 /* 67 = 0x43 */ +# define ATTACH_REJECT 0b01000100 /* 68 = 0x44 */ +# define DETACH_REQUEST 0b01000101 /* 69 = 0x45 */ +# define DETACH_ACCEPT 0b01000110 /* 70 = 0x46 */ +# define TRACKING_AREA_UPDATE_REQUEST 0b01001000 /* 72 = 0x48 */ +# define TRACKING_AREA_UPDATE_ACCEPT 0b01001001 /* 73 = 0x49 */ +# define TRACKING_AREA_UPDATE_COMPLETE 0b01001010 /* 74 = 0x4a */ +# define TRACKING_AREA_UPDATE_REJECT 0b01001011 /* 75 = 0x4b */ +# define EXTENDED_SERVICE_REQUEST 0b01001100 /* 76 = 0x4c */ +# define SERVICE_REJECT 0b01001110 /* 78 = 0x4e */ +# define GUTI_REALLOCATION_COMMAND 0b01010000 /* 80 = 0x50 */ +# define GUTI_REALLOCATION_COMPLETE 0b01010001 /* 81 = 0x51 */ +# define AUTHENTICATION_REQUEST 0b01010010 /* 82 = 0x52 */ +# define AUTHENTICATION_RESPONSE 0b01010011 /* 83 = 0x53 */ +# define AUTHENTICATION_REJECT 0b01010100 /* 84 = 0x54 */ +# define AUTHENTICATION_FAILURE 0b01011100 /* 92 = 0x5c */ +# define IDENTITY_REQUEST 0b01010101 /* 85 = 0x55 */ +# define IDENTITY_RESPONSE 0b01010110 /* 86 = 0x56 */ +# define SECURITY_MODE_COMMAND 0b01011101 /* 93 = 0x5d */ +# define SECURITY_MODE_COMPLETE 0b01011110 /* 94 = 0x5e */ +# define SECURITY_MODE_REJECT 0b01011111 /* 95 = 0x5f */ +# define EMM_STATUS 0b01100000 /* 96 = 0x60 */ +# define EMM_INFORMATION 0b01100001 /* 97 = 0x61 */ +# define DOWNLINK_NAS_TRANSPORT 0b01100010 /* 98 = 0x62 */ +# define UPLINK_NAS_TRANSPORT 0b01100011 /* 99 = 0x63 */ +# define CS_SERVICE_NOTIFICATION 0b01100100 /* 100 = 0x64 */ + +/* + * Message identifiers for EMM messages that does not follow the structure + * of a standard layer 3 message + */ +# define SERVICE_REQUEST 0b01001101 /* TODO: TBD - 77 = 0x4d */ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Header of EPS Mobility Management plain NAS message + * --------------------------------------------------- + * 8 7 6 5 4 3 2 1 + * +-----------------------+------------------------+ + * | Security header type | Protocol discriminator | + * +-----------------------+------------------------+ + * | Message type | + * +-----------------------+------------------------+ + */ +typedef struct { +#ifdef __LITTLE_ENDIAN_BITFIELD + uint8_t protocol_discriminator:4; + uint8_t security_header_type:4; +#endif +#ifdef __BIG_ENDIAN_BITFIELD + uint8_t security_header_type:4; + uint8_t protocol_discriminator:4; +#endif + uint8_t message_type; +}__attribute__((__packed__)) emm_msg_header_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __EMM_MSGDEF_H__ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmCommonProcedureInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmCommonProcedureInitiated.c new file mode 100644 index 0000000000..378805f8f9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmCommonProcedureInitiated.c @@ -0,0 +1,155 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmCommonProcedureInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-COMMON-PROCEDURE-INITIATED state. + + In EMM-COMMON-PROCEDURE-INITIATED state, the MME has started + a common EMM procedure and is waiting for a response from the + UE. + +*****************************************************************************/ + +#ifdef NAS_MME + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "EmmCommon.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmCommonProcedureInitiated() ** + ** ** + ** Description: Handles the behaviour of the MME while the EMM-SAP is in ** + ** EMM_COMMON_PROCEDURE_INITIATED state. ** + ** ** + ** 3GPP TS 24.301, section 5.1.3.4.2 ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmCommonProcedureInitiated(const emm_reg_t* evt) +{ + int rc = RETURNerror; + + LOG_FUNC_IN; + + assert(emm_fsm_get_status(evt->ueid, evt->ctx) == EMM_COMMON_PROCEDURE_INITIATED); + + switch (evt->primitive) + { + case _EMMREG_PROC_ABORT: + /* + * The EMM procedure that initiated EMM common procedure aborted + */ + rc = emm_proc_common_abort(evt->ueid); + break; + + case _EMMREG_COMMON_PROC_CNF: + /* + * An EMM common procedure successfully completed; + */ + if (evt->u.common.is_attached) { + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_REGISTERED); + } else { + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_DEREGISTERED); + } + if (rc != RETURNerror) { + rc = emm_proc_common_success(evt->ueid); + } + break; + + case _EMMREG_COMMON_PROC_REJ: + /* + * An EMM common procedure failed; + * enter state EMM-DEREGISTERED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_DEREGISTERED); + if (rc != RETURNerror) { + rc = emm_proc_common_reject(evt->ueid); + } + break; + + case _EMMREG_ATTACH_CNF: + /* + * Attach procedure successful and default EPS bearer + * context activated; + * enter state EMM-REGISTERED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_REGISTERED); + break; + + case _EMMREG_ATTACH_REJ: + /* + * Attach procedure failed; + * enter state EMM-DEREGISTERED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_DEREGISTERED); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data successfully delivered to the network + */ + rc = RETURNok; + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Transmission failure occurred before the EMM common + * procedure being completed + */ + rc = emm_proc_common_failure(evt->ueid); + if (rc != RETURNerror) { + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_DEREGISTERED); + } + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregistered.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregistered.c new file mode 100644 index 0000000000..8daf854c1b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregistered.c @@ -0,0 +1,202 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregistered.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED state. + + In EMM-DEREGISTERED state, no EMM context has been established + or the EMM context is marked as detached. + The UE shall start the attach or combined attach procedure to + establish an EMM context. + + The MME may answer to an attach or a combined attach procedure + initiated by the UE. It may also answer to a tracking area + updating procedure or combined tracking area updating procedure + initiated by a UE if the EMM context is marked as detached. + +*****************************************************************************/ + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregistered() ** + ** ** + ** Description: Handles the behaviour of the UE and the MME while the ** + ** EMM-SAP is in EMM-DEREGISTERED state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.2 ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregistered(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + +#ifdef NAS_UE + assert(emm_fsm_get_status() == EMM_DEREGISTERED); +#endif +#ifdef NAS_MME + assert(emm_fsm_get_status(evt->ueid, evt->ctx) == EMM_DEREGISTERED); +#endif + +#ifdef NAS_UE + /* Delete the authentication data RAND and RES */ + rc = emm_proc_authentication_delete(); + if (rc != RETURNok) { + LOG_FUNC_RETURN (rc); + } + /* TODO: 3GPP TS 24.301, section 4.4.2.1 + * The UE shall store the current native EPS security context as specified + * in annex C and mark it as valid only when the UE enters state EMM- + * DEREGISTERED from any other state except EMM-NULL or when the UE aborts + * the attach procedure without having left EMM-DEREGISTERED. + */ +#endif + + switch (evt->primitive) + { + +#ifdef NAS_UE + case _EMMREG_NO_IMSI: + /* + * The UE was powered on without a valid USIM application present + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_NO_IMSI); + break; + + case _EMMREG_REGISTER_REQ: + /* + * The default EMM primary substate when the UE is switched on + * with valid USIM application shall be PLMN-SEARCH + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_PLMN_SEARCH); + if (rc != RETURNerror) { + /* Process the network registration request */ + rc = emm_fsm_process(evt); + } + break; + + case _EMMREG_ATTACH_INIT: + /* + * Attach procedure has to be restarted (timers T3402 or T3411 + * expired) while the UE locally detached from the network + */ + + /* Move to the corresponding initial EMM state */ + if (evt->u.attach.is_emergency) { + rc = emm_fsm_set_status(EMM_DEREGISTERED_LIMITED_SERVICE); + } else { + rc = emm_fsm_set_status(EMM_DEREGISTERED_NORMAL_SERVICE); + } + if (rc != RETURNerror) { + /* Restart the attach procedure */ + rc = emm_proc_attach_restart(); + } + break; + +#endif + +#ifdef NAS_MME + case _EMMREG_PROC_ABORT: + /* + * Ongoing EMM procedure aborted + */ + rc = RETURNok; + break; + + case _EMMREG_COMMON_PROC_REQ: + /* + * An EMM common procedure has been initiated; + * enter state EMM-COMMON-PROCEDURE-INITIATED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_COMMON_PROCEDURE_INITIATED); + break; + + case _EMMREG_ATTACH_CNF: + /* + * Attach procedure successful and default EPS bearer + * context activated; + * enter state EMM-REGISTERED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_REGISTERED); + break; + +#endif + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data successfully delivered to the network + */ + rc = RETURNok; + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Data failed to be delivered to the network + */ + rc = RETURNok; + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + +#ifdef NAS_UE + /* TODO: 3GPP TS 24.301, section 4.4.2.1 + * The UE shall mark the EPS security context on the USIM or in the non- + * volatile memory as invalid when the UE initiates an attach procedure + * or when the UE leaves state EMM-DEREGISTERED for any other state except + * EMM-NULL. + */ +#endif + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttachNeeded.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttachNeeded.c new file mode 100644 index 0000000000..4ce29fe1e7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttachNeeded.c @@ -0,0 +1,78 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredAttachNeeded.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.ATTACH-NEEDED state. + + In EMM-DEREGISTERED.ATTACH-NEEDED state, Valid subscriber + data are available for the UE and for some reason an attach + must be performed as soon as possible. The access class may + be blocked due to access class control, or the network rejec- + ted the NAS signalling connection establishment. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredAttachNeeded() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.ATTACH-NEEDED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredAttachNeeded(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_ATTACH_NEEDED); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttemptingToAttach.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttemptingToAttach.c new file mode 100644 index 0000000000..5ab9027968 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredAttemptingToAttach.c @@ -0,0 +1,120 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredAttemptingToAttach.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.ATTEMPTING-TO-ATTACH + state. + + In EMM-DEREGISTERED.ATTEMPTING-TO-ATTACH state, the EPS update + status is EU2, and a previous attach was not successful. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredAttemptingToAttach() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.ATTEMPTING-TO-ATTACH state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.3 ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredAttemptingToAttach(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH); + + switch (evt->primitive) + { + case _EMMREG_ATTACH_INIT: + /* + * Attach procedure has to be restarted (timers T3402 or T3411 + * expired) + */ + + /* Move to the corresponding initial EMM state */ + if (evt->u.attach.is_emergency) { + rc = emm_fsm_set_status(EMM_DEREGISTERED_LIMITED_SERVICE); + } else { + rc = emm_fsm_set_status(EMM_DEREGISTERED_NORMAL_SERVICE); + } + if (rc != RETURNerror) { + /* Restart the attach procedure */ + rc = emm_proc_attach_restart(); + } + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data successfully delivered to the network + */ + rc = emm_proc_lowerlayer_success(); + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Data failed to be delivered to the network + */ + rc = emm_proc_lowerlayer_failure(FALSE); + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredInitiated.c new file mode 100644 index 0000000000..aec629cb15 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredInitiated.c @@ -0,0 +1,128 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED-INITIATED state. + + In EMM-DEREGISTERED-INITIATED state, the UE has requested + release of the EMM context by starting the detach or combined + detach procedure and is waiting for a response from the MME. + The MME has started a detach procedure and is waiting for a + response from the UE. + +*****************************************************************************/ + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredInitiated() ** + ** ** + ** Description: Handles the behaviour of the UE and the MME while the ** + ** EMM-SAP is in EMM-DEREGISTERED-INITIATED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredInitiated(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + +#ifdef NAS_UE + assert(emm_fsm_get_status() == EMM_DEREGISTERED_INITIATED); +#endif +#ifdef NAS_MME + assert(emm_fsm_get_status(evt->ueid, evt->ctx) == EMM_DEREGISTERED_INITIATED); +#endif + + switch (evt->primitive) + { +#ifdef NAS_UE + case _EMMREG_DETACH_CNF: + /* + * The UE explicitly detached from the network (all EPS + * bearer contexts have been deactivated as UE initiated + * detach procedure successfully completed) + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED); + break; + + case _EMMREG_DETACH_FAILED: + /* + * The detach procedure failed + */ + if (evt->u.detach.type == EMM_DETACH_TYPE_IMSI) { + rc = emm_fsm_set_status(EMM_REGISTERED_NORMAL_SERVICE); + } else { + rc = emm_fsm_set_status(EMM_DEREGISTERED); + } + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Ignore Detach Request message successful retransmission + */ + rc = RETURNok; + break; + + case _EMMREG_LOWERLAYER_FAILURE: + case _EMMREG_LOWERLAYER_RELEASE: + /* + * Lower layer failure or release of the NAS signalling connection + * before the Detach Accept is received + */ + rc = emm_proc_lowerlayer_release(); + break; +#endif + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredLimitedService.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredLimitedService.c new file mode 100644 index 0000000000..3c43682b34 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredLimitedService.c @@ -0,0 +1,141 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredLimitedService.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.LIMITED-SERVICE state. + + In EMM-DEREGISTERED.LIMITED-SERVICE state, the EPS update + status is EU3, and it is known that a selected cell is unable + to provide normal service. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredLimitedService() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.LIMITED-SERVICE state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.2 ** + ** The UE shall initiate an attach or combined attach proce- ** + ** dure when entering a cell which provides normal service. ** + ** It may initiate attach for emergency bearer services. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredLimitedService(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_LIMITED_SERVICE); + + switch (evt->primitive) + { + case _EMMREG_REGISTER_REQ: + /* + * The user manually re-selected a PLMN to register to + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_PLMN_SEARCH); + if (rc != RETURNerror) { + /* Process the network registration request */ + rc = emm_fsm_process(evt); + } + break; + + case _EMMREG_ATTACH_INIT: + /* + * Initiate attach procedure for emergency bearer services + */ + rc = emm_proc_attach(EMM_ATTACH_TYPE_EMERGENCY); + break; + + case _EMMREG_ATTACH_REQ: + /* + * An attach for bearer emergency services has been requested + * (Attach Request message successfully delivered to the network); + * enter state EMM-REGISTERED-INITIATED + */ + rc = emm_fsm_set_status(EMM_REGISTERED_INITIATED); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Initial NAS message has been successfully delivered + * to the network + */ + rc = emm_proc_lowerlayer_success(); + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Initial NAS message failed to be delivered to the network + */ + rc = emm_proc_lowerlayer_failure(TRUE); + break; + + case _EMMREG_LOWERLAYER_RELEASE: + /* + * NAS signalling connection has been released + */ + rc = emm_proc_lowerlayer_release(); + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoCellAvailable.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoCellAvailable.c new file mode 100644 index 0000000000..5d92edbad3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoCellAvailable.c @@ -0,0 +1,120 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredNoCellAvailable.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.NO-CELL-AVAILABLE + state. + + In EMM-DEREGISTERED.NO-CELL-AVAILABLE state, no E-UTRAN cell + can be selected. A first intensive search failed when in + substate EMM_DEREGISTERED.PLMN-SEARCH. Cells are searched for + at a low rhythm. No EPS services are offered. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredNoCellAvailable() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.NO-CELL-AVAILABLE state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.7 ** + ** The UE shall perform cell selection and choose an appro- ** + ** priate substate when a cell is found. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredNoCellAvailable(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_NO_CELL_AVAILABLE); + + switch (evt->primitive) + { + /* TODO: network re-selection is not allowed when in No Cell + * Available substate. The AS should search for a suitable cell + * and notify the NAS when such a cell is found (TS 24.008 section + * 4.2.4.1.2) */ + case _EMMREG_REGISTER_REQ: + /* + * The user manually re-selected a PLMN to register to + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_PLMN_SEARCH); + + if (rc != RETURNerror) { + /* + * Notify EMM that the MT is currently searching an operator + * to register to + */ + rc = emm_proc_registration_notify(NET_REG_STATE_ON); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-FSM - " + "Failed to notify registration update"); + } + /* + * Perform network re-selection procedure + */ + rc = emm_proc_plmn_selection(evt->u.regist.index); + } + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoImsi.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoImsi.c new file mode 100644 index 0000000000..351e823bde --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNoImsi.c @@ -0,0 +1,79 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredNoImsi.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.NO-IMSI state. + + In EMM-DEREGISTERED.NO-IMSI state, the UE is switched on + without a valid USIM inserted. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredNoImsi() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.NO-IMSI state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.5 ** + ** The UE shall perform cell selection and may initiate ** + ** attach for emergency bearer services. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredNoImsi(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_NO_IMSI); + + LOG_TRACE(ERROR, "EMM-FSM - USIM is not present or not valid"); + + LOG_FUNC_RETURN (RETURNerror); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNormalService.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNormalService.c new file mode 100644 index 0000000000..c1b9a9c776 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredNormalService.c @@ -0,0 +1,141 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredNormalService.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.NORMAL-SERVICE state. + + In EMM-DEREGISTERED.NORMAL-SERVICE state, the EPS update + status is EU1 or EU2, in the meantime a suitable cell has + been found and the PLMN or tracking area is not in the + forbidden list. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredNormalService() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.NORMAL-SERVICE state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.1 ** + ** The UE shall initiate an attach or combined attach proce- ** + ** dure. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredNormalService(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_NORMAL_SERVICE); + + switch (evt->primitive) + { + case _EMMREG_REGISTER_REQ: + /* + * The user manually re-selected a PLMN to register to + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_PLMN_SEARCH); + if (rc != RETURNerror) { + /* Process the network registration request */ + rc = emm_fsm_process(evt); + } + break; + + case _EMMREG_ATTACH_INIT: + /* + * Initiate the attach procedure for EPS services + */ + rc = emm_proc_attach(EMM_ATTACH_TYPE_EPS); + break; + + case _EMMREG_ATTACH_REQ: + /* + * An EPS network attach has been requested (Attach Request + * message successfully delivered to the network); + * enter state EMM-REGISTERED-INITIATED + */ + rc = emm_fsm_set_status(EMM_REGISTERED_INITIATED); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Initial NAS message has been successfully delivered + * to the network + */ + rc = emm_proc_lowerlayer_success(); + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Initial NAS message failed to be delivered to the network + */ + rc = emm_proc_lowerlayer_failure(TRUE); + break; + + case _EMMREG_LOWERLAYER_RELEASE: + /* + * NAS signalling connection has been released + */ + rc = emm_proc_lowerlayer_release(); + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredPlmnSearch.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredPlmnSearch.c new file mode 100644 index 0000000000..5b46d691c8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmDeregisteredPlmnSearch.c @@ -0,0 +1,136 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmDeregisteredPlmnSearch.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-DEREGISTERED.PLMN-SEARCH state. + + In EMM-DEREGISTERED.PLMN-SEARCH state, the UE with a valid + USIM is switched on. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmDeregisteredPlmnSearch() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-DEREGISTERED.PLMN-SEARCH state. ** + ** ** + ** 3GPP TS 24.301, section 5.2.2.3.4 ** + ** The UE shall perform PLMN selection. If a new PLMN is ** + ** selected, the UE shall reset the attach attempt counter ** + ** and initiate the attach or combined attach procedure. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmDeregisteredPlmnSearch(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_DEREGISTERED_PLMN_SEARCH); + + switch (evt->primitive) + { + case _EMMREG_NO_CELL: + /* + * No suitable cell of the selected PLMN has been found to camp on + */ + rc = emm_proc_registration_notify(NET_REG_STATE_DENIED); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-FSM - " + "Failed to notify registration update"); + } + rc = emm_fsm_set_status(EMM_DEREGISTERED_NO_CELL_AVAILABLE); + break; + + case _EMMREG_REGISTER_REQ: + /* + * The UE has been switched on and is currently searching an + * operator to register to. The particular PLMN to be contacted + * may be selected either automatically or manually. + * Or the user manually re-selected a PLMN to register to. + */ + rc = emm_proc_registration_notify(NET_REG_STATE_ON); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-FSM - " + "Failed to notify registration update"); + } + /* + * Perform network selection procedure + */ + rc = emm_proc_plmn_selection(evt->u.regist.index); + break; + + case _EMMREG_REGISTER_REJ: + /* + * The selected cell is known not to be able to provide normal + * service + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_LIMITED_SERVICE); + break; + + case _EMMREG_REGISTER_CNF: + /* + * A suitable cell of the selected PLMN has been found to camp on + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_NORMAL_SERVICE); + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmNull.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmNull.c new file mode 100644 index 0000000000..482ac6fccb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmNull.c @@ -0,0 +1,110 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmNull.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-NULL state. + + In EMM-NULL state, the EPS capability is disabled in the UE. + No EPS mobility management function shall be performed. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmNull() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-NULL state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmNull(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc; + + assert(emm_fsm_get_status() == EMM_NULL); + + /* Delete the authentication data RAND and RES */ + rc = emm_proc_authentication_delete(); + if (rc != RETURNok) { + LOG_FUNC_RETURN (rc); + } + + switch (evt->primitive) + { + case _EMMREG_S1_ENABLED: + /* + * The EPS capability has been enabled in the UE: + * Move to the DEREGISTERED state; + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED); + + /* + * And initialize the EMM procedure call manager in order to + * establish an EMM context and make the UE reachable by an MME. + */ + if (rc != RETURNerror) { + rc = emm_proc_initialize(); + } + break; + + default: + rc = RETURNerror; + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + LOG_TRACE(WARNING, "EMM-FSM - Set phone functionnality to " + "enable EPS capability (+cfun=1)"); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegistered.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegistered.c new file mode 100644 index 0000000000..e74205f811 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegistered.c @@ -0,0 +1,196 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegistered.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED state. + + In EMM-REGISTERED state, an EMM context has been established + and a default EPS bearer context has been activated in the UE + and the MME. + The UE may initiate sending and receiving user data and signal- + ling information and reply to paging. Additionally, tracking + area updating or combined tracking area updating procedure is + performed. + +*****************************************************************************/ + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegistered() ** + ** ** + ** Description: Handles the behaviour of the UE and the MME while the ** + ** EMM-SAP is in EMM-REGISTERED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegistered(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + +#ifdef NAS_UE + assert(emm_fsm_get_status() == EMM_REGISTERED); +#endif +#ifdef NAS_MME + assert(emm_fsm_get_status(evt->ueid, evt->ctx) == EMM_REGISTERED); +#endif + + switch (evt->primitive) + { +#ifdef NAS_UE + case _EMMREG_DETACH_INIT: + /* + * Initiate detach procedure for EPS services + */ + rc = emm_proc_detach(EMM_DETACH_TYPE_EPS, evt->u.detach.switch_off); + break; + + case _EMMREG_DETACH_REQ: + /* + * Network detach has been requested (Detach Request + * message successfully delivered to the network); + * enter state EMM-DEREGISTERED-INITIATED + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_INITIATED); + break; + + case _EMMREG_DETACH_CNF: + /* + * The UE implicitly detached from the network (all EPS + * bearer contexts may have been deactivated) + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED); + break; + + case _EMMREG_TAU_REQ: + /* + * TODO: Tracking Area Update has been requested + */ + LOG_TRACE(ERROR, "EMM-FSM - Tracking Area Update procedure " + "is not implemented"); + break; + + case _EMMREG_SERVICE_REQ: + /* + * TODO: Service Request has been requested + */ + LOG_TRACE(ERROR, "EMM-FSM - Service Request procedure " + "is not implemented"); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data transfer message has been successfully delivered + */ + rc = emm_proc_lowerlayer_success(); + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Data transfer message failed to be delivered + */ + rc = emm_proc_lowerlayer_failure(FALSE); + break; + + case _EMMREG_LOWERLAYER_RELEASE: + /* + * NAS signalling connection has been released + */ + rc = emm_proc_lowerlayer_release(); + break; +#endif + +#ifdef NAS_MME + case _EMMREG_DETACH_REQ: + /* + * Network detach has been requested (implicit detach); + * enter state EMM-DEREGISTERED + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_DEREGISTERED); + break; + + case _EMMREG_COMMON_PROC_REQ: + /* + * An EMM common procedure has been initiated; + * enter state EMM-COMMON-PROCEDURE-INITIATED. + */ + rc = emm_fsm_set_status(evt->ueid, evt->ctx, EMM_COMMON_PROCEDURE_INITIATED); + break; + + case _EMMREG_TAU_REJ: + /* + * TODO: Tracking Area Update has been rejected + */ + LOG_TRACE(ERROR, "EMM-FSM - Tracking Area Update procedure " + "is not implemented"); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data successfully delivered to the network + */ + rc = RETURNok; + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Data failed to be delivered to the network + */ + rc = RETURNok; + break; +#endif + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredAttemptingToUpdate.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredAttemptingToUpdate.c new file mode 100644 index 0000000000..cc8f837894 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredAttemptingToUpdate.c @@ -0,0 +1,80 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredAttemptingToUpdate.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.ATTEMPTING-TO-UPDATE + state. + + In EMM-REGISTERED.ATTEMPTING-TO-UPDATE state, the tracking + area updating or combined tracking area updating procedure + failed due to a missing response from the network. + No EMM procedure except the tracking area updating or com- + bined tracking area updating procedure shall be initiated + by the UE in this substate. No data shall be sent or received. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredAttemptingToUpdate() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.ATTEMPTING-TO-UPDATE state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredAttemptingToUpdate(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_ATTEMPTING_TO_UPDATE); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredImsiDetachInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredImsiDetachInitiated.c new file mode 100644 index 0000000000..702d2c7685 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredImsiDetachInitiated.c @@ -0,0 +1,79 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredImsiDetachInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.IMSI-DETACH-INITIATED + state. + + In EMM-REGISTERED.IMSI-DETACH-INITIATED state, the UE performs + a combined detach procedure for non-EPS services only. + The UE was attached for EPS and non-EPS services and wants to + detach for non-EPS services only. User data and signalling + information may be sent and received. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredImsiDetachInitiated() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.IMSI-DETACH-INITIATED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredImsiDetachInitiated(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_IMSI_DETACH_INITIATED); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredInitiated.c new file mode 100644 index 0000000000..8b9921d834 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredInitiated.c @@ -0,0 +1,240 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED-INITIATED state. + + In EMM-REGISTERED-INITIATED state, the attach or the combined + attach procedure has been started and the UE is waiting for a + response from the MME. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "networkDef.h" +#include "nas_log.h" + +#include "emm_proc.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredInitiated() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED-INITIATED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredInitiated(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + assert(emm_fsm_get_status() == EMM_REGISTERED_INITIATED); + + switch (evt->primitive) + { + case _EMMREG_ATTACH_INIT: + /* + * Attach procedure has to be restarted (timers T3402 or T3411 + * expired) + */ + + /* Move to the corresponding initial EMM state */ + if (evt->u.attach.is_emergency) { + rc = emm_fsm_set_status(EMM_DEREGISTERED_LIMITED_SERVICE); + } else { + rc = emm_fsm_set_status(EMM_DEREGISTERED_NORMAL_SERVICE); + } + if (rc != RETURNerror) { + /* Restart the attach procedure */ + rc = emm_proc_attach_restart(); + } + break; + + case _EMMREG_ATTACH_FAILED: + /* + * Attempt to attach to the network failed (abnormal case or + * timer T3410 expired). The network attach procedure shall be + * restarted when timer T3411 expires. + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH); + break; + + case _EMMREG_ATTACH_EXCEEDED: + /* + * Attempt to attach to the network failed (abnormal case or + * timer T3410 expired) and the attach attempt counter reached + * its maximum value. The state is changed to EMM-DEREGISTERED. + * ATTEMPTING-TO-ATTACH or optionally to EMM-DEREGISTERED.PLMN- + * SEARCH in order to perform a PLMN selection. + */ + /* TODO: ATTEMPTING-TO-ATTACH or PLMN-SEARCH ??? */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH); + break; + + case _EMMREG_ATTACH_CNF: + /* + * EPS network attach accepted by the network; + * enter state EMM-REGISTERED. + */ + rc = emm_fsm_set_status(EMM_REGISTERED); + + if (rc != RETURNerror) { + /* + * Notify EMM that the MT is registered + */ + rc = emm_proc_registration_notify(NET_REG_STATE_HN); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-FSM - " + "Failed to notify registration update"); + } + } + break; + + case _EMMREG_AUTH_REJ: + /* + * UE authentication rejected by the network; + * abort any EMM signalling procedure + */ + case _EMMREG_ATTACH_REJ: + /* + * EPS network attach rejected by the network; + * enter state EMM-DEREGISTERED. + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED); + + if (rc != RETURNerror) { + /* + * Notify EMM that the MT's registration is denied + */ + rc = emm_proc_registration_notify(NET_REG_STATE_DENIED); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMM-FSM - " + "Failed to notify registration update"); + } + } + break; + + case _EMMREG_REGISTER_REQ: + /* + * The UE has to select a new PLMN to register to + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_PLMN_SEARCH); + if (rc != RETURNerror) { + /* Process the network registration request */ + rc = emm_fsm_process(evt); + } + break; + + case _EMMREG_REGISTER_REJ: + /* + * The UE failed to register to the network for normal EPS service + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_LIMITED_SERVICE); + break; + + case _EMMREG_NO_IMSI: + /* + * The UE failed to register to the network for emergency + * bearer services + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_NO_IMSI); + break; + + case _EMMREG_DETACH_INIT: + /* + * Initiate detach procedure for EPS services + */ + rc = emm_proc_detach(EMM_DETACH_TYPE_EPS, evt->u.detach.switch_off); + break; + + case _EMMREG_DETACH_REQ: + /* + * An EPS network detach has been requested (Detach Request + * message successfully delivered to the network); + * enter state EMM-DEREGISTERED-INITIATED + */ + rc = emm_fsm_set_status(EMM_DEREGISTERED_INITIATED); + break; + + case _EMMREG_LOWERLAYER_SUCCESS: + /* + * Data transfer message has been successfully delivered; + * The NAS message may be Attach Complete, Detach Request or + * any message transfered by EMM common procedures requested + * by the network. + */ + rc = emm_proc_lowerlayer_success(); + break; + + case _EMMREG_LOWERLAYER_FAILURE: + /* + * Data transfer message failed to be delivered; + * The NAS message may be Attach Complete, Detach Request or + * any message transfered by EMM common procedures requested + * by the network. + */ + rc = emm_proc_lowerlayer_failure(FALSE); + break; + + case _EMMREG_LOWERLAYER_RELEASE: + /* + * NAS signalling connection has been released before the Attach + * Accept, Attach Reject, or any message transfered by EMM common + * procedures requested by the network, is received. + */ + rc = emm_proc_lowerlayer_release(); + break; + + default: + LOG_TRACE(ERROR, "EMM-FSM - Primitive is not valid (%d)", + evt->primitive); + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredLimitedService.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredLimitedService.c new file mode 100644 index 0000000000..022cae3f41 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredLimitedService.c @@ -0,0 +1,75 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredLimitedService.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.LIMITED-SERVICE state. + + In EMM-REGISTERED.LIMITED-SERVICE state, the cell the UE + selected is known not to be able to provide normal service. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredLimitedService() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.LIMITED-SERVICE state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredLimitedService(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_LIMITED_SERVICE); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNoCellAvailable.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNoCellAvailable.c new file mode 100644 index 0000000000..d82380ff81 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNoCellAvailable.c @@ -0,0 +1,76 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredNoCellAvailable.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.NO-CELL-AVAILABLE state. + + In EMM-REGISTERED.NO-CELL-AVAILABLE state, E-UTRAN coverage + has been lost. The UE shall not initiate any EMM procedures + except for cell and PLMN reselection. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredNoCellAvailable() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.NO-CELL-AVAILABLE state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredNoCellAvailable(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_NO_CELL_AVAILABLE); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNormalService.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNormalService.c new file mode 100644 index 0000000000..567048b8d5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredNormalService.c @@ -0,0 +1,75 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredNormalService.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.NORMAL-SERVICE state. + + The EMM-REGISTERED.NORMAL-SERVICE state is the primary + substate choosen when the UE enters the state EMM-REGISTERED. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredNormalService() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.NORMAL-SERVICE state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredNormalService(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_NORMAL_SERVICE); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredPlmnSearch.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredPlmnSearch.c new file mode 100644 index 0000000000..afa79e6017 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredPlmnSearch.c @@ -0,0 +1,103 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredPlmnSearch.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.PLMN-SEARCH state. + + In EMM-REGISTERED.PLMN-SEARCH state, the UE is searching + for PLMNs. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredPlmnSearch() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.PLMN-SEARCH state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredPlmnSearch(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_PLMN_SEARCH); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +#if 0 +/**************************************************************************** + ** ** + ** Name: EmmRegisteredPlmnSearch_xxx() ** + ** ** + ** Description: Procedure executed when xxx ** + ** while the EMM-SAP is in EMM-REGISTERED.PLMN-SEARCH state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredPlmnSearch_xxx(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_PLMN_SEARCH); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} +#endif + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredUpdateNeeded.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredUpdateNeeded.c new file mode 100644 index 0000000000..3d8fcce569 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmRegisteredUpdateNeeded.c @@ -0,0 +1,81 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmRegisteredUpdateNeeded.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-REGISTERED.UPDATE-NEEDED state. + + In EMM-REGISTERED.UPDATE-NEEDED state, the UE has to perform + a tracking area updating or combined tracking area updating + procedure, but access to the current cell is barred. The access + class may be blocked due to access class control, or the + network rejected the NAS signalling connection establishment. + No EMM procedure except tracking area updating or combined + tracking area updating or service request as a response to + paging shall be initiated by the UE in this substate. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmRegisteredUpdateNeeded() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-REGISTERED.UPDATE-NEEDED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmRegisteredUpdateNeeded(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_REGISTERED_UPDATE_NEEDED); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmServiceRequestInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmServiceRequestInitiated.c new file mode 100644 index 0000000000..da55c61a05 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmServiceRequestInitiated.c @@ -0,0 +1,77 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmServiceRequestInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-SERVICE-REQUEST-INITIATED + state. + + In EMM-SERVICE-REQUEST-INITIATED state, the UE has started + the service request procedure and is waiting for a response + from the MME. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmServiceRequestInitiated() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-SERVICE-REQUEST-INITIATED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmServiceRequestInitiated(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_SERVICE_REQUEST_INITIATED); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmTrackingAreaUpdatingInitiated.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmTrackingAreaUpdatingInitiated.c new file mode 100644 index 0000000000..2ecdc88249 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/EmmTrackingAreaUpdatingInitiated.c @@ -0,0 +1,77 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EmmTrackingAreaUpdatingInitiated.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Implements the EPS Mobility Management procedures executed + when the EMM-SAP is in EMM-TRACKING-AREA-UPDATING-INITIATED + state. + + In EMM-TRACKING-AREA-UPDATING-INITIATED state, the UE has + started the tracking area updating or combined tracking area + updating procedure and is waiting for a response from the MME. + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: EmmTrackingAreaUpdatingInitiated() ** + ** ** + ** Description: Handles the behaviour of the UE while the EMM-SAP is in ** + ** EMM-TRACKING-AREA-UPDATING-INITIATED state. ** + ** ** + ** Inputs: evt: The received EMM-SAP event ** + ** Others: emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: emm_fsm_status ** + ** ** + ***************************************************************************/ +int EmmTrackingAreaUpdatingInitiated(const emm_reg_t* evt) +{ + LOG_FUNC_IN; + + assert(emm_fsm_get_status() == EMM_TRACKING_AREA_UPDATING_INITIATED); + + /* TODO */ + + LOG_FUNC_RETURN (RETURNok); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#endif diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/Makefile b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/Makefile new file mode 100644 index 0000000000..31726ee67e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/Makefile @@ -0,0 +1,42 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(MMEAPIDIR) \ + -I$(EMMDIR) -I$(EMMMSGDIR) -I$(ESMMSGDIR) -I$(NETAPIDIR) + +TARGET = $(LIBEMMSAP) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c Makefile $(PROJDIR)/Makerules $(PROJDIR)/Makefile.inc + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.c new file mode 100644 index 0000000000..1015c12d7e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.c @@ -0,0 +1,1808 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_as.c + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMAS Service Access Point that provides + services to the EPS Mobility Management for NAS message + transfer to/from the Access Stratum sublayer. + +*****************************************************************************/ + +#include "emm_as.h" +#include "emm_recv.h" +#include "emm_send.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "TLVDecoder.h" +#include "as_message.h" +#include "nas_message.h" + +#include "emm_cause.h" +#include "LowerLayer.h" + +#include <string.h> // memset +#include <stdlib.h> // malloc, free + +#if defined(EPC_BUILD) +# include "intertask_interface.h" +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#ifdef NAS_UE +extern int emm_proc_plmn_selection_end(int found, tac_t tac, ci_t ci, AcT_t rat); +#endif + +extern int emm_proc_status(unsigned int ueid, int emm_cause); + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * String representation of EMMAS-SAP primitives + */ +static const char* _emm_as_primitive_str[] = { + "EMMAS_SECURITY_REQ", + "EMMAS_SECURITY_IND", + "EMMAS_SECURITY_RES", + "EMMAS_SECURITY_REJ", + "EMMAS_ESTABLISH_REQ", + "EMMAS_ESTABLISH_CNF", + "EMMAS_ESTABLISH_REJ", + "EMMAS_RELEASE_REQ", + "EMMAS_RELEASE_IND", + "EMMAS_DATA_REQ", + "EMMAS_DATA_IND", + "EMMAS_PAGE_IND", + "EMMAS_STATUS_IND", + "EMMAS_CELL_INFO_REQ", + "EMMAS_CELL_INFO_RES", + "EMMAS_CELL_INFO_IND", +}; + +/* + * Functions executed to process EMM procedures upon receiving + * data from the network + */ +static int _emm_as_recv(unsigned int ueid, const char* msg, int len, int *emm_cause); + +#ifdef NAS_UE +static int _emm_as_establish_cnf(const emm_as_establish_t* msg, int *emm_cause); +static int _emm_as_establish_rej(void); +static int _emm_as_release_ind(const emm_as_release_t* msg); +static int _emm_as_page_ind(const emm_as_page_t* msg); +#endif + +#ifdef NAS_MME +static int _emm_as_establish_req(const emm_as_establish_t* msg, int *emm_cause); +#endif + +static int _emm_as_cell_info_res(const emm_as_cell_info_t* msg); +static int _emm_as_cell_info_ind(const emm_as_cell_info_t* msg); + +static int _emm_as_data_ind(const emm_as_data_t* msg, int *emm_cause); + +/* + * Functions executed to send data to the network when requested + * within EMM procedure processing + */ +static EMM_msg* _emm_as_set_header(nas_message_t* msg, const emm_as_security_data_t* security); +static int _emm_as_encode(as_nas_info_t* info, nas_message_t* msg, int length); +static int _emm_as_encrypt(as_nas_info_t* info, const nas_message_security_header_t* header, const char* buffer, int length); +static int _emm_as_send(const emm_as_t* msg); + +#ifdef NAS_UE +static int _emm_as_security_res(const emm_as_security_t*, ul_info_transfer_req_t*); +static int _emm_as_establish_req(const emm_as_establish_t*, nas_establish_req_t*); +#endif + +#ifdef NAS_MME +static int _emm_as_security_req(const emm_as_security_t*, dl_info_transfer_req_t*); +static int _emm_as_security_rej(const emm_as_security_t*, dl_info_transfer_req_t*); +static int _emm_as_establish_cnf(const emm_as_establish_t*, nas_establish_rsp_t*); +static int _emm_as_establish_rej(const emm_as_establish_t*, nas_establish_rsp_t*); +static int _emm_as_page_ind(const emm_as_page_t*, paging_req_t*); +#endif + +static int _emm_as_cell_info_req(const emm_as_cell_info_t*, cell_info_req_t*); + +static int _emm_as_data_req(const emm_as_data_t*, ul_info_transfer_req_t*); +static int _emm_as_status_ind(const emm_as_status_t*, ul_info_transfer_req_t*); +static int _emm_as_release_req(const emm_as_release_t*, nas_release_req_t*); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_as_initialize() ** + ** ** + ** Description: Initializes the EMMAS Service Access Point ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: NONE ** + ** ** + ***************************************************************************/ +void emm_as_initialize(void) +{ + LOG_FUNC_IN; + + /* TODO: Initialize the EMMAS-SAP */ + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: emm_as_send() ** + ** ** + ** Description: Processes the EMMAS Service Access Point primitive. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_as_send(const emm_as_t* msg) +{ + LOG_FUNC_IN; + + int rc; + int emm_cause = EMM_CAUSE_SUCCESS; + emm_as_primitive_t primitive = msg->primitive; + + UInt32_t ueid = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Received primitive %s (%d)", + _emm_as_primitive_str[primitive - _EMMAS_START - 1], primitive); + + switch (primitive) + { + case _EMMAS_DATA_IND: + rc = _emm_as_data_ind(&msg->u.data, &emm_cause); + ueid = msg->u.data.ueid; + break; + +#ifdef NAS_UE + case _EMMAS_ESTABLISH_CNF: + rc = _emm_as_establish_cnf(&msg->u.establish, &emm_cause); + break; + + case _EMMAS_ESTABLISH_REJ: + rc = _emm_as_establish_rej(); + break; + + case _EMMAS_RELEASE_IND: + rc = _emm_as_release_ind(&msg->u.release); + break; + + case _EMMAS_PAGE_IND: + rc = _emm_as_page_ind(&msg->u.page); + break; +#endif +#ifdef NAS_MME + case _EMMAS_ESTABLISH_REQ: + rc = _emm_as_establish_req(&msg->u.establish, &emm_cause); + ueid = msg->u.establish.ueid; + break; +#endif + case _EMMAS_CELL_INFO_RES: + rc = _emm_as_cell_info_res(&msg->u.cell_info); + break; + + case _EMMAS_CELL_INFO_IND: + rc = _emm_as_cell_info_ind(&msg->u.cell_info); + break; + + default: + /* Other primitives are forwarded to the Access Stratum */ + rc = _emm_as_send(msg); + if (rc != RETURNok) { + LOG_TRACE(ERROR, "EMMAS-SAP - " + "Failed to process primitive %s (%d)", + _emm_as_primitive_str[primitive - _EMMAS_START - 1], + primitive); + LOG_FUNC_RETURN (RETURNerror); + } + break; + } + + /* Handle decoding errors */ + if (emm_cause != EMM_CAUSE_SUCCESS) { + /* Ignore received message that is too short to contain a complete + * message type information element */ + if (rc == TLV_DECODE_BUFFER_TOO_SHORT) { + LOG_FUNC_RETURN (RETURNok); + } + /* Ignore received message that contains not supported protocol + * discriminator */ + else if (rc == TLV_DECODE_PROTOCOL_NOT_SUPPORTED) { + LOG_FUNC_RETURN (RETURNok); + } + else if (rc == TLV_DECODE_WRONG_MESSAGE_TYPE) { + emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED; + } + /* EMM message processing failed */ + LOG_TRACE(WARNING, "EMMAS-SAP - Received EMM message is not valid " + "(cause=%d)", emm_cause); + /* Return an EMM status message */ + rc = emm_proc_status(ueid, emm_cause); + } + + if (rc != RETURNok) { + LOG_TRACE(ERROR, "EMMAS-SAP - Failed to process primitive %s (%d)", + _emm_as_primitive_str[primitive - _EMMAS_START - 1], + primitive); + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed to process EMM procedures upon receiving data from the + * network + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_as_recv() ** + ** ** + ** Description: Decodes and processes the EPS Mobility Management message ** + ** received from the Access Stratum ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The EMM message to process ** + ** len: The length of the EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_recv(unsigned int ueid, const char* msg, int len, + int *emm_cause) +{ + LOG_FUNC_IN; + + int decoder_rc; + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMMAS-SAP - Received EMM message (length=%d)", len); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Decode the received message */ + decoder_rc = nas_message_decode(msg, &nas_msg, len); + + if (decoder_rc < 0) { + LOG_TRACE(WARNING, "EMMAS-SAP - Failed to decode NAS message " + "(err=%d)", decoder_rc); + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (decoder_rc); + } + + /* Process NAS message */ + EMM_msg* emm_msg = &nas_msg.plain.emm; + switch (emm_msg->header.message_type) + { + case EMM_STATUS: + rc = emm_recv_status(ueid, &emm_msg->emm_status, emm_cause); + break; + +#ifdef NAS_UE + case IDENTITY_REQUEST: + rc = emm_recv_identity_request(&emm_msg->identity_request, + emm_cause); + break; + + case AUTHENTICATION_REQUEST: + rc = emm_recv_authentication_request( + &emm_msg->authentication_request, + emm_cause); + break; + + case AUTHENTICATION_REJECT: + rc = emm_recv_authentication_reject( + &emm_msg->authentication_reject, + emm_cause); + break; + + case SECURITY_MODE_COMMAND: + rc = emm_recv_security_mode_command( + &emm_msg->security_mode_command, + emm_cause); + break; + + case DETACH_ACCEPT: + rc = emm_recv_detach_accept(&emm_msg->detach_accept, emm_cause); + break; +#endif + +#ifdef NAS_UE + case TRACKING_AREA_UPDATE_ACCEPT: + case TRACKING_AREA_UPDATE_REJECT: + case SERVICE_REJECT: + case GUTI_REALLOCATION_COMMAND: + case EMM_INFORMATION: + case DOWNLINK_NAS_TRANSPORT: + case CS_SERVICE_NOTIFICATION: + /* TODO */ + break; +#endif +#ifdef NAS_MME + case IDENTITY_RESPONSE: + rc = emm_recv_identity_response(ueid, + &emm_msg->identity_response, + emm_cause); + break; + + case AUTHENTICATION_RESPONSE: + rc = emm_recv_authentication_response(ueid, + &emm_msg->authentication_response, + emm_cause); + break; + + case AUTHENTICATION_FAILURE: + rc = emm_recv_authentication_failure(ueid, + &emm_msg->authentication_failure, + emm_cause); + break; + + case SECURITY_MODE_COMPLETE: + rc = emm_recv_security_mode_complete(ueid, + &emm_msg->security_mode_complete, + emm_cause); + break; + + case SECURITY_MODE_REJECT: + rc = emm_recv_security_mode_reject(ueid, + &emm_msg->security_mode_reject, + emm_cause); + break; + + case ATTACH_COMPLETE: + rc = emm_recv_attach_complete(ueid, &emm_msg->attach_complete, + emm_cause); + break; + + case TRACKING_AREA_UPDATE_COMPLETE: + case GUTI_REALLOCATION_COMPLETE: + case UPLINK_NAS_TRANSPORT: + /* TODO */ + break; + + case DETACH_REQUEST: + rc = emm_recv_detach_request(ueid, &emm_msg->detach_request, + emm_cause); + break; +#endif + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - EMM message 0x%x is not valid", + emm_msg->header.message_type); + *emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + break; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_data_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP data transfer indication ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: DATA_IND - Data transfer procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_data_ind(const emm_as_data_t* msg, int *emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS data transfer indication " + "(ueid=%d, delivered=%s, length=%d)", msg->ueid, + (msg->delivered)? "TRUE" : "FALSE", msg->NASmsg.length); + + if (msg->delivered) { + if (msg->NASmsg.length > 0) + { + /* Process the received NAS message */ + char* plain_msg = (char*)malloc(msg->NASmsg.length); + if (plain_msg) + { + nas_message_security_header_t header; + /* Decrypt the received security protected message */ + int bytes = nas_message_decrypt((char*)(msg->NASmsg.value), + plain_msg, &header, + msg->NASmsg.length); + if (bytes < 0) { + /* Failed to decrypt the message */ + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (bytes); + } + else if (header.protocol_discriminator == + EPS_MOBILITY_MANAGEMENT_MESSAGE) { + /* Process EMM data */ + rc = _emm_as_recv(msg->ueid, plain_msg, bytes, emm_cause); + } + else if (header.protocol_discriminator == + EPS_SESSION_MANAGEMENT_MESSAGE) { + const OctetString data = {bytes, (uint8_t*)plain_msg}; + /* Foward ESM data to EPS session management */ + rc = lowerlayer_data_ind(msg->ueid, &data); + } + free(plain_msg); + } + } + else { + /* Process successfull lower layer transfer indication */ + rc = lowerlayer_success(msg->ueid); + } + } + else { + /* Process lower layer transmission failure of NAS message */ + rc = lowerlayer_failure(msg->ueid); + } + + LOG_FUNC_RETURN (rc); +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_cnf() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish confirmation ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: ESTABLISH_CNF - NAS signalling connection ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_cnf(const emm_as_establish_t* msg, + int *emm_cause) +{ + LOG_FUNC_IN; + + int decoder_rc; + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS connection establish confirm"); + + if (msg->NASmsg.length > 0) { + /* The NAS signalling connection is established */ + (void) lowerlayer_establish(); + } else { + /* The initial NAS message has been successfully delivered to + * lower layers */ + rc = lowerlayer_success(0); + LOG_FUNC_RETURN (rc); + } + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Decode initial NAS message */ + decoder_rc = nas_message_decode((char*)(msg->NASmsg.value), &nas_msg, + msg->NASmsg.length); + if (decoder_rc < 0) { + LOG_TRACE(WARNING, "EMMAS-SAP - Failed to decode initial NAS message" + "(err=%d)", decoder_rc); + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (decoder_rc); + } + + /* Process initial NAS message */ + EMM_msg* emm_msg = &nas_msg.plain.emm; + switch (emm_msg->header.message_type) + { + case ATTACH_ACCEPT: + rc = emm_recv_attach_accept(&emm_msg->attach_accept, emm_cause); + break; + + case ATTACH_REJECT: + rc = emm_recv_attach_reject(&emm_msg->attach_reject, emm_cause); + break; + + case DETACH_ACCEPT: + break; + + case TRACKING_AREA_UPDATE_ACCEPT: + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Initial NAS message 0x%x is " + "not valid", emm_msg->header.message_type); + *emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + break; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_rej() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish reject ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: ESTABLISH_REJ - NAS signalling connection ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_rej(void) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS initial NAS message transmission " + "failure"); + + /* Process lower layer transmission failure of initial NAS message */ + rc = lowerlayer_failure(0); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_release_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP connection release indication ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: RELEASE_IND - NAS signalling release procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_release_ind(const emm_as_release_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS connection release indication " + "(cause=%d)", msg->cause); + + /* Process NAS signalling connection release indication */ + rc = lowerlayer_release(msg->cause); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_page_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP paging data indication primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: PAGE_IND - Paging data procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_page_ind(const emm_as_page_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS paging data indication"); + + /* TODO */ + + LOG_FUNC_RETURN (rc); +} + +#endif + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_req() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish request ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: ESTABLISH_REQ - NAS signalling connection ** + ** The AS notifies the NAS that establishment of the signal- ** + ** ling connection has been requested to tranfer initial NAS ** + ** message from the UE. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_req(const emm_as_establish_t* msg, int *emm_cause) +{ + LOG_FUNC_IN; + + int decoder_rc; + int rc = RETURNerror; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS connection establish request"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Decode initial NAS message */ + decoder_rc = nas_message_decode((char*)(msg->NASmsg.value), &nas_msg, + msg->NASmsg.length); + + if (decoder_rc < TLV_DECODE_FATAL_ERROR) { + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (decoder_rc); + } else if (decoder_rc == TLV_DECODE_UNEXPECTED_IEI) { + *emm_cause = EMM_CAUSE_IE_NOT_IMPLEMENTED; + } else if (decoder_rc < 0) { + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + } + + /* Process initial NAS message */ + EMM_msg* emm_msg = &nas_msg.plain.emm; + switch (emm_msg->header.message_type) + { + case ATTACH_REQUEST: + rc = emm_recv_attach_request(msg->ueid, &emm_msg->attach_request, + emm_cause); + break; + + case DETACH_REQUEST: + rc = RETURNok; /* TODO */ + break; + + case TRACKING_AREA_UPDATE_REQUEST: + rc = RETURNok; /* TODO */ + break; + + case SERVICE_REQUEST: + rc = RETURNok; /* TODO */ + break; + + case EXTENDED_SERVICE_REQUEST: + rc = RETURNok; /* TODO */ + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Initial NAS message 0x%x is " + "not valid", emm_msg->header.message_type); + *emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + break; + } + + LOG_FUNC_RETURN (rc); +} +#endif + +/**************************************************************************** + ** ** + ** Name: _emm_as_cell_info_res() ** + ** ** + ** Description: Processes the EMMAS-SAP cell information response ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: CELL_INFO_RES - PLMN and cell selection procedure ** + ** The NAS received a response to cell selection request pre- ** + ** viously sent to the Access-Startum. If a suitable cell is ** + ** found to serve the selected PLMN with associated Radio Ac- ** + ** cess Technologies, this cell is selected to camp on. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_cell_info_res(const emm_as_cell_info_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS cell information response"); + +#ifdef NAS_UE + int AcT = NET_ACCESS_EUTRAN; + if (msg->found == TRUE) { + /* Get the first supported access technology */ + while (AcT != NET_ACCESS_UNAVAILABLE) { + if (msg->rat & (1 << AcT)) { + break; + } + AcT -= 1; + } + } + /* Notify EMM that a cell has been found */ + rc = emm_proc_plmn_selection_end(msg->found, msg->tac, msg->cellID, AcT); +#endif + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_cell_info_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP cell information indication ** + ** primitive ** + ** ** + ** EMMAS-SAP - AS->EMM: CELL_INFO_IND - PLMN and cell selection procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_cell_info_ind(const emm_as_cell_info_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received AS cell information indication"); + + /* TODO */ + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * Functions executed to send data to the network when requested within EMM + * procedure processing + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _emm_as_set_header() ** + ** ** + ** Description: Setup the security header of the given NAS message ** + ** ** + ** Inputs: security: The NAS security data to use ** + ** Others: None ** + ** ** + ** Outputs: msg: The NAS message ** + ** Return: Pointer to the plain NAS message to be se- ** + ** curity protected if setting of the securi- ** + ** ty header succeed; ** + ** NULL pointer otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static EMM_msg* _emm_as_set_header(nas_message_t* msg, + const emm_as_security_data_t* security) +{ + LOG_FUNC_IN; + + msg->header.protocol_discriminator = EPS_MOBILITY_MANAGEMENT_MESSAGE; + + if ( security && (security->ksi != EMM_AS_NO_KEY_AVAILABLE) ) { + /* A valid EPS security context exists */ + if (security->is_new) { + /* New EPS security context is taken into use */ + if (security->k_int) { + if (security->k_enc) { + /* NAS integrity and cyphering keys are available */ + msg->header.security_header_type = + SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED_NEW; + } else { + /* NAS integrity key only is available */ + msg->header.security_header_type = + SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_NEW; + } + LOG_FUNC_RETURN (&msg->protected.plain.emm); + } + } + else if (security->k_int) { + if (security->k_enc) { + /* NAS integrity and cyphering keys are available */ + msg->header.security_header_type = + SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED; + } else { + /* NAS integrity key only is available */ + msg->header.security_header_type = + SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED; + } + LOG_FUNC_RETURN (&msg->protected.plain.emm); + } + } + else { + /* No valid EPS security context exists */ + msg->header.security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED; + LOG_FUNC_RETURN (&msg->plain.emm); + } + + /* A valid EPS security context exists but NAS integrity key + * is not available */ + LOG_FUNC_RETURN (NULL); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_encode() ** + ** ** + ** Description: Encodes NAS message into NAS information container ** + ** ** + ** Inputs: msg: The NAS message to encode ** + ** length: The maximum length of the NAS message ** + ** Others: None ** + ** ** + ** Outputs: info: The NAS information container ** + ** msg: The NAS message to encode ** + ** Return: The number of bytes successfully encoded ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_encode(as_nas_info_t* info, nas_message_t* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = 0; + + if (msg->header.security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) + { + emm_msg_header_t* header = &msg->protected.plain.emm.header; + /* Expand size of protected NAS message */ + length += NAS_MESSAGE_SECURITY_HEADER_SIZE; + /* Set header of plain NAS message */ + header->protocol_discriminator = EPS_MOBILITY_MANAGEMENT_MESSAGE; + header->security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED; + } + /* Allocate memory to the NAS information container */ + info->data = (Byte_t*)malloc(length * sizeof(Byte_t)); + if (info->data != NULL) { + /* Encode the NAS message */ + bytes = nas_message_encode((char*)(info->data), msg, length); + if (bytes > 0) { + info->length = bytes; + } else { + free(info->data); + info->length = 0; + info->data = NULL; + } + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_encrypt() ** + ** ** + ** Description: Encryts NAS message into NAS information container ** + ** ** + ** Inputs: header: The Security header in used ** + ** msg: The NAS message to encrypt ** + ** length: The maximum length of the NAS message ** + ** Others: None ** + ** ** + ** Outputs: info: The NAS information container ** + ** Return: The number of bytes successfully encrypted ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_encrypt(as_nas_info_t* info, + const nas_message_security_header_t* header, + const char* msg, int length) +{ + LOG_FUNC_IN; + + int bytes = 0; + + if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) { + /* Expand size of protected NAS message */ + length += NAS_MESSAGE_SECURITY_HEADER_SIZE; + } + /* Allocate memory to the NAS information container */ + info->data = (Byte_t*)malloc(length * sizeof(Byte_t)); + if (info->data != NULL) { + /* Encrypt the NAS information message */ + bytes = nas_message_encrypt(msg, (char*)(info->data), header, length); + if (bytes > 0) { + info->length = bytes; + } else { + free(info->data); + info->length = 0; + info->data = NULL; + } + } + + LOG_FUNC_RETURN (bytes); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_send() ** + ** ** + ** Description: Builds NAS message according to the given EMMAS Service ** + ** Access Point primitive and sends it to the Access Stratum ** + ** sublayer ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to be sent ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_send(const emm_as_t* msg) +{ + LOG_FUNC_IN; + + as_message_t as_msg; + memset(&as_msg, 0 , sizeof(as_message_t)); + + switch (msg->primitive) + { + case _EMMAS_DATA_REQ: + as_msg.msgID = _emm_as_data_req(&msg->u.data, + &as_msg.msg.ul_info_transfer_req); + break; + + case _EMMAS_STATUS_IND: + as_msg.msgID = _emm_as_status_ind(&msg->u.status, + &as_msg.msg.ul_info_transfer_req); + break; + + case _EMMAS_RELEASE_REQ: + as_msg.msgID = _emm_as_release_req(&msg->u.release, + &as_msg.msg.nas_release_req); + break; + +#ifdef NAS_UE + case _EMMAS_SECURITY_RES: + as_msg.msgID = _emm_as_security_res(&msg->u.security, + &as_msg.msg.ul_info_transfer_req); + break; + + case _EMMAS_ESTABLISH_REQ: + as_msg.msgID = _emm_as_establish_req(&msg->u.establish, + &as_msg.msg.nas_establish_req); + break; + +#endif +#ifdef NAS_MME + case _EMMAS_SECURITY_REQ: + as_msg.msgID = _emm_as_security_req(&msg->u.security, + &as_msg.msg.dl_info_transfer_req); + break; + + case _EMMAS_SECURITY_REJ: + as_msg.msgID = _emm_as_security_rej(&msg->u.security, + &as_msg.msg.dl_info_transfer_req); + break; + + case _EMMAS_ESTABLISH_CNF: + as_msg.msgID = _emm_as_establish_cnf(&msg->u.establish, + &as_msg.msg.nas_establish_rsp); + break; + + case _EMMAS_ESTABLISH_REJ: + as_msg.msgID = _emm_as_establish_rej(&msg->u.establish, + &as_msg.msg.nas_establish_rsp); + break; + + case _EMMAS_PAGE_IND: + as_msg.msgID = _emm_as_page_ind(&msg->u.page, + &as_msg.msg.paging_req); + break; + +#endif + case _EMMAS_CELL_INFO_REQ: + as_msg.msgID = _emm_as_cell_info_req(&msg->u.cell_info, + &as_msg.msg.cell_info_req); + /* + * TODO: NAS may provide a list of equivalent PLMNs, if available, + * that AS shall use for cell selection and cell reselection. + */ + break; + + default: + as_msg.msgID = 0; + break; + } + + /* Send the message to the Access Stratum or S1AP in case of MME */ + if (as_msg.msgID > 0) { +#if defined(EPC_BUILD) && defined(NAS_MME) + MessageDef *message_p = NULL; + + switch (as_msg.msgID) { + case AS_DL_INFO_TRANSFER_REQ: { + int ret; + + message_p = alloc_new_message(TASK_NAS, NAS_DOWNLINK_DATA_IND); + + memcpy(&message_p->msg.nas_dl_data_ind, + &as_msg.msg.dl_info_transfer_req, + sizeof(nas_dl_data_ind_t)); + + ret = send_msg_to_task(TASK_S1AP, 0, message_p); + + if (ret != -1) { + LOG_FUNC_RETURN (RETURNok); + } + } break; + default: + break; + } +#else + int bytes = as_message_send(&as_msg); + if (bytes > 0) { + LOG_FUNC_RETURN (RETURNok); + } +#endif + } + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_data_req() ** + ** ** + ** Description: Processes the EMMAS-SAP data transfer request ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: DATA_REQ - Data transfer procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_data_req(const emm_as_data_t* msg, + ul_info_transfer_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + int is_encoded = FALSE; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS data transfer request"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS information message */ + if (emm_msg != NULL) switch (msg->NASinfo) + { +#ifdef NAS_UE + case EMM_AS_NAS_DATA_ATTACH: + size = emm_send_attach_complete(msg, &emm_msg->attach_complete); + break; + + case EMM_AS_NAS_DATA_DETACH: + size = emm_send_detach_request(msg, &emm_msg->detach_request); + break; +#endif + +#ifdef NAS_MME + case EMM_AS_NAS_DATA_DETACH: + size = emm_send_detach_accept(msg, &emm_msg->detach_accept); + break; +#endif + + default: + /* Send other NAS messages as already encoded ESM messages */ + size = msg->NASmsg.length; + is_encoded = TRUE; + break; + } + + if (size > 0) { + int bytes; + if (!is_encoded) { + /* Encode the NAS information message */ + bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + } else { + /* Encrypt the NAS information message */ + bytes = _emm_as_encrypt(&as_msg->nasMsg, &nas_msg.header, + (char*)(msg->NASmsg.value), size); + } + if (bytes > 0) { +#ifdef NAS_UE + LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ); +#endif +#ifdef NAS_MME + LOG_FUNC_RETURN (AS_DL_INFO_TRANSFER_REQ); +#endif + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_status_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP status indication primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: STATUS_IND - EMM status report procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_status_ind(const emm_as_status_t* msg, + ul_info_transfer_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS status indication (cause=%d)", + msg->emm_cause); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS information message */ + if (emm_msg != NULL) { + size = emm_send_status(msg, &emm_msg->emm_status); + } + + if (size > 0) { + /* Encode the NAS information message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { +#ifdef NAS_UE + LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ); +#endif +#ifdef NAS_MME + LOG_FUNC_RETURN (AS_DL_INFO_TRANSFER_REQ); +#endif + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_release_req() ** + ** ** + ** Description: Processes the EMMAS-SAP connection release request ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: RELEASE_REQ - NAS signalling release procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_release_req(const emm_as_release_t* msg, + nas_release_req_t* as_msg) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS release request"); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + if (msg->cause == EMM_AS_CAUSE_AUTHENTICATION) { + as_msg->cause = AS_AUTHENTICATION_FAILURE; + } else if (msg->cause == EMM_AS_CAUSE_DETACH) { + as_msg->cause = AS_DETACH; + } + + LOG_FUNC_RETURN (AS_NAS_RELEASE_REQ); +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _emm_as_security_res() ** + ** ** + ** Description: Processes the EMMAS-SAP security response primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: SECURITY_RES - Security mode control procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_security_res(const emm_as_security_t* msg, + ul_info_transfer_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS security response"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS security message */ + if (emm_msg != NULL) switch (msg->msgType) + { + case EMM_AS_MSG_TYPE_IDENT: + size = emm_send_identity_response(msg, &emm_msg->identity_response); + break; + + case EMM_AS_MSG_TYPE_AUTH: + if (msg->emm_cause != EMM_CAUSE_SUCCESS) { + size = emm_send_authentication_failure(msg, + &emm_msg->authentication_failure); + } else { + size = emm_send_authentication_response(msg, + &emm_msg->authentication_response); + } + break; + + case EMM_AS_MSG_TYPE_SMC: + if (msg->emm_cause != EMM_CAUSE_SUCCESS) { + size = emm_send_security_mode_reject(msg, + &emm_msg->security_mode_reject); + } else { + size = emm_send_security_mode_complete(msg, + &emm_msg->security_mode_complete); + } + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of NAS security " + "message 0x%.2x is not valid", msg->msgType); + } + + if (size > 0) { + /* Encode the NAS security message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { + LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ); + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_req() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish request ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: ESTABLISH_REQ - NAS signalling connection ** + ** The NAS requests the AS to establish signalling connection ** + ** to tranfer initial NAS message to the network. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_req(const emm_as_establish_t* msg, + nas_establish_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS connection establish request"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + as_msg->cause = msg->RRCcause; + as_msg->type = msg->RRCtype; + as_msg->plmnID = *msg->plmnID; + /* Derive the S-TMSI from the GUTI, if valid */ + if (msg->UEid.guti) { + as_msg->s_tmsi.MMEcode = msg->UEid.guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->UEid.guti->m_tmsi; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the initial NAS information message */ + if (emm_msg != NULL) switch (msg->NASinfo) + { + case EMM_AS_NAS_INFO_ATTACH: + size = emm_send_attach_request(msg, &emm_msg->attach_request); + break; + + case EMM_AS_NAS_INFO_DETACH: + size = emm_send_initial_detach_request(msg, + &emm_msg->detach_request); + break; + + case EMM_AS_NAS_INFO_TAU: + size = emm_send_initial_tau_request(msg, + &emm_msg->tracking_area_update_request); + break; + + case EMM_AS_NAS_INFO_SR: + size = emm_send_initial_sr_request(msg, &emm_msg->service_request); + break; + + case EMM_AS_NAS_INFO_EXTSR: + size = emm_send_initial_extsr_request(msg, + &emm_msg->extended_service_request); + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of initial NAS " + "message 0x%.2x is not valid", msg->NASinfo); + break; + } + + if (size > 0) { + /* Encode the initial NAS information message */ + int bytes = _emm_as_encode(&as_msg->initialNasMsg, &nas_msg, size); + if (bytes > 0) { + LOG_FUNC_RETURN (AS_NAS_ESTABLISH_REQ); + } + } + LOG_FUNC_RETURN (0); +} +#endif // NAS_UE + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _emm_as_security_req() ** + ** ** + ** Description: Processes the EMMAS-SAP security request primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: SECURITY_REQ - Security mode control procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_security_req(const emm_as_security_t* msg, + dl_info_transfer_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS security request"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS security message */ + if (emm_msg != NULL) switch (msg->msgType) + { + case EMM_AS_MSG_TYPE_IDENT: + size = emm_send_identity_request(msg, &emm_msg->identity_request); + break; + + case EMM_AS_MSG_TYPE_AUTH: + size = emm_send_authentication_request(msg, + &emm_msg->authentication_request); + break; + + case EMM_AS_MSG_TYPE_SMC: + size = emm_send_security_mode_command(msg, + &emm_msg->security_mode_command); + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of NAS security " + "message 0x%.2x is not valid", msg->msgType); + } + + if (size > 0) { + /* Encode the NAS security message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { + LOG_FUNC_RETURN (AS_DL_INFO_TRANSFER_REQ); + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_security_rej() ** + ** ** + ** Description: Processes the EMMAS-SAP security reject primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: SECURITY_REJ - Security mode control procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_security_rej(const emm_as_security_t* msg, + dl_info_transfer_req_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS security reject"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->guti) { + as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS security message */ + if (emm_msg != NULL) switch (msg->msgType) + { + case EMM_AS_MSG_TYPE_AUTH: + size = emm_send_authentication_reject( + &emm_msg->authentication_reject); + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of NAS security " + "message 0x%.2x is not valid", msg->msgType); + } + + if (size > 0) { + /* Encode the NAS security message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { + LOG_FUNC_RETURN (AS_DL_INFO_TRANSFER_REQ); + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_cnf() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish confirm ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: ESTABLISH_CNF - NAS signalling connection ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_cnf(const emm_as_establish_t* msg, + nas_establish_rsp_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS connection establish response"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + as_msg->UEid = msg->ueid; + if (msg->UEid.guti == NULL) { + LOG_FUNC_RETURN (0); + } + as_msg->s_tmsi.MMEcode = msg->UEid.guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->UEid.guti->m_tmsi; + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the initial NAS information message */ + if (emm_msg != NULL) switch (msg->NASinfo) + { + case EMM_AS_NAS_INFO_ATTACH: + size = emm_send_attach_accept(msg, &emm_msg->attach_accept); + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of initial NAS " + "message 0x%.2x is not valid", msg->NASinfo); + break; + } + + if (size > 0) { + /* Encode the initial NAS information message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { + as_msg->errCode = AS_SUCCESS; + LOG_FUNC_RETURN (AS_NAS_ESTABLISH_RSP); + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_establish_rej() ** + ** ** + ** Description: Processes the EMMAS-SAP connection establish reject ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: ESTABLISH_REJ - NAS signalling connection ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_establish_rej(const emm_as_establish_t* msg, + nas_establish_rsp_t* as_msg) +{ + LOG_FUNC_IN; + + int size = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS connection establish reject"); + + nas_message_t nas_msg; + memset(&nas_msg, 0 , sizeof(nas_message_t)); + + /* Setup the AS message */ + if (msg->UEid.guti) { + as_msg->s_tmsi.MMEcode = msg->UEid.guti->gummei.MMEcode; + as_msg->s_tmsi.m_tmsi = msg->UEid.guti->m_tmsi; + } + else { + as_msg->UEid = msg->ueid; + } + + /* Setup the NAS security header */ + EMM_msg* emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx); + + /* Setup the NAS information message */ + if (emm_msg != NULL) switch (msg->NASinfo) + { + case EMM_AS_NAS_INFO_ATTACH: + size = emm_send_attach_reject(msg, &emm_msg->attach_reject); + break; + + default: + LOG_TRACE(WARNING, "EMMAS-SAP - Type of initial NAS " + "message 0x%.2x is not valid", msg->NASinfo); + break; + } + + if (size > 0) { + /* Encode the initial NAS information message */ + int bytes = _emm_as_encode(&as_msg->nasMsg, &nas_msg, size); + if (bytes > 0) { + as_msg->errCode = AS_TERMINATED_NAS; + LOG_FUNC_RETURN (AS_NAS_ESTABLISH_RSP); + } + } + LOG_FUNC_RETURN (0); +} + +/**************************************************************************** + ** ** + ** Name: _emm_as_page_ind() ** + ** ** + ** Description: Processes the EMMAS-SAP paging data indication primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: PAGE_IND - Paging data procedure ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_page_ind(const emm_as_page_t* msg, paging_req_t* as_msg) +{ + LOG_FUNC_IN; + + int bytes = 0; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS data paging indication"); + + /* TODO */ + + if (bytes > 0) { + LOG_FUNC_RETURN (AS_PAGING_IND); + } + LOG_FUNC_RETURN (0); +} + +#endif // NAS_MME + +/**************************************************************************** + ** ** + ** Name: _emm_as_cell_info_req() ** + ** ** + ** Description: Processes the EMMAS-SAP cell information request ** + ** primitive ** + ** ** + ** EMMAS-SAP - EMM->AS: CELL_INFO_REQ - PLMN and cell selection procedure ** + ** The NAS requests the AS to select a cell belonging to the ** + ** selected PLMN with associated Radio Access Technologies. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: as_msg: The message to send to the AS ** + ** Return: The identifier of the AS message ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _emm_as_cell_info_req(const emm_as_cell_info_t* msg, + cell_info_req_t* as_msg) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMMAS-SAP - Send AS cell information request"); + + as_msg->plmnID = msg->plmnIDs.plmn[0]; + as_msg->rat = msg->rat; + + LOG_FUNC_RETURN (AS_CELL_INFO_REQ); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.h new file mode 100644 index 0000000000..69985720ce --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_as.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_as.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMAS Service Access Point that provides + services to the EPS Mobility Management for NAS message + transfer to/from the Access Stratum sublayer. + +*****************************************************************************/ +#ifndef __EMM_AS_H__ +#define __EMM_AS_H__ + +#include "emm_asDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void emm_as_initialize(void); + +int emm_as_send(const emm_as_t* msg); + +#endif /* __EMM_AS_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h new file mode 100644 index 0000000000..064d67bf77 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h @@ -0,0 +1,240 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_asDef.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMM primitives available at the EMMAS Service + Access Point to transfer NAS messages to/from the Access + Stratum sublayer. + +*****************************************************************************/ +#ifndef __EMM_ASDEF_H__ +#define __EMM_ASDEF_H__ + +#include "commonDef.h" +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * EMMAS-SAP primitives + */ +typedef enum { + _EMMAS_START = 200, + _EMMAS_SECURITY_REQ, /* EMM->AS: Security request */ + _EMMAS_SECURITY_IND, /* AS->EMM: Security indication */ + _EMMAS_SECURITY_RES, /* EMM->AS: Security response */ + _EMMAS_SECURITY_REJ, /* EMM->AS: Security reject */ + _EMMAS_ESTABLISH_REQ, /* EMM->AS: Connection establish request */ + _EMMAS_ESTABLISH_CNF, /* AS->EMM: Connection establish confirm */ + _EMMAS_ESTABLISH_REJ, /* AS->EMM: Connection establish reject */ + _EMMAS_RELEASE_REQ, /* EMM->AS: Connection release request */ + _EMMAS_RELEASE_IND, /* AS->EMM: Connection release indication */ + _EMMAS_DATA_REQ, /* EMM->AS: Data transfer request */ + _EMMAS_DATA_IND, /* AS->EMM: Data transfer indication */ + _EMMAS_PAGE_IND, /* AS->EMM: Paging data indication */ + _EMMAS_STATUS_IND, /* AS->EMM: Status indication */ + _EMMAS_CELL_INFO_REQ, /* EMM->AS: Cell information request */ + _EMMAS_CELL_INFO_RES, /* AS->EMM: Cell information response */ + _EMMAS_CELL_INFO_IND, /* AS->EMM: Cell information indication */ + _EMMAS_END +} emm_as_primitive_t; + +/* Data used to setup EPS NAS security */ +typedef struct { + UInt8_t is_new; /* New security data indicator */ +#define EMM_AS_NO_KEY_AVAILABLE 0xff + UInt8_t ksi; /* NAS key set identifier */ + UInt8_t sqn; /* Sequence number */ + UInt32_t count; /* NAS counter */ + const OctetString* k_enc; /* NAS cyphering key */ + const OctetString* k_int; /* NAS integrity key */ +} emm_as_security_data_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * EMMAS primitive for security + * ---------------------------- + */ +typedef struct { + UInt32_t ueid; /* UE lower layer identifier */ + const GUTI_t *guti; /* GUTI temporary mobile identity */ + emm_as_security_data_t sctx;/* EPS NAS security context */ + int emm_cause; /* EMM failure cause code */ + /* + * Identity request/response + */ + UInt8_t identType; /* Type of requested UE's identity */ + const imsi_t *imsi; /* The requested IMSI of the UE */ + const imei_t *imei; /* The requested IMEI of the UE */ + UInt32_t tmsi; /* The requested TMSI of the UE */ + /* + * Authentication request/response + */ + UInt8_t ksi; /* NAS key set identifier */ + const OctetString* rand; /* Random challenge number */ + const OctetString* autn; /* Authentication token */ + const OctetString* res; /* Authentication response */ + const OctetString* auts; /* Synchronisation failure */ + /* + * Security Mode Command + */ + UInt8_t eea; /* Replayed EPS encryption algorithms */ + UInt8_t eia; /* Replayed EPS integrity algorithms */ + +#define EMM_AS_MSG_TYPE_IDENT 0x01 /* Identification message */ +#define EMM_AS_MSG_TYPE_AUTH 0x02 /* Authentication message */ +#define EMM_AS_MSG_TYPE_SMC 0x03 /* Security Mode Command */ + UInt8_t msgType; /* Type of NAS security message to transfer */ +} emm_as_security_t; + +/* + * EMMAS primitive for connection establishment + * -------------------------------------------- + */ +typedef struct { + const GUTI_t *guti; /* The GUTI, if valid */ + const tai_t *tai; /* The last visited registered Tracking + * Area Identity, if available */ + const imsi_t *imsi; /* IMSI in case of "AttachWithImsi" */ + const imei_t *imei; /* UE's IMEI for emergency bearer services */ +} emm_as_EPS_identity_t; + +typedef struct { + UInt32_t ueid; /* UE lower layer identifier */ + emm_as_EPS_identity_t UEid; /* UE's EPS mobile identity */ + emm_as_security_data_t sctx;/* EPS NAS security context */ + int switch_off; /* TRUE if the UE is switched off */ + UInt8_t type; /* Network attach/detach type */ + UInt8_t RRCcause; /* Connection establishment cause */ + UInt8_t RRCtype; /* Associated call type */ + const plmn_t* plmnID; /* Identifier of the selected PLMN */ + UInt8_t ksi; /* NAS key set identifier */ + UInt8_t encryption:4; /* Ciphering algorithm */ + UInt8_t integrity:4; /* Integrity protection algorithm */ + int emm_cause; /* EMM failure cause code */ + const GUTI_t *new_guti; /* New GUTI, if re-allocated */ + int n_tacs; /* Number of concecutive tracking areas + * the UE is registered to */ + tac_t tac; /* Code of the first tracking area the UE + * is registered to */ +#define EMM_AS_NAS_INFO_ATTACH 0x01 /* Attach request */ +#define EMM_AS_NAS_INFO_DETACH 0x02 /* Detach request */ +#define EMM_AS_NAS_INFO_TAU 0x03 /* Tracking Area Update request */ +#define EMM_AS_NAS_INFO_SR 0x04 /* Service Request */ +#define EMM_AS_NAS_INFO_EXTSR 0x05 /* Extended Service Request */ + UInt8_t NASinfo; /* Type of initial NAS information to transfer */ + OctetString NASmsg; /* NAS message to be transfered within + * initial NAS information message */ +} emm_as_establish_t; + +/* + * EMMAS primitive for connection release + * -------------------------------------- + */ +typedef struct { + UInt32_t ueid; /* UE lower layer identifier */ + const GUTI_t *guti; /* GUTI temporary mobile identity */ +#define EMM_AS_CAUSE_AUTHENTICATION 0x01 /* Authentication failure */ +#define EMM_AS_CAUSE_DETACH 0x02 /* Detach requested */ + UInt8_t cause; /* Release cause */ +} emm_as_release_t; + +/* + * EMMAS primitive for data transfer + * --------------------------------- + */ +typedef struct { + UInt32_t ueid; /* UE lower layer identifier */ + const GUTI_t *guti; /* GUTI temporary mobile identity */ + emm_as_security_data_t sctx;/* EPS NAS security context */ + int switch_off; /* TRUE if the UE is switched off */ + UInt8_t type; /* Network detach type */ + UInt8_t delivered; /* Data message delivery indicator */ +#define EMM_AS_NAS_DATA_ATTACH 0x01 /* Attach complete */ +#define EMM_AS_NAS_DATA_DETACH 0x02 /* Detach request */ + UInt8_t NASinfo; /* Type of NAS information to transfer */ + OctetString NASmsg; /* NAS message to be transfered */ +} emm_as_data_t; + +/* + * EMMAS primitive for paging + * -------------------------- + */ +typedef struct {} emm_as_page_t; + +/* + * EMMAS primitive for status indication + * ------------------------------------- + */ +typedef struct { + UInt32_t ueid; /* UE lower layer identifier */ + const GUTI_t *guti; /* GUTI temporary mobile identity */ + emm_as_security_data_t sctx;/* EPS NAS security context */ + int emm_cause; /* EMM failure cause code */ +} emm_as_status_t; + +/* + * EMMAS primitive for cell information + * ------------------------------------ + */ +typedef struct { + UInt8_t found; /* Indicates whether a suitable cell is found */ +#define EMM_AS_PLMN_LIST_SIZE 6 + PLMN_LIST_T(EMM_AS_PLMN_LIST_SIZE) plmnIDs; + /* List of identifiers of available PLMNs */ + Byte_t rat; /* Bitmap of Radio Access Technologies */ + tac_t tac; /* Tracking Area Code */ + ci_t cellID; /* cell identity */ +} emm_as_cell_info_t; + +/* + * -------------------------------- + * Structure of EMMAS-SAP primitive + * -------------------------------- + */ +typedef struct { + emm_as_primitive_t primitive; + union { + emm_as_security_t security; + emm_as_establish_t establish; + emm_as_release_t release; + emm_as_data_t data; + emm_as_page_t page; + emm_as_status_t status; + emm_as_cell_info_t cell_info; + } u; +} emm_as_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * Defined in LowerLayer.c + * Setup security data according to the given EPS security context + */ +void emm_as_set_security_data(emm_as_security_data_t* data, const void* context, + int is_new, int is_ciphered); + +#endif /* __EMM_ASDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.c new file mode 100644 index 0000000000..571ac088ed --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.c @@ -0,0 +1,157 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_esm.c + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMESM Service Access Point that provides + interlayer services to the EPS Session Management sublayer + for service registration and activate/deactivate PDN + connections. + +*****************************************************************************/ + +#include "emm_esm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "LowerLayer.h" + +#ifdef NAS_UE +#include "emm_proc.h" +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * String representation of EMMESM-SAP primitives + */ +static const char* _emm_esm_primitive_str[] = { +#ifdef NAS_UE + "EMMESM_ESTABLISH_REQ", + "EMMESM_ESTABLISH_CNF", + "EMMESM_ESTABLISH_REJ", +#endif + "EMMESM_RELEASE_IND", + "EMMESM_UNITDATA_REQ", + "EMMESM_UNITDATA_IND", +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_esm_initialize() ** + ** ** + ** Description: Initializes the EMMESM Service Access Point ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: NONE ** + ** ** + ***************************************************************************/ +void emm_esm_initialize(void) +{ + LOG_FUNC_IN; + + /* TODO: Initialize the EMMESM-SAP */ + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: emm_esm_send() ** + ** ** + ** Description: Processes the EMMESM Service Access Point primitive ** + ** ** + ** Inputs: msg: The EMMESM-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_esm_send(const emm_esm_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + emm_esm_primitive_t primitive = msg->primitive; + + LOG_TRACE(INFO, "EMMESM-SAP - Received primitive %s (%d)", + _emm_esm_primitive_str[primitive - _EMMESM_START - 1], primitive); + + switch (primitive) + { +#ifdef NAS_UE + case _EMMESM_ESTABLISH_REQ: + /* ESM requests EMM to initiate an attach procedure before + * requesting subsequent connectivity to additional PDNs */ + rc = emm_proc_attach_restart(); + break; + + case _EMMESM_ESTABLISH_CNF: + /* ESM notifies EMM that PDN connectivity procedure successfully + * processed */ + if (msg->u.establish.is_attached) { + if (msg->u.establish.is_emergency) { + /* Consider the UE attached for emergency bearer services + * only */ + rc = emm_proc_attach_set_emergency(); + } + } + else { + /* Consider the UE locally detached from the network */ + rc = emm_proc_attach_set_detach(); + } + break; + + case _EMMESM_ESTABLISH_REJ: + /* ESM notifies EMM that PDN connectivity procedure failed */ + break; +#endif + case _EMMESM_UNITDATA_REQ: + /* ESM requests EMM to transfer ESM data unit to lower layer */ + rc = lowerlayer_data_req(msg->ueid, &msg->u.data.msg); + break; + + default: + break; + + } + + if (rc != RETURNok) { + LOG_TRACE(WARNING, "EMMESM-SAP - Failed to process primitive %s (%d)", + _emm_esm_primitive_str[primitive - _EMMESM_START - 1], + primitive); + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.h new file mode 100644 index 0000000000..17b991341e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esm.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_esm.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMESM Service Access Point that provides + interlayer services to the EPS Session Management sublayer + for service registration and activate/deactivate PDP context. + +*****************************************************************************/ +#ifndef __EMM_ESM_H__ +#define __EMM_ESM_H__ + +#include "emm_esmDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void emm_esm_initialize(void); + +int emm_esm_send(const emm_esm_t* msg); + +#endif /* __EMM_ESM_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h new file mode 100644 index 0000000000..3577a0d40e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h @@ -0,0 +1,94 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_esmDef.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMESM Service Access Point that provides + interlayer services to the EPS Session Management sublayer + for service registration and activate/deactivate PDN + connections. + +*****************************************************************************/ +#ifndef __EMM_ESMDEF_H__ +#define __EMM_ESMDEF_H__ + +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * EMMESM-SAP primitives + */ +typedef enum { + _EMMESM_START = 100, +#ifdef NAS_UE + _EMMESM_ESTABLISH_REQ, + _EMMESM_ESTABLISH_CNF, + _EMMESM_ESTABLISH_REJ, +#endif + _EMMESM_RELEASE_IND, + _EMMESM_UNITDATA_REQ, + _EMMESM_UNITDATA_IND, + _EMMESM_END +} emm_esm_primitive_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * EMMESM primitive for connection establishment + * --------------------------------------------- + */ +typedef struct { + int is_emergency; /* Indicates whether the PDN connection is established + * for emergency bearer services only */ + int is_attached; /* Indicates whether the UE remains attached to the + * network */ +} emm_esm_establish_t; + +/* + * EMMESM primitive for data transfer + * ---------------------------------- + */ +typedef struct { + OctetString msg; /* ESM message to be transfered */ +} emm_esm_data_t; + +/* + * --------------------------------- + * Structure of EMMESM-SAP primitive + * --------------------------------- + */ +typedef struct { + emm_esm_primitive_t primitive; + unsigned int ueid; + union { + emm_esm_establish_t establish; + emm_esm_data_t data; + } u; + /* TODO: complete emm_esm_t structure definition */ +} emm_esm_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __EMM_ESMDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.c new file mode 100644 index 0000000000..17bbf0de4d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.c @@ -0,0 +1,397 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_fsm.c + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EPS Mobility Management procedures executed at + the EMMREG Service Access Point. + +*****************************************************************************/ + +#include "emm_fsm.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "mme_api.h" +#include "emmData.h" + +#if defined(EPC_BUILD) +# include "assertions.h" +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#ifdef NAS_UE +#define EMM_FSM_NB_UE_MAX 1 +#endif +#ifdef NAS_MME +#define EMM_FSM_NB_UE_MAX (MME_API_NB_UE_MAX + 1) +#endif + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Data used for trace logging + * ----------------------------------------------------------------------------- + */ + +/* String representation of EMM events */ +static const char* _emm_fsm_event_str[] = { +#ifdef NAS_UE + "S1_ENABLED", + "S1_DISABLED", + "NO_IMSI", + "NO_CELL", + "REGISTER_REQ", + "REGISTER_CNF", + "REGISTER_REJ", + "ATTACH_INIT", + "ATTACH_REQ", + "ATTACH_FAILED", + "ATTACH_EXCEEDED", + "AUTHENTICATION_REJ", +#endif +#ifdef NAS_MME + "COMMON_PROC_REQ", + "COMMON_PROC_CNF", + "COMMON_PROC_REJ", + "PROC_ABORT", +#endif + "ATTACH_CNF", + "ATTACH_REJ", + "DETACH_INIT", + "DETACH_REQ", + "DETACH_FAILED", + "DETACH_CNF", + "TAU_REQ", + "TAU_CNF", + "TAU_REJ", + "SERVICE_REQ", + "SERVICE_CNF", + "SERVICE_REJ", + "LOWERLAYER_SUCCESS", + "LOWERLAYER_FAILURE", + "LOWERLAYER_RELEASE", +}; + +/* String representation of EMM status */ +static const char* _emm_fsm_status_str[EMM_STATE_MAX] = +{ +#ifdef NAS_UE + "NULL", +#endif + "DEREGISTERED", + "REGISTERED", + "DEREGISTERED-INITIATED", +#ifdef NAS_UE + "DEREGISTERED.NORMAL-SERVICE", + "DEREGISTERED.LIMITED-SERVICE", + "DEREGISTERED.ATTEMPTING-TO-ATTACH", + "DEREGISTERED.PLMN-SEARCH", + "DEREGISTERED.NO-IMSI", + "DEREGISTERED.ATTACH-NEEDED", + "DEREGISTERED.NO-CELL-AVAILABLE", + "REGISTERED-INITIATED", + "REGISTERED.NORMAL-SERVICE", + "REGISTERED.ATTEMPTING-TO-PDATE", + "REGISTERED.LIMITED-SERVICE", + "REGISTERED.PLMN-SEARCH", + "REGISTERED.UPDATE-NEEDED", + "REGISTERED.NO-CELL-AVAILABLE", + "REGISTERED.ATTEMPTING-TO-UPDATE-MM", + "REGISTERED.IMSI-DETACH-INITIATED", + "TRACKING-AREA-UPDATING-INITIATED", + "SERVICE-REQUEST-INITIATED", +#endif +#ifdef NAS_MME + "COMMON-PROCEDURE-INITIATED", +#endif +}; + +/* + * ----------------------------------------------------------------------------- + * EPS Mobility Management state machine handlers + * ----------------------------------------------------------------------------- + */ + +/* Type of the EPS Mobility Management state machine handler */ +typedef int(*emm_fsm_handler_t)(const emm_reg_t*); + +#ifdef NAS_UE +int EmmNull(const emm_reg_t*); +#endif +int EmmDeregistered(const emm_reg_t*); +int EmmRegistered(const emm_reg_t*); +int EmmDeregisteredInitiated(const emm_reg_t*); +#ifdef NAS_UE +int EmmDeregisteredNormalService(const emm_reg_t*); +int EmmDeregisteredLimitedService(const emm_reg_t*); +int EmmDeregisteredAttemptingToAttach(const emm_reg_t*); +int EmmDeregisteredPlmnSearch(const emm_reg_t*); +int EmmDeregisteredNoImsi(const emm_reg_t*); +int EmmDeregisteredAttachNeeded(const emm_reg_t*); +int EmmDeregisteredNoCellAvailable(const emm_reg_t*); +int EmmRegisteredInitiated(const emm_reg_t*); +int EmmRegisteredNormalService(const emm_reg_t*); +int EmmRegisteredAttemptingToUpdate(const emm_reg_t*); +int EmmRegisteredLimitedService(const emm_reg_t*); +int EmmRegisteredPlmnSearch(const emm_reg_t*); +int EmmRegisteredUpdateNeeded(const emm_reg_t*); +int EmmRegisteredNoCellAvailable(const emm_reg_t*); +int EmmRegisteredAttemptingToUpdate(const emm_reg_t*); +int EmmRegisteredImsiDetachInitiated(const emm_reg_t*); +int EmmTrackingAreaUpdatingInitiated(const emm_reg_t*); +int EmmServiceRequestInitiated(const emm_reg_t*); +#endif +#ifdef NAS_MME +int EmmCommonProcedureInitiated(const emm_reg_t*); +#endif + +/* EMM state machine handlers */ +static const emm_fsm_handler_t _emm_fsm_handlers[EMM_STATE_MAX] = +{ +#ifdef NAS_UE + EmmNull, +#endif + EmmDeregistered, + EmmRegistered, + EmmDeregisteredInitiated, +#ifdef NAS_UE + EmmDeregisteredNormalService, + EmmDeregisteredLimitedService, + EmmDeregisteredAttemptingToAttach, + EmmDeregisteredPlmnSearch, + EmmDeregisteredNoImsi, + EmmDeregisteredAttachNeeded, + EmmDeregisteredNoCellAvailable, + EmmRegisteredInitiated, + EmmRegisteredNormalService, + EmmRegisteredAttemptingToUpdate, + EmmRegisteredLimitedService, + EmmRegisteredPlmnSearch, + EmmRegisteredUpdateNeeded, + EmmRegisteredNoCellAvailable, + EmmRegisteredAttemptingToUpdate, + EmmRegisteredImsiDetachInitiated, + EmmTrackingAreaUpdatingInitiated, + EmmServiceRequestInitiated, +#endif +#ifdef NAS_MME + EmmCommonProcedureInitiated, +#endif +}; + +/* + * ----------------------------------------------------------------------------- + * Current EPS Mobility Management status + * ----------------------------------------------------------------------------- + */ + +#if !defined(EPC_BUILD) +emm_fsm_state_t _emm_fsm_status[EMM_FSM_NB_UE_MAX]; +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_fsm_initialize() ** + ** ** + ** Description: Initializes the EMM state machine ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _emm_fsm_status ** + ** ** + ***************************************************************************/ +void emm_fsm_initialize(void) +{ + int ueid; + LOG_FUNC_IN; + +#ifdef NAS_UE + _emm_fsm_status[0] = EMM_NULL; +#endif + +#if defined(NAS_MME) && !defined(EPC_BUILD) + for (ueid = 0; ueid < EMM_FSM_NB_UE_MAX; ueid++) { + _emm_fsm_status[ueid] = EMM_DEREGISTERED; + } +#endif + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: emm_fsm_set_status() ** + ** ** + ** Description: Set the EPS Mobility Management status to the given state ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** status: The new EMM status ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _emm_fsm_status ** + ** ** + ***************************************************************************/ +int emm_fsm_set_status( +#ifdef NAS_MME + unsigned int ueid, + void *ctx, +#endif + emm_fsm_state_t status) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + +#if defined(EPC_BUILD) + emm_data_context_t *emm_ctx = (emm_data_context_t*)ctx; + + DevAssert(emm_ctx != NULL); + + if ((status < EMM_STATE_MAX) && (ueid > 0)) { + LOG_TRACE(INFO, "EMM-FSM - Status changed: %s ===> %s", + _emm_fsm_status_str[emm_ctx->_emm_fsm_status], + _emm_fsm_status_str[status]); + if (status != emm_ctx->_emm_fsm_status) { + emm_ctx->_emm_fsm_status = status; + } + LOG_FUNC_RETURN (RETURNok); + } +#else + if ( (status < EMM_STATE_MAX) && (ueid < EMM_FSM_NB_UE_MAX) ) { + LOG_TRACE(INFO, "EMM-FSM - Status changed: %s ===> %s", + _emm_fsm_status_str[_emm_fsm_status[ueid]], + _emm_fsm_status_str[status]); + if (status != _emm_fsm_status[ueid]) { + _emm_fsm_status[ueid] = status; + } + LOG_FUNC_RETURN (RETURNok); + } +#endif + + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: emm_fsm_get_status() ** + ** ** + ** Description: Get the current value of the EPS Mobility Management ** + ** status ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** Others: _emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: The current value of the EMM status ** + ** Others: None ** + ** ** + ***************************************************************************/ +#ifdef NAS_UE +emm_fsm_state_t emm_fsm_get_status(void) +{ + return (_emm_fsm_status[0]); +} +#endif + +#ifdef NAS_MME +emm_fsm_state_t emm_fsm_get_status(unsigned int ueid, void *ctx) +{ +# if defined(EPC_BUILD) + emm_data_context_t *emm_ctx = (emm_data_context_t*)ctx; + + if (emm_ctx != NULL) { + return emm_ctx->_emm_fsm_status; + } +# else + if (ueid < EMM_FSM_NB_UE_MAX) { + return (_emm_fsm_status[ueid]); + } +#endif + return EMM_STATE_MAX; +} +#endif + +/**************************************************************************** + ** ** + ** Name: emm_fsm_process() ** + ** ** + ** Description: Executes the EMM state machine ** + ** ** + ** Inputs: evt: The EMMREG-SAP event to process ** + ** Others: _emm_fsm_status ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_fsm_process(const emm_reg_t* evt) +{ + emm_fsm_state_t status; + + LOG_FUNC_IN; + + int rc; + emm_reg_primitive_t primitive = evt->primitive; + +#ifdef NAS_UE + status = _emm_fsm_status[0]; +#endif +#ifdef NAS_MME +# if defined(EPC_BUILD) + emm_data_context_t *emm_ctx = (emm_data_context_t*)evt->ctx; + + DevAssert(emm_ctx != NULL); + + status = emm_ctx->_emm_fsm_status; +# else + if (evt->ueid >= EMM_FSM_NB_UE_MAX) { + LOG_FUNC_RETURN (RETURNerror); + } + status = _emm_fsm_status[evt->ueid]; +# endif +#endif + + LOG_TRACE(INFO, "EMM-FSM - Received event %s (%d) in state %s", + _emm_fsm_event_str[primitive - _EMMREG_START - 1], primitive, + _emm_fsm_status_str[status]); + + /* Execute the EMM state machine */ + rc = (_emm_fsm_handlers[status])(evt); + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.h new file mode 100644 index 0000000000..fa7cee6629 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_fsm.h @@ -0,0 +1,95 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_fsm.h + +Version 0.1 + +Date 2012/10/03 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EPS Mobility Management procedures executed at + the EMMREG Service Access Point. + +*****************************************************************************/ +#ifndef __EMM_FSM_H__ +#define __EMM_FSM_H__ + +#include "emm_regDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * States of the EPS Mobility Management sublayer + * ---------------------------------------------- + * The EMM protocol of the UE and the network is described by means of two + * different state machines. + */ +typedef enum { +#ifdef NAS_UE + EMM_NULL, +#endif + EMM_DEREGISTERED, + EMM_REGISTERED, + EMM_DEREGISTERED_INITIATED, +#ifdef NAS_UE + EMM_DEREGISTERED_NORMAL_SERVICE, + EMM_DEREGISTERED_LIMITED_SERVICE, + EMM_DEREGISTERED_ATTEMPTING_TO_ATTACH, + EMM_DEREGISTERED_PLMN_SEARCH, + EMM_DEREGISTERED_NO_IMSI, + EMM_DEREGISTERED_ATTACH_NEEDED, + EMM_DEREGISTERED_NO_CELL_AVAILABLE, + EMM_REGISTERED_INITIATED, + EMM_REGISTERED_NORMAL_SERVICE, + EMM_REGISTERED_ATTEMPTING_TO_UPDATE, + EMM_REGISTERED_LIMITED_SERVICE, + EMM_REGISTERED_PLMN_SEARCH, + EMM_REGISTERED_UPDATE_NEEDED, + EMM_REGISTERED_NO_CELL_AVAILABLE, + EMM_REGISTERED_ATTEMPTING_TO_UPDATE_MM, + EMM_REGISTERED_IMSI_DETACH_INITIATED, + EMM_TRACKING_AREA_UPDATING_INITIATED, + EMM_SERVICE_REQUEST_INITIATED, +#endif +#ifdef NAS_MME + EMM_COMMON_PROCEDURE_INITIATED, +#endif + EMM_STATE_MAX +} emm_fsm_state_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void emm_fsm_initialize(void); + +#ifdef NAS_UE +int emm_fsm_set_status(emm_fsm_state_t status); +emm_fsm_state_t emm_fsm_get_status(void); +#endif +#ifdef NAS_MME +struct emm_data_context_t; +int emm_fsm_set_status(unsigned int ueid, void *ctx, emm_fsm_state_t status); +emm_fsm_state_t emm_fsm_get_status(unsigned int ueid, void *ctx); +#endif + +int emm_fsm_process(const emm_reg_t* evt); + +#endif /* __EMM_FSM_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.c new file mode 100644 index 0000000000..bf7374954c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.c @@ -0,0 +1,1037 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_recv.c + +Version 0.1 + +Date 2013/01/30 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines functions executed at the EMMAS Service Access + Point upon receiving EPS Mobility Management messages + from the Access Stratum sublayer. + +*****************************************************************************/ + +#include "emm_recv.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_msgDef.h" +#include "emm_cause.h" +#include "emm_proc.h" + +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME upon receiving EMM messages + * -------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: emm_recv_status() ** + ** ** + ** Description: Processes EMM status message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_status(unsigned int ueid, emm_status_msg* msg, int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received EMM Status message (cause=%d)", + msg->emmcause); + + /* + * Message checking + */ + *emm_cause = EMM_CAUSE_SUCCESS; + /* + * Message processing + */ + rc = emm_proc_status_ind(ueid, msg->emmcause); + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE upon receiving EMM message from the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_recv_attach_accept() ** + ** ** + ** Description: Processes Attach Accept message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_attach_accept(attach_accept_msg* msg, int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Attach Accept message"); + + /* + * Message checking + */ + if (msg->tailist.typeoflist != + TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS) { + /* Only list of TACs belonging to one PLMN with consecutive + * TAC values is supported */ + *emm_cause = EMM_CAUSE_IE_NOT_IMPLEMENTED; + } + else if (msg->tailist.numberofelements < 1) { + /* The tracking area identity list shall contain + * at leat one TAI value */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + else if ( (msg->presencemask & ATTACH_ACCEPT_GUTI_PRESENT) && + (msg->guti.guti.typeofidentity != EPS_MOBILE_IDENTITY_GUTI) ) { + /* The only supported type of EPS mobile identity is GUTI */ + *emm_cause = EMM_CAUSE_IE_NOT_IMPLEMENTED; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Message processing + */ + /* Compute timers value */ + long T3412, T3402 = -1, T3423 = -1; + T3412 = gprs_timer_value(&msg->t3412value); + if (msg->presencemask & ATTACH_ACCEPT_T3402_VALUE_PRESENT) { + T3402 = gprs_timer_value(&msg->t3402value); + } + if (msg->presencemask & ATTACH_ACCEPT_T3423_VALUE_PRESENT) { + T3423 = gprs_timer_value(&msg->t3423value); + } + /* Get the tracking area list the UE is registered to */ + int n_tais = msg->tailist.numberofelements; + tai_t tai[n_tais]; + for (int i = 0; i < n_tais; i++) { + tai[i].plmn.MCCdigit1 = msg->tailist.mccdigit1; + tai[i].plmn.MCCdigit2 = msg->tailist.mccdigit2; + tai[i].plmn.MCCdigit3 = msg->tailist.mccdigit3; + tai[i].plmn.MNCdigit1 = msg->tailist.mncdigit1; + tai[i].plmn.MNCdigit2 = msg->tailist.mncdigit2; + tai[i].plmn.MNCdigit3 = msg->tailist.mncdigit3; + tai[i].tac = msg->tailist.tac + i; + } + /* Get the GUTI */ + GUTI_t* pguti = NULL; + GUTI_t guti; + if (msg->presencemask & ATTACH_ACCEPT_GUTI_PRESENT) { + pguti = &guti; + guti.gummei.plmn.MCCdigit1 = msg->guti.guti.mccdigit1; + guti.gummei.plmn.MCCdigit2 = msg->guti.guti.mccdigit2; + guti.gummei.plmn.MCCdigit3 = msg->guti.guti.mccdigit3; + guti.gummei.plmn.MNCdigit1 = msg->guti.guti.mncdigit1; + guti.gummei.plmn.MNCdigit2 = msg->guti.guti.mncdigit2; + guti.gummei.plmn.MNCdigit3 = msg->guti.guti.mncdigit3; + guti.gummei.MMEgid = msg->guti.guti.mmegroupid; + guti.gummei.MMEcode = msg->guti.guti.mmecode; + guti.m_tmsi = msg->guti.guti.mtmsi; + } + /* Get the list of equivalent PLMNs */ + int n_eplmns = 0; + plmn_t eplmn; + if (msg->presencemask & ATTACH_ACCEPT_EQUIVALENT_PLMNS_PRESENT) { + n_eplmns = 1; + eplmn.MCCdigit1 = msg->equivalentplmns.mccdigit1; + eplmn.MCCdigit2 = msg->equivalentplmns.mccdigit2; + eplmn.MCCdigit3 = msg->equivalentplmns.mccdigit3; + eplmn.MNCdigit1 = msg->equivalentplmns.mncdigit1; + eplmn.MNCdigit2 = msg->equivalentplmns.mncdigit2; + eplmn.MNCdigit3 = msg->equivalentplmns.mncdigit3; + } + + /* Execute attach procedure accepted by the network */ + rc = emm_proc_attach_accept(T3412, T3402, T3423, n_tais, tai, pguti, + n_eplmns, &eplmn, + &msg->esmmessagecontainer.esmmessagecontainercontents); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_attach_reject() ** + ** ** + ** Description: Processes Attach Reject message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_attach_reject(attach_reject_msg* msg, int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Attach Reject message (cause=%d)", + msg->emmcause); + + /* + * Message checking + */ + if ( (msg->emmcause == EMM_CAUSE_ESM_FAILURE) && + !(msg->presencemask & ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT) ) { + /* The ATTACH REJECT message shall be combined with a PDN + * CONNECTIVITY REJECT message contained in the ESM message + * container information element */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Message processing + */ + if (msg->presencemask & ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT) { + /* Execute attach procedure rejected by the network */ + rc = emm_proc_attach_reject(msg->emmcause, + &msg->esmmessagecontainer.esmmessagecontainercontents); + } else { + /* Execute attach procedure rejected by the network */ + rc = emm_proc_attach_reject(msg->emmcause, NULL); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_detach_accept() ** + ** ** + ** Description: Processes Detach Accept message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_detach_accept(detach_accept_msg* msg, int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Detach Accept message"); + + /* + * Message processing + */ + /* Execute the UE initiated detach procedure completion by the UE */ + rc = emm_proc_detach_accept(); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_identity_request() ** + ** ** + ** Description: Processes Identity Request message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_identity_request(identity_request_msg* msg, int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Identity Request message"); + + /* + * Message processing + */ + /* Get the requested identity type */ + emm_proc_identity_type_t type; + if (msg->identitytype == IDENTITY_TYPE_2_IMSI) { + type = EMM_IDENT_TYPE_IMSI; + } else if (msg->identitytype == IDENTITY_TYPE_2_IMEI) { + type = EMM_IDENT_TYPE_IMEI; + } else if (msg->identitytype == IDENTITY_TYPE_2_IMEISV) { + type = EMM_IDENT_TYPE_IMEISV; + } else if (msg->identitytype == IDENTITY_TYPE_2_TMSI) { + type = EMM_IDENT_TYPE_TMSI; + } else { + /* All other values are interpreted as IMSI */ + type = EMM_IDENT_TYPE_IMSI; + } + + /* Execute the identification procedure initiated by the network */ + rc = emm_proc_identification_request(type); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_authentication_request() ** + ** ** + ** Description: Processes Authentication Request message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_authentication_request(authentication_request_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Authentication Request message"); + + /* + * Message checking + */ + if ( (msg->authenticationparameterrand.rand.length == 0) || + (msg->authenticationparameterautn.autn.length == 0) ) { + /* RAND and AUTN parameters shall not be null */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Message processing + */ + /* Execute the authentication procedure initiated by the network */ + rc = emm_proc_authentication_request( + msg->naskeysetidentifierasme.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, + msg->naskeysetidentifierasme.naskeysetidentifier, + &msg->authenticationparameterrand.rand, + &msg->authenticationparameterautn.autn); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_authentication_reject() ** + ** ** + ** Description: Processes Authentication Reject message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_authentication_reject(authentication_reject_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Authentication Reject message"); + + /* + * Message processing + */ + /* Execute the authentication procedure not accepted by the network */ + rc = emm_proc_authentication_reject(); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_security_mode_command() ** + ** ** + ** Description: Processes Security Mode Command message ** + ** ** + ** Inputs: msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_security_mode_command(security_mode_command_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Security Mode Command message"); + + /* + * Message processing + */ + /* Execute the security mode control procedure initiated by the network */ + rc = emm_proc_security_mode_command( + msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, + msg->naskeysetidentifier.naskeysetidentifier, + msg->selectednassecurityalgorithms.typeofcipheringalgorithm, + msg->selectednassecurityalgorithms.typeofintegrityalgorithm, + msg->replayeduesecuritycapabilities.eea, + msg->replayeduesecuritycapabilities.eia); + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME upon receiving EMM message from the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_recv_attach_request() ** + ** ** + ** Description: Processes Attach Request message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_attach_request(unsigned int ueid, const attach_request_msg* msg, + int* emm_cause) +{ + int rc; + emm_proc_attach_type_t type; + + LOG_FUNC_IN; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Attach Request message"); + + /* + * Message checking + */ +#if !defined(UPDATE_RELEASE_9) + /* SR: In releases 9 and beyond the mandatory ie (old GUTI) has been removed */ + if ( (msg->oldgutiorimsi.guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) && + !(msg->presencemask & ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT) ) { + /* The Old GUTI type IE shall be included if the type of identity + * in the EPS mobile identity IE is set to "GUTI" */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + LOG_TRACE(WARNING, "EMMAS-SAP - [%08x] - Received GUTI identity without " + "old GUTI IEI", ueid); + } + else +#endif /* !defined(UPDATE_RELEASE_9) */ + if (msg->uenetworkcapability.spare != 0b000) { + /* Spare bits shall be coded as zero */ + *emm_cause = EMM_CAUSE_PROTOCOL_ERROR; + LOG_TRACE(WARNING, "EMMAS-SAP - [%08x] - Non zero spare bits is suspicious", + ueid); + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + /* 3GPP TS 24.301, section 5.5.1.2.7, case b + * Perform protocol error abnormal case on the network side */ + rc = emm_proc_attach_reject(ueid, *emm_cause); + *emm_cause = EMM_CAUSE_SUCCESS; + LOG_FUNC_RETURN (rc); + } + /* + * Message processing + */ + /* Get the EPS attach type */ + if (msg->epsattachtype == EPS_ATTACH_TYPE_EPS) { + type = EMM_ATTACH_TYPE_EPS; + } else if (msg->epsattachtype == EPS_ATTACH_TYPE_IMSI) { + type = EMM_ATTACH_TYPE_IMSI; + } else if (msg->epsattachtype == EPS_ATTACH_TYPE_EMERGENCY) { + type = EMM_ATTACH_TYPE_EMERGENCY; + } else if (msg->epsattachtype == EPS_ATTACH_TYPE_RESERVED) { + type = EMM_ATTACH_TYPE_RESERVED; + } else { + /* All other values shall be interpreted as "EPS attach" */ + type = EMM_ATTACH_TYPE_EPS; + } + + /* Get the EPS mobile identity */ + GUTI_t guti, *p_guti = NULL; + imsi_t imsi, *p_imsi = NULL; + imei_t imei, *p_imei = NULL; + if (msg->oldgutiorimsi.guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) + { + /* Get the GUTI */ + p_guti = &guti; + guti.gummei.plmn.MCCdigit1 = msg->oldgutiorimsi.guti.mccdigit1; + guti.gummei.plmn.MCCdigit2 = msg->oldgutiorimsi.guti.mccdigit2; + guti.gummei.plmn.MCCdigit3 = msg->oldgutiorimsi.guti.mccdigit3; + guti.gummei.plmn.MNCdigit1 = msg->oldgutiorimsi.guti.mncdigit1; + guti.gummei.plmn.MNCdigit2 = msg->oldgutiorimsi.guti.mncdigit2; + guti.gummei.plmn.MNCdigit3 = msg->oldgutiorimsi.guti.mncdigit3; + guti.gummei.MMEgid = msg->oldgutiorimsi.guti.mmegroupid; + guti.gummei.MMEcode = msg->oldgutiorimsi.guti.mmecode; + guti.m_tmsi = msg->oldgutiorimsi.guti.mtmsi; + } + else if (msg->oldgutiorimsi.imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) + { + /* Get the IMSI */ + p_imsi = &imsi; + imsi.u.num.digit1 = msg->oldgutiorimsi.imsi.digit1; + imsi.u.num.digit2 = msg->oldgutiorimsi.imsi.digit2; + imsi.u.num.digit3 = msg->oldgutiorimsi.imsi.digit3; + imsi.u.num.digit4 = msg->oldgutiorimsi.imsi.digit4; + imsi.u.num.digit5 = msg->oldgutiorimsi.imsi.digit5; + imsi.u.num.digit6 = msg->oldgutiorimsi.imsi.digit6; + imsi.u.num.digit7 = msg->oldgutiorimsi.imsi.digit7; + imsi.u.num.digit8 = msg->oldgutiorimsi.imsi.digit8; + imsi.u.num.digit9 = msg->oldgutiorimsi.imsi.digit9; + imsi.u.num.digit10 = msg->oldgutiorimsi.imsi.digit10; + imsi.u.num.digit11 = msg->oldgutiorimsi.imsi.digit11; + imsi.u.num.digit12 = msg->oldgutiorimsi.imsi.digit12; + imsi.u.num.digit13 = msg->oldgutiorimsi.imsi.digit13; + imsi.u.num.digit14 = msg->oldgutiorimsi.imsi.digit14; + imsi.u.num.digit15 = msg->oldgutiorimsi.imsi.digit15; + imsi.u.num.parity = msg->oldgutiorimsi.imsi.oddeven; + } + else if (msg->oldgutiorimsi.imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) + { + /* Get the IMEI */ + p_imei = &imei; + imei.u.num.digit1 = msg->oldgutiorimsi.imei.digit1; + imei.u.num.digit2 = msg->oldgutiorimsi.imei.digit2; + imei.u.num.digit3 = msg->oldgutiorimsi.imei.digit3; + imei.u.num.digit4 = msg->oldgutiorimsi.imei.digit4; + imei.u.num.digit5 = msg->oldgutiorimsi.imei.digit5; + imei.u.num.digit6 = msg->oldgutiorimsi.imei.digit6; + imei.u.num.digit7 = msg->oldgutiorimsi.imei.digit7; + imei.u.num.digit8 = msg->oldgutiorimsi.imei.digit8; + imei.u.num.digit9 = msg->oldgutiorimsi.imei.digit9; + imei.u.num.digit10 = msg->oldgutiorimsi.imei.digit10; + imei.u.num.digit11 = msg->oldgutiorimsi.imei.digit11; + imei.u.num.digit12 = msg->oldgutiorimsi.imei.digit12; + imei.u.num.digit13 = msg->oldgutiorimsi.imei.digit13; + imei.u.num.digit14 = msg->oldgutiorimsi.imei.digit14; + imei.u.num.digit15 = msg->oldgutiorimsi.imei.digit15; + imei.u.num.parity = msg->oldgutiorimsi.imei.oddeven; + } + /* TODO: Get the UE network capabilities */ + + /* Get the Last visited registered TAI */ + tai_t tai, *p_tai = NULL; + if (msg->presencemask & ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT) { + p_tai = &tai; + tai.plmn.MCCdigit1 = msg->lastvisitedregisteredtai.mccdigit1; + tai.plmn.MCCdigit2 = msg->lastvisitedregisteredtai.mccdigit2; + tai.plmn.MCCdigit3 = msg->lastvisitedregisteredtai.mccdigit3; + tai.plmn.MNCdigit1 = msg->lastvisitedregisteredtai.mncdigit1; + tai.plmn.MNCdigit2 = msg->lastvisitedregisteredtai.mncdigit2; + tai.plmn.MNCdigit3 = msg->lastvisitedregisteredtai.mncdigit3; + tai.tac = msg->lastvisitedregisteredtai.tac; + } + + /* Execute the requested UE attach procedure */ + rc = emm_proc_attach_request(ueid, type, + msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, + msg->naskeysetidentifier.naskeysetidentifier, + msg->oldgutitype != GUTI_MAPPED, p_guti, p_imsi, p_imei, p_tai, + msg->uenetworkcapability.eea, msg->uenetworkcapability.eia, + &msg->esmmessagecontainer.esmmessagecontainercontents); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_attach_complete() ** + ** ** + ** Description: Processes Attach Complete message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_attach_complete(unsigned int ueid, const attach_complete_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Attach Complete message"); + + /* Execute the attach procedure completion */ + rc = emm_proc_attach_complete(ueid, + &msg->esmmessagecontainer.esmmessagecontainercontents); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_detach_request() ** + ** ** + ** Description: Processes Detach Request message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_detach_request(unsigned int ueid, const detach_request_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Detach Request message"); + + /* + * Message processing + */ + /* Get the detach type */ + emm_proc_detach_type_t type; + if (msg->detachtype.typeofdetach == DETACH_TYPE_EPS) { + type = EMM_DETACH_TYPE_EPS; + } else if (msg->detachtype.typeofdetach == DETACH_TYPE_IMSI) { + type = EMM_DETACH_TYPE_IMSI; + } else if (msg->detachtype.typeofdetach == DETACH_TYPE_EPS_IMSI) { + type = EMM_DETACH_TYPE_EPS_IMSI; + } else if (msg->detachtype.typeofdetach == DETACH_TYPE_RESERVED_1) { + type = EMM_DETACH_TYPE_RESERVED; + } else if (msg->detachtype.typeofdetach == DETACH_TYPE_RESERVED_2) { + type = EMM_DETACH_TYPE_RESERVED; + } else { + /* All other values are interpreted as "combined EPS/IMSI detach" */ + type = DETACH_TYPE_EPS_IMSI; + } + + /* Get the EPS mobile identity */ + GUTI_t guti, *p_guti = NULL; + imsi_t imsi, *p_imsi = NULL; + imei_t imei, *p_imei = NULL; + if (msg->gutiorimsi.guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) + { + /* Get the GUTI */ + p_guti = &guti; + guti.gummei.plmn.MCCdigit1 = msg->gutiorimsi.guti.mccdigit1; + guti.gummei.plmn.MCCdigit2 = msg->gutiorimsi.guti.mccdigit2; + guti.gummei.plmn.MCCdigit3 = msg->gutiorimsi.guti.mccdigit3; + guti.gummei.plmn.MNCdigit1 = msg->gutiorimsi.guti.mncdigit1; + guti.gummei.plmn.MNCdigit2 = msg->gutiorimsi.guti.mncdigit2; + guti.gummei.plmn.MNCdigit3 = msg->gutiorimsi.guti.mncdigit3; + guti.gummei.MMEgid = msg->gutiorimsi.guti.mmegroupid; + guti.gummei.MMEcode = msg->gutiorimsi.guti.mmecode; + guti.m_tmsi = msg->gutiorimsi.guti.mtmsi; + } + else if (msg->gutiorimsi.imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) + { + /* Get the IMSI */ + p_imsi = &imsi; + imsi.u.num.digit1 = msg->gutiorimsi.imsi.digit1; + imsi.u.num.digit2 = msg->gutiorimsi.imsi.digit2; + imsi.u.num.digit3 = msg->gutiorimsi.imsi.digit3; + imsi.u.num.digit4 = msg->gutiorimsi.imsi.digit4; + imsi.u.num.digit5 = msg->gutiorimsi.imsi.digit5; + imsi.u.num.digit6 = msg->gutiorimsi.imsi.digit6; + imsi.u.num.digit7 = msg->gutiorimsi.imsi.digit7; + imsi.u.num.digit8 = msg->gutiorimsi.imsi.digit8; + imsi.u.num.digit9 = msg->gutiorimsi.imsi.digit9; + imsi.u.num.digit10 = msg->gutiorimsi.imsi.digit10; + imsi.u.num.digit11 = msg->gutiorimsi.imsi.digit11; + imsi.u.num.digit12 = msg->gutiorimsi.imsi.digit12; + imsi.u.num.digit13 = msg->gutiorimsi.imsi.digit13; + imsi.u.num.digit14 = msg->gutiorimsi.imsi.digit14; + imsi.u.num.digit15 = msg->gutiorimsi.imsi.digit15; + imsi.u.num.parity = msg->gutiorimsi.imsi.oddeven; + } + else if (msg->gutiorimsi.imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) + { + /* Get the IMEI */ + p_imei = &imei; + imei.u.num.digit1 = msg->gutiorimsi.imei.digit1; + imei.u.num.digit2 = msg->gutiorimsi.imei.digit2; + imei.u.num.digit3 = msg->gutiorimsi.imei.digit3; + imei.u.num.digit4 = msg->gutiorimsi.imei.digit4; + imei.u.num.digit5 = msg->gutiorimsi.imei.digit5; + imei.u.num.digit6 = msg->gutiorimsi.imei.digit6; + imei.u.num.digit7 = msg->gutiorimsi.imei.digit7; + imei.u.num.digit8 = msg->gutiorimsi.imei.digit8; + imei.u.num.digit9 = msg->gutiorimsi.imei.digit9; + imei.u.num.digit10 = msg->gutiorimsi.imei.digit10; + imei.u.num.digit11 = msg->gutiorimsi.imei.digit11; + imei.u.num.digit12 = msg->gutiorimsi.imei.digit12; + imei.u.num.digit13 = msg->gutiorimsi.imei.digit13; + imei.u.num.digit14 = msg->gutiorimsi.imei.digit14; + imei.u.num.digit15 = msg->gutiorimsi.imei.digit15; + imei.u.num.parity = msg->gutiorimsi.imei.oddeven; + } + + /* Execute the UE initiated detach procedure completion by the network */ + rc = emm_proc_detach_request(ueid, type, + msg->detachtype.switchoff != DETACH_TYPE_NORMAL_DETACH, + msg->naskeysetidentifier.tsc != NAS_KEY_SET_IDENTIFIER_MAPPED, + msg->naskeysetidentifier.naskeysetidentifier, + p_guti, p_imsi, p_imei); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_identity_response() ** + ** ** + ** Description: Processes Identity Response message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_identity_response(unsigned int ueid, identity_response_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Identity Response message"); + + /* + * Message processing + */ + /* Get the mobile identity */ + imsi_t imsi, *p_imsi = NULL; + imei_t imei, *p_imei = NULL; + struct tmsi_struct_t { + uint8_t digit1:4; + uint8_t digit2:4; + uint8_t digit3:4; + uint8_t digit4:4; + uint8_t digit5:4; + uint8_t digit6:4; + uint8_t digit7:4; + uint8_t digit8:4; + } tmsi, *p_tmsi = NULL; + if (msg->mobileidentity.imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + /* Get the IMSI */ + p_imsi = &imsi; + imsi.u.num.digit1 = msg->mobileidentity.imsi.digit1; + imsi.u.num.digit2 = msg->mobileidentity.imsi.digit2; + imsi.u.num.digit3 = msg->mobileidentity.imsi.digit3; + imsi.u.num.digit4 = msg->mobileidentity.imsi.digit4; + imsi.u.num.digit5 = msg->mobileidentity.imsi.digit5; + imsi.u.num.digit6 = msg->mobileidentity.imsi.digit6; + imsi.u.num.digit7 = msg->mobileidentity.imsi.digit7; + imsi.u.num.digit8 = msg->mobileidentity.imsi.digit8; + imsi.u.num.digit9 = msg->mobileidentity.imsi.digit9; + imsi.u.num.digit10 = msg->mobileidentity.imsi.digit10; + imsi.u.num.digit11 = msg->mobileidentity.imsi.digit11; + imsi.u.num.digit12 = msg->mobileidentity.imsi.digit12; + imsi.u.num.digit13 = msg->mobileidentity.imsi.digit13; + imsi.u.num.digit14 = msg->mobileidentity.imsi.digit14; + imsi.u.num.digit15 = msg->mobileidentity.imsi.digit15; + imsi.u.num.parity = msg->mobileidentity.imsi.oddeven; + } + else if ((msg->mobileidentity.imei.typeofidentity == MOBILE_IDENTITY_IMEI) || + (msg->mobileidentity.imeisv.typeofidentity==MOBILE_IDENTITY_IMEISV)) + { + /* Get the IMEI */ + p_imei = &imei; + imei.u.num.digit1 = msg->mobileidentity.imei.digit1; + imei.u.num.digit2 = msg->mobileidentity.imei.digit2; + imei.u.num.digit3 = msg->mobileidentity.imei.digit3; + imei.u.num.digit4 = msg->mobileidentity.imei.digit4; + imei.u.num.digit5 = msg->mobileidentity.imei.digit5; + imei.u.num.digit6 = msg->mobileidentity.imei.digit6; + imei.u.num.digit7 = msg->mobileidentity.imei.digit7; + imei.u.num.digit8 = msg->mobileidentity.imei.digit8; + imei.u.num.digit9 = msg->mobileidentity.imei.digit9; + imei.u.num.digit10 = msg->mobileidentity.imei.digit10; + imei.u.num.digit11 = msg->mobileidentity.imei.digit11; + imei.u.num.digit12 = msg->mobileidentity.imei.digit12; + imei.u.num.digit13 = msg->mobileidentity.imei.digit13; + imei.u.num.digit14 = msg->mobileidentity.imei.digit14; + imei.u.num.digit15 = msg->mobileidentity.imei.digit15; + imei.u.num.parity = msg->mobileidentity.imei.oddeven; + } + else if (msg->mobileidentity.tmsi.typeofidentity == MOBILE_IDENTITY_TMSI) + { + /* Get the TMSI */ + p_tmsi = &tmsi; + tmsi.digit1 = msg->mobileidentity.tmsi.digit2; + tmsi.digit2 = msg->mobileidentity.tmsi.digit3; + tmsi.digit3 = msg->mobileidentity.tmsi.digit4; + tmsi.digit4 = msg->mobileidentity.tmsi.digit5; + tmsi.digit5 = msg->mobileidentity.tmsi.digit6; + tmsi.digit6 = msg->mobileidentity.tmsi.digit7; + tmsi.digit7 = msg->mobileidentity.tmsi.digit8; + tmsi.digit8 = msg->mobileidentity.tmsi.digit9; + } + + /* Execute the identification completion procedure */ + rc = emm_proc_identification_complete(ueid, p_imsi, p_imei, + (UInt32_t*)(p_tmsi)); + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_authentication_response() ** + ** ** + ** Description: Processes Authentication Response message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_authentication_response(unsigned int ueid, + authentication_response_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Authentication Response message"); + + /* + * Message checking + */ + if (msg->authenticationresponseparameter.res.length == 0) { + /* RES parameter shall not be null */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Message processing + */ + /* Execute the authentication completion procedure */ + rc = emm_proc_authentication_complete(ueid, EMM_CAUSE_SUCCESS, + &msg->authenticationresponseparameter.res); + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_authentication_failure() ** + ** ** + ** Description: Processes Authentication Failure message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_authentication_failure(unsigned int ueid, + authentication_failure_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Authentication Failure message"); + + /* + * Message checking + */ + if (msg->emmcause == EMM_CAUSE_SUCCESS) { + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + else if ( (msg->emmcause == EMM_CAUSE_SYNCH_FAILURE) && + !(msg->presencemask & AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT) ) + { + /* AUTS parameter shall be present in case of "synch failure" */ + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Message processing + */ + /* Execute the authentication completion procedure */ + rc = emm_proc_authentication_complete(ueid, msg->emmcause, + &msg->authenticationfailureparameter.auts); + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_security_mode_complete() ** + ** ** + ** Description: Processes Security Mode Complete message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_security_mode_complete(unsigned int ueid, + security_mode_complete_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Security Mode Complete message"); + + /* + * Message processing + */ + /* Execute the NAS security mode control completion procedure */ + rc = emm_proc_security_mode_complete(ueid); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: emm_recv_security_mode_reject() ** + ** ** + ** Description: Processes Security Mode Reject message ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** msg: The received EMM message ** + ** Others: None ** + ** ** + ** Outputs: emm_cause: EMM cause code ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_recv_security_mode_reject(unsigned int ueid, + security_mode_reject_msg* msg, + int* emm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "EMMAS-SAP - Received Security Mode Reject message " + "(cause=%d)", msg->emmcause); + + /* + * Message checking + */ + if (msg->emmcause == EMM_CAUSE_SUCCESS) { + *emm_cause = EMM_CAUSE_INVALID_MANDATORY_INFO; + } + /* Handle message checking error */ + if (*emm_cause != EMM_CAUSE_SUCCESS) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Message processing + */ + /* Execute the NAS security mode commend not accepted by the UE */ + rc = emm_proc_security_mode_reject(ueid); + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.h new file mode 100644 index 0000000000..6bbc3ba21b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_recv.h @@ -0,0 +1,120 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_recv.h + +Version 0.1 + +Date 2013/01/30 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines functions executed at the EMMAS Service Access + Point upon receiving EPS Mobility Management messages + from the Access Stratum sublayer. + +*****************************************************************************/ +#ifndef __EMM_RECV_H__ +#define __EMM_RECV_H__ + +#include "EmmStatus.h" + +#include "DetachRequest.h" +#include "DetachAccept.h" + +#ifdef NAS_UE +#include "AttachAccept.h" +#include "AttachReject.h" +#include "TrackingAreaUpdateAccept.h" +#include "TrackingAreaUpdateReject.h" +#include "ServiceReject.h" +#include "GutiReallocationCommand.h" +#include "AuthenticationRequest.h" +#include "AuthenticationReject.h" +#include "IdentityRequest.h" +#include "SecurityModeCommand.h" +#include "EmmInformation.h" +#include "DownlinkNasTransport.h" +#include "CsServiceNotification.h" +#endif + +#ifdef NAS_MME +#include "AttachRequest.h" +#include "AttachComplete.h" +#include "TrackingAreaUpdateRequest.h" +#include "TrackingAreaUpdateComplete.h" +#include "ServiceRequest.h" +#include "ExtendedServiceRequest.h" +#include "GutiReallocationComplete.h" +#include "AuthenticationResponse.h" +#include "AuthenticationFailure.h" +#include "IdentityResponse.h" +#include "SecurityModeComplete.h" +#include "SecurityModeReject.h" +#include "UplinkNasTransport.h" +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME upon receiving EMM messages + * -------------------------------------------------------------------------- + */ +int emm_recv_status(unsigned int ueid, emm_status_msg* msg, int* emm_cause); + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE upon receiving EMM message from the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_recv_attach_accept(attach_accept_msg* msg, int* emm_cause); +int emm_recv_attach_reject(attach_reject_msg* msg, int* emm_cause); + +int emm_recv_detach_accept(detach_accept_msg* msg, int* emm_cause); + +int emm_recv_identity_request(identity_request_msg* msg, int* emm_cause); +int emm_recv_authentication_request(authentication_request_msg* msg, int* emm_cause); +int emm_recv_authentication_reject(authentication_reject_msg* msg, int* emm_cause); +int emm_recv_security_mode_command(security_mode_command_msg* msg, int* emm_cause); +#endif + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME upon receiving EMM message from the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +int emm_recv_attach_request(unsigned int ueid, const attach_request_msg* msg, int* emm_cause); +int emm_recv_attach_complete(unsigned int ueid, const attach_complete_msg* msg, int* emm_cause); + +int emm_recv_detach_request(unsigned int ueid, const detach_request_msg* msg, int* emm_cause); + +int emm_recv_identity_response(unsigned int ueid, identity_response_msg* msg, int* emm_cause); +int emm_recv_authentication_response(unsigned int ueid, authentication_response_msg* msg, int* emm_cause); +int emm_recv_authentication_failure(unsigned int ueid, authentication_failure_msg* msg, int* emm_cause); +int emm_recv_security_mode_complete(unsigned int ueid, security_mode_complete_msg* msg, int* emm_cause); +int emm_recv_security_mode_reject(unsigned int ueid, security_mode_reject_msg* msg, int* emm_cause); +#endif + +#endif /* __EMM_RECV_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.c new file mode 100644 index 0000000000..92c433e6f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.c @@ -0,0 +1,100 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_reg.c + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMREG Service Access Point that provides + registration services for location updating and attach/detach + procedures. + +*****************************************************************************/ + +#include "emm_reg.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_fsm.h" + +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_reg_initialize() ** + ** ** + ** Description: Initializes the EMMREG Service Access Point ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: NONE ** + ** ** + ***************************************************************************/ +void emm_reg_initialize(void) +{ + LOG_FUNC_IN; + + /* Initialize the EMM state machine */ + emm_fsm_initialize(); + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: emm_reg_send() ** + ** ** + ** Description: Processes the EMMREG Service Access Point primitive ** + ** ** + ** Inputs: msg: The EMMREG-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_reg_send(const emm_reg_t* msg) +{ + LOG_FUNC_IN; + + int rc; + + /* Check the EMM-SAP primitive */ + emm_reg_primitive_t primitive = msg->primitive; + assert( (primitive > _EMMREG_START) && (primitive < _EMMREG_END)); + + /* Execute the EMM procedure */ + rc = emm_fsm_process(msg); + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.h new file mode 100644 index 0000000000..7419f7eafe --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_reg.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_reg.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMREG Service Access Point that provides + registration services for location updating and attach/detach + procedures. + +*****************************************************************************/ +#ifndef __EMM_REG_H__ +#define __EMM_REG_H__ + +#include "emm_regDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void emm_reg_initialize(void); + +int emm_reg_send(const emm_reg_t* msg); + +#endif /* __EMM_REG_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h new file mode 100644 index 0000000000..a73876e34c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h @@ -0,0 +1,145 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_regDef.h + +Version 0.1 + +Date 2012/10/16 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMMREG Service Access Point that provides + registration services for location updating and attach/detach + procedures. + +*****************************************************************************/ +#ifndef __EMM_REGDEF_H__ +#define __EMM_REGDEF_H__ + +#include "commonDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * EMMREG-SAP primitives + */ +typedef enum { + _EMMREG_START = 0, +#ifdef NAS_UE + _EMMREG_S1_ENABLED, /* S1 mode is enabled */ + _EMMREG_S1_DISABLED, /* S1 mode is disabled */ + _EMMREG_NO_IMSI, /* The UE is powered on without a valid USIM */ + _EMMREG_NO_CELL, /* No available cell has been found */ + _EMMREG_REGISTER_REQ, /* Network registration procedure requested */ + _EMMREG_REGISTER_CNF, /* Network registration procedure succeed */ + _EMMREG_REGISTER_REJ, /* Network registration procedure rejected */ + _EMMREG_ATTACH_INIT, /* EPS network attach initiated */ + _EMMREG_ATTACH_REQ, /* EPS network attach requested */ + _EMMREG_ATTACH_FAILED, /* Attach attempt failed */ + _EMMREG_ATTACH_EXCEEDED, /* Attach attempt exceeded */ + _EMMREG_AUTH_REJ, /* Authentication rejected */ +#endif +#ifdef NAS_MME + _EMMREG_COMMON_PROC_REQ, /* EMM common procedure requested */ + _EMMREG_COMMON_PROC_CNF, /* EMM common procedure successful */ + _EMMREG_COMMON_PROC_REJ, /* EMM common procedure failed */ + _EMMREG_PROC_ABORT, /* EMM procedure aborted */ +#endif + _EMMREG_ATTACH_CNF, /* EPS network attach accepted */ + _EMMREG_ATTACH_REJ, /* EPS network attach rejected */ + _EMMREG_DETACH_INIT, /* Network detach initiated */ + _EMMREG_DETACH_REQ, /* Network detach requested */ + _EMMREG_DETACH_FAILED, /* Network detach attempt failed */ + _EMMREG_DETACH_CNF, /* Network detach accepted */ + _EMMREG_TAU_REQ, + _EMMREG_TAU_CNF, + _EMMREG_TAU_REJ, + _EMMREG_SERVICE_REQ, + _EMMREG_SERVICE_CNF, + _EMMREG_SERVICE_REJ, + _EMMREG_LOWERLAYER_SUCCESS, /* Data successfully delivered */ + _EMMREG_LOWERLAYER_FAILURE, /* Lower layer failure indication */ + _EMMREG_LOWERLAYER_RELEASE, /* NAS signalling connection released */ + _EMMREG_END +} emm_reg_primitive_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * EMMREG primitive for network registration procedure + * ---------------------------------------------------- + */ +typedef struct { + int index; /* Index of the currently selected PLMN in the ordered + * list of available PLMNs */ +} emm_reg_register_t; +#endif + +/* + * EMMREG primitive for attach procedure + * ------------------------------------- + */ +typedef struct { + int is_emergency; /* TRUE if the UE was attempting to register to + * the network for emergency services only */ +} emm_reg_attach_t; + +/* + * EMMREG primitive for detach procedure + * ------------------------------------- + */ +typedef struct { + int switch_off; /* TRUE if the UE is switched off */ + int type; /* Network detach type */ +} emm_reg_detach_t; + +#ifdef NAS_MME +/* + * EMMREG primitive for EMM common procedures + * ------------------------------------------ + */ +typedef struct { + int is_attached; /* UE context attach indicator */ +} emm_reg_common_t; +#endif + +/* + * Structure of EMMREG-SAP primitive + */ +typedef struct { + emm_reg_primitive_t primitive; + unsigned int ueid; + void *ctx; + + union { + emm_reg_attach_t attach; + emm_reg_detach_t detach; +#ifdef NAS_UE + emm_reg_register_t regist; +#endif +#ifdef NAS_MME + emm_reg_common_t common; +#endif + } u; +} emm_reg_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __EMM_REGDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.c new file mode 100644 index 0000000000..9ba72138d7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.c @@ -0,0 +1,120 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_sap.c + +Version 0.1 + +Date 2012/10/01 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMM Service Access Points at which the EPS + Mobility Management sublayer provides procedures for the + control of security and mobility when the User Equipment + is using the Evolved UTRA Network. + +*****************************************************************************/ + +#include "emm_sap.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_reg.h" +#include "emm_esm.h" +#include "emm_as.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: emm_sap_initialize() ** + ** ** + ** Description: Initializes the EMM Service Access Points ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: NONE ** + ** ** + ***************************************************************************/ +void emm_sap_initialize(void) +{ + LOG_FUNC_IN; + + emm_reg_initialize(); + emm_esm_initialize(); + emm_as_initialize(); + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: emm_sap_send() ** + ** ** + ** Description: Processes the EMM Service Access Point primitive ** + ** ** + ** Inputs: msg: The EMM-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: msg: The EMM-SAP primitive to process ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_sap_send(emm_sap_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + emm_primitive_t primitive = msg->primitive; + + /* Check the EMM-SAP primitive */ + if ( (primitive > EMMREG_PRIMITIVE_MIN) && + (primitive < EMMREG_PRIMITIVE_MAX) ) { + /* Forward to the EMMREG-SAP */ + msg->u.emm_reg.primitive = primitive; + rc = emm_reg_send(&msg->u.emm_reg); + } + else if ( (primitive > EMMESM_PRIMITIVE_MIN) && + (primitive < EMMESM_PRIMITIVE_MAX) ) { + /* Forward to the EMMESM-SAP */ + msg->u.emm_esm.primitive = primitive; + rc = emm_esm_send(&msg->u.emm_esm); + } + else if ( (primitive > EMMAS_PRIMITIVE_MIN) && + (primitive < EMMAS_PRIMITIVE_MAX) ) { + /* Forward to the EMMAS-SAP */ + msg->u.emm_as.primitive = primitive; + rc = emm_as_send(&msg->u.emm_as); + } + else { + LOG_TRACE(WARNING, "EMM-SAP - Out of range primitive (%d)", primitive); + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h new file mode 100644 index 0000000000..09bedaf3c4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h @@ -0,0 +1,151 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_sap.h + +Version 0.1 + +Date 2012/10/01 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines the EMM Service Access Points at which the EPS + Mobility Management sublayer provides procedures for the + control of security and mobility when the User Equipment + is using the Evolved UTRA Network. + +*****************************************************************************/ +#ifndef __EMM_SAP_H__ +#define __EMM_SAP_H__ + +#include "emm_regDef.h" +#include "emm_esmDef.h" +#include "emm_asDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * EPS Mobility Management primitives + * ---------------------------------- + * EMMREG-SAP provides registration services for location updating and + * attach/detach procedures; + * EMMESM-SAP provides interlayer services to the EPS Session Management + * sublayer for service registration and activate/deactivate PDP context; + * EMMAS-SAP provides services to the Access Stratum sublayer for NAS message + * transfer; + */ +typedef enum { + /* EMMREG-SAP */ +#ifdef NAS_UE + EMMREG_S1_ENABLED = _EMMREG_S1_ENABLED, + EMMREG_S1_DISABLED = _EMMREG_S1_DISABLED, + EMMREG_NO_IMSI = _EMMREG_NO_IMSI, + EMMREG_NO_CELL = _EMMREG_NO_CELL, + EMMREG_REGISTER_REQ = _EMMREG_REGISTER_REQ, + EMMREG_REGISTER_CNF = _EMMREG_REGISTER_CNF, + EMMREG_REGISTER_REJ = _EMMREG_REGISTER_REJ, + EMMREG_ATTACH_INIT = _EMMREG_ATTACH_INIT, + EMMREG_ATTACH_REQ = _EMMREG_ATTACH_REQ, + EMMREG_ATTACH_FAILED = _EMMREG_ATTACH_FAILED, + EMMREG_ATTACH_EXCEEDED = _EMMREG_ATTACH_EXCEEDED, + EMMREG_AUTH_REJ = _EMMREG_AUTH_REJ, +#endif +#ifdef NAS_MME + EMMREG_COMMON_PROC_REQ = _EMMREG_COMMON_PROC_REQ, + EMMREG_COMMON_PROC_CNF = _EMMREG_COMMON_PROC_CNF, + EMMREG_COMMON_PROC_REJ = _EMMREG_COMMON_PROC_REJ, + EMMREG_PROC_ABORT = _EMMREG_PROC_ABORT, +#endif + EMMREG_ATTACH_CNF = _EMMREG_ATTACH_CNF, + EMMREG_ATTACH_REJ = _EMMREG_ATTACH_REJ, + EMMREG_DETACH_INIT = _EMMREG_DETACH_INIT, + EMMREG_DETACH_REQ = _EMMREG_DETACH_REQ, + EMMREG_DETACH_FAILED = _EMMREG_DETACH_FAILED, + EMMREG_DETACH_CNF = _EMMREG_DETACH_CNF, + EMMREG_TAU_REQ = _EMMREG_TAU_REQ, + EMMREG_TAU_CNF = _EMMREG_TAU_CNF, + EMMREG_TAU_REJ = _EMMREG_TAU_REJ, + EMMREG_SERVICE_REQ = _EMMREG_SERVICE_REQ, + EMMREG_SERVICE_CNF = _EMMREG_SERVICE_CNF, + EMMREG_SERVICE_REJ = _EMMREG_SERVICE_REJ, + EMMREG_LOWERLAYER_SUCCESS = _EMMREG_LOWERLAYER_SUCCESS, + EMMREG_LOWERLAYER_FAILURE = _EMMREG_LOWERLAYER_FAILURE, + EMMREG_LOWERLAYER_RELEASE = _EMMREG_LOWERLAYER_RELEASE, + /* EMMESM-SAP */ +#ifdef NAS_UE + EMMESM_ESTABLISH_REQ = _EMMESM_ESTABLISH_REQ, + EMMESM_ESTABLISH_CNF = _EMMESM_ESTABLISH_CNF, + EMMESM_ESTABLISH_REJ = _EMMESM_ESTABLISH_REJ, +#endif + EMMESM_RELEASE_IND = _EMMESM_RELEASE_IND, + EMMESM_UNITDATA_REQ = _EMMESM_UNITDATA_REQ, + EMMESM_UNITDATA_IND = _EMMESM_UNITDATA_IND, + /* EMMAS-SAP */ + EMMAS_SECURITY_REQ = _EMMAS_SECURITY_REQ, + EMMAS_SECURITY_IND = _EMMAS_SECURITY_IND, + EMMAS_SECURITY_RES = _EMMAS_SECURITY_RES, + EMMAS_SECURITY_REJ = _EMMAS_SECURITY_REJ, + EMMAS_ESTABLISH_REQ = _EMMAS_ESTABLISH_REQ, + EMMAS_ESTABLISH_CNF = _EMMAS_ESTABLISH_CNF, + EMMAS_ESTABLISH_REJ = _EMMAS_ESTABLISH_REJ, + EMMAS_RELEASE_REQ = _EMMAS_RELEASE_REQ, + EMMAS_RELEASE_IND = _EMMAS_RELEASE_IND, + EMMAS_DATA_REQ = _EMMAS_DATA_REQ, + EMMAS_DATA_IND = _EMMAS_DATA_IND, + EMMAS_PAGE_IND = _EMMAS_PAGE_IND, + EMMAS_STATUS_IND = _EMMAS_STATUS_IND, + EMMAS_CELL_INFO_REQ = _EMMAS_CELL_INFO_REQ, + EMMAS_CELL_INFO_RES = _EMMAS_CELL_INFO_RES, + EMMAS_CELL_INFO_IND = _EMMAS_CELL_INFO_IND, +} emm_primitive_t; + +/* + * Minimal identifier for EMM-SAP primitives + */ +#define EMMREG_PRIMITIVE_MIN _EMMREG_START +#define EMMESM_PRIMITIVE_MIN _EMMESM_START +#define EMMAS_PRIMITIVE_MIN _EMMAS_START + +/* + * Maximal identifier for EMM-SAP primitives + */ +#define EMMREG_PRIMITIVE_MAX _EMMREG_END +#define EMMESM_PRIMITIVE_MAX _EMMESM_END +#define EMMAS_PRIMITIVE_MAX _EMMAS_END + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Structure of EPS Mobility Management primitive + */ +typedef struct { + emm_primitive_t primitive; + union { + emm_reg_t emm_reg; /* EMMREG-SAP primitives */ + emm_esm_t emm_esm; /* EMMESM-SAP primitives */ + emm_as_t emm_as; /* EMMAS-SAP primitives */ + } u; +} emm_sap_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void emm_sap_initialize(void); + +int emm_sap_send(emm_sap_t* msg); + +#endif /* __EMM_SAP_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.c b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.c new file mode 100644 index 0000000000..dfe9cfa7e8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.c @@ -0,0 +1,1171 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_send.c + +Version 0.1 + +Date 2013/01/30 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines functions executed at the EMMAS Service Access + Point to send EPS Mobility Management messages to the + Access Stratum sublayer. + +*****************************************************************************/ + +#include "emm_send.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "emm_msgDef.h" +#include "emm_proc.h" + +#include <string.h> // strlen + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME to send EMM messages + * -------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: emm_send_status() ** + ** ** + ** Description: Builds EMM status message ** + ** ** + ** The EMM status message is sent by the UE or the network ** + ** at any time to report certain error conditions. ** + ** ** + ** Inputs: emm_cause: EMM cause code ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_status(const emm_as_status_t* msg, emm_status_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(WARNING, "EMMAS-SAP - Send EMM Status message (cause=%d)", + msg->emm_cause); + + /* Mandatory - Message type */ + emm_msg->messagetype = EMM_STATUS; + + /* Mandatory - EMM cause */ + size += EMM_CAUSE_MAXIMUM_LENGTH; + emm_msg->emmcause = msg->emm_cause; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_detach_accept() ** + ** ** + ** Description: Builds Detach Accept message ** + ** ** + ** The Detach Accept message is sent by the UE or the net- ** + ** work to indicate that the detach procedure has been com- ** + ** pleted. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_detach_accept(const emm_as_data_t* msg, + detach_accept_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Detach Accept message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = DETACH_ACCEPT; + + LOG_FUNC_RETURN (size); +} + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE to send EMM messages to the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: emm_send_attach_request() ** + ** ** + ** Description: Builds Attach Request message ** + ** ** + ** The Attach Request message is sent by the UE to the net- ** + ** work in order to perform an attach procedure. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_attach_request(const emm_as_establish_t* msg, + attach_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Attach Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = ATTACH_REQUEST; + + /* Mandatory - EPS attach type */ + size += EPS_ATTACH_TYPE_MAXIMUM_LENGTH; + if (msg->type == EMM_ATTACH_TYPE_EPS) { + emm_msg->epsattachtype = EPS_ATTACH_TYPE_EPS; + } else if (msg->type == EMM_ATTACH_TYPE_IMSI) { + emm_msg->epsattachtype = EPS_ATTACH_TYPE_IMSI; + } else if (msg->type == EMM_ATTACH_TYPE_EMERGENCY) { + emm_msg->epsattachtype = EPS_ATTACH_TYPE_EMERGENCY; + } else if (msg->type == EMM_ATTACH_TYPE_RESERVED) { + emm_msg->epsattachtype = EPS_ATTACH_TYPE_RESERVED; + } else { + /* All other values shall be interpreted as "EPS attach" */ + emm_msg->epsattachtype = EPS_ATTACH_TYPE_EPS; + } + + /* Mandatory - NAS key set identifier */ + size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH; + if (msg->ksi != EMM_AS_NO_KEY_AVAILABLE) { + emm_msg->naskeysetidentifier.naskeysetidentifier = msg->ksi; + } else { + emm_msg->naskeysetidentifier.naskeysetidentifier = + NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE; + } + + /* Mandatory - EPS mobile identity */ + size += EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH; + if (msg->UEid.guti) { + /* Set GUTI mobile identity */ + GutiEpsMobileIdentity_t* guti = &emm_msg->oldgutiorimsi.guti; + guti->typeofidentity = EPS_MOBILE_IDENTITY_GUTI; + guti->oddeven = EPS_MOBILE_IDENTITY_EVEN; + guti->mmegroupid = msg->UEid.guti->gummei.MMEgid; + guti->mmecode = msg->UEid.guti->gummei.MMEcode; + guti->mtmsi = msg->UEid.guti->m_tmsi; + guti->mccdigit1 = msg->UEid.guti->gummei.plmn.MCCdigit1; + guti->mccdigit2 = msg->UEid.guti->gummei.plmn.MCCdigit2; + guti->mccdigit3 = msg->UEid.guti->gummei.plmn.MCCdigit3; + guti->mncdigit1 = msg->UEid.guti->gummei.plmn.MNCdigit1; + guti->mncdigit2 = msg->UEid.guti->gummei.plmn.MNCdigit2; + guti->mncdigit3 = msg->UEid.guti->gummei.plmn.MNCdigit3; + } else if (msg->UEid.imsi) { + /* Set IMSI mobile identity */ + ImsiEpsMobileIdentity_t* imsi = &emm_msg->oldgutiorimsi.imsi; + imsi->typeofidentity = EPS_MOBILE_IDENTITY_IMSI; + imsi->oddeven = msg->UEid.imsi->u.num.parity; + imsi->digit1 = msg->UEid.imsi->u.num.digit1; + imsi->digit2 = msg->UEid.imsi->u.num.digit2; + imsi->digit3 = msg->UEid.imsi->u.num.digit3; + imsi->digit4 = msg->UEid.imsi->u.num.digit4; + imsi->digit5 = msg->UEid.imsi->u.num.digit5; + imsi->digit6 = msg->UEid.imsi->u.num.digit6; + imsi->digit7 = msg->UEid.imsi->u.num.digit7; + imsi->digit8 = msg->UEid.imsi->u.num.digit8; + imsi->digit9 = msg->UEid.imsi->u.num.digit9; + imsi->digit10 = msg->UEid.imsi->u.num.digit10; + imsi->digit11 = msg->UEid.imsi->u.num.digit11; + imsi->digit12 = msg->UEid.imsi->u.num.digit12; + imsi->digit13 = msg->UEid.imsi->u.num.digit13; + imsi->digit14 = msg->UEid.imsi->u.num.digit14; + imsi->digit15 = msg->UEid.imsi->u.num.digit15; + } else if (msg->UEid.imei) { + /* Set IMEI mobile identity */ + ImeiEpsMobileIdentity_t* imei = &emm_msg->oldgutiorimsi.imei; + imei->typeofidentity = EPS_MOBILE_IDENTITY_IMEI; + imei->oddeven = msg->UEid.imei->u.num.parity; + imei->digit1 = msg->UEid.imei->u.num.digit1; + imei->digit2 = msg->UEid.imei->u.num.digit2; + imei->digit3 = msg->UEid.imei->u.num.digit3; + imei->digit4 = msg->UEid.imei->u.num.digit4; + imei->digit5 = msg->UEid.imei->u.num.digit5; + imei->digit6 = msg->UEid.imei->u.num.digit6; + imei->digit7 = msg->UEid.imei->u.num.digit7; + imei->digit8 = msg->UEid.imei->u.num.digit8; + imei->digit9 = msg->UEid.imei->u.num.digit9; + imei->digit10 = msg->UEid.imei->u.num.digit10; + imei->digit11 = msg->UEid.imei->u.num.digit11; + imei->digit12 = msg->UEid.imei->u.num.digit12; + imei->digit13 = msg->UEid.imei->u.num.digit13; + imei->digit14 = msg->UEid.imei->u.num.digit14; + imei->digit15 = msg->UEid.imei->u.num.digit15; + } + + /* Mandatory - UE network capability */ + size += UE_NETWORK_CAPABILITY_MAXIMUM_LENGTH; + emm_msg->uenetworkcapability.eea = (0x80 >> msg->encryption); + emm_msg->uenetworkcapability.eia = (0x80 >> msg->integrity); + emm_msg->uenetworkcapability.uea = 0; + emm_msg->uenetworkcapability.ucs2 = 0; + emm_msg->uenetworkcapability.uia = 0; + emm_msg->uenetworkcapability.csfb = 0; + emm_msg->uenetworkcapability.lpp = 0; + emm_msg->uenetworkcapability.lcs = 0; + emm_msg->uenetworkcapability.srvcc = 0; + emm_msg->uenetworkcapability.nf = 0; + + /* Mandatory - ESM message container */ + size += ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH + msg->NASmsg.length; + emm_msg->esmmessagecontainer.esmmessagecontainercontents = msg->NASmsg; + + /* Optional - Last visited registered TAI */ + if (msg->UEid.tai) { + size += TRACKING_AREA_IDENTITY_MAXIMUM_LENGTH; + emm_msg->presencemask |= ATTACH_REQUEST_LAST_VISITED_REGISTERED_TAI_PRESENT; + emm_msg->lastvisitedregisteredtai.mccdigit2 = + msg->UEid.tai->plmn.MCCdigit2; + emm_msg->lastvisitedregisteredtai.mccdigit1 = + msg->UEid.tai->plmn.MCCdigit1; + emm_msg->lastvisitedregisteredtai.mncdigit3 = + msg->UEid.tai->plmn.MNCdigit3; + emm_msg->lastvisitedregisteredtai.mccdigit3 = + msg->UEid.tai->plmn.MCCdigit3; + emm_msg->lastvisitedregisteredtai.mncdigit2 = + msg->UEid.tai->plmn.MNCdigit2; + emm_msg->lastvisitedregisteredtai.mncdigit1 = + msg->UEid.tai->plmn.MNCdigit1; + emm_msg->lastvisitedregisteredtai.tac = msg->UEid.tai->tac; + } + + /* Optional - Old GUTI type */ + if (msg->UEid.guti) { + size += GUTI_TYPE_MAXIMUM_LENGTH; + emm_msg->presencemask |= ATTACH_REQUEST_OLD_GUTI_TYPE_PRESENT; + emm_msg->oldgutitype = GUTI_NATIVE; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_attach_complete() ** + ** ** + ** Description: Builds Attach Complete message ** + ** ** + ** The Attach Complete message is sent by the UE to the net- ** + ** work in response to an Attach Accept message. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_attach_complete(const emm_as_data_t* msg, + attach_complete_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Attach Complete message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = ATTACH_COMPLETE; + + /* Mandatory - ESM message container */ + size += ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH + msg->NASmsg.length; + emm_msg->esmmessagecontainer.esmmessagecontainercontents = msg->NASmsg; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_initial_detach_request() ** + ** ** + ** Description: Builds Detach Request message ** + ** ** + ** The Detach Request message is sent by the UE to request ** + ** the release of an EMM context. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_initial_detach_request(const emm_as_establish_t* msg, + detach_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Detach Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = DETACH_REQUEST; + + /* Mandatory - Detach type */ + size += DETACH_TYPE_MAXIMUM_LENGTH; + if (msg->switch_off) { + emm_msg->detachtype.switchoff = DETACH_TYPE_SWITCH_OFF; + } else { + emm_msg->detachtype.switchoff = DETACH_TYPE_NORMAL_DETACH; + } + if (msg->type == EMM_DETACH_TYPE_EPS) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS; + } else if (msg->type == EMM_DETACH_TYPE_IMSI) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_IMSI; + } else if (msg->type == EMM_DETACH_TYPE_EPS_IMSI) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS_IMSI; + } else if (msg->type == EMM_DETACH_TYPE_RESERVED) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_RESERVED_1; + } else { + /* All other values are interpreted as "combined EPS/IMSI detach" */ + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS_IMSI; + } + + /* Mandatory - NAS key set identifier */ + size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH; + if (msg->ksi != EMM_AS_NO_KEY_AVAILABLE) { + emm_msg->naskeysetidentifier.naskeysetidentifier = msg->ksi; + } else { + emm_msg->naskeysetidentifier.naskeysetidentifier = + NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE; + } + + /* Mandatory - EPS mobile identity */ + size += EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH; + if (msg->UEid.guti) { + /* Set GUTI mobile identity */ + GutiEpsMobileIdentity_t* guti = &emm_msg->gutiorimsi.guti; + guti->typeofidentity = EPS_MOBILE_IDENTITY_GUTI; + guti->oddeven = EPS_MOBILE_IDENTITY_EVEN; + guti->mmegroupid = msg->UEid.guti->gummei.MMEgid; + guti->mmecode = msg->UEid.guti->gummei.MMEcode; + guti->mtmsi = msg->UEid.guti->m_tmsi; + guti->mccdigit1 = msg->UEid.guti->gummei.plmn.MCCdigit1; + guti->mccdigit2 = msg->UEid.guti->gummei.plmn.MCCdigit2; + guti->mccdigit3 = msg->UEid.guti->gummei.plmn.MCCdigit3; + guti->mncdigit1 = msg->UEid.guti->gummei.plmn.MNCdigit1; + guti->mncdigit2 = msg->UEid.guti->gummei.plmn.MNCdigit2; + guti->mncdigit3 = msg->UEid.guti->gummei.plmn.MNCdigit3; + } else if (msg->UEid.imsi) { + /* Set IMSI mobile identity */ + ImsiEpsMobileIdentity_t* imsi = &emm_msg->gutiorimsi.imsi; + imsi->typeofidentity = EPS_MOBILE_IDENTITY_IMSI; + imsi->oddeven = msg->UEid.imsi->u.num.parity; + imsi->digit1 = msg->UEid.imsi->u.num.digit1; + imsi->digit2 = msg->UEid.imsi->u.num.digit2; + imsi->digit3 = msg->UEid.imsi->u.num.digit3; + imsi->digit4 = msg->UEid.imsi->u.num.digit4; + imsi->digit5 = msg->UEid.imsi->u.num.digit5; + imsi->digit6 = msg->UEid.imsi->u.num.digit6; + imsi->digit7 = msg->UEid.imsi->u.num.digit7; + imsi->digit8 = msg->UEid.imsi->u.num.digit8; + imsi->digit9 = msg->UEid.imsi->u.num.digit9; + imsi->digit10 = msg->UEid.imsi->u.num.digit10; + imsi->digit11 = msg->UEid.imsi->u.num.digit11; + imsi->digit12 = msg->UEid.imsi->u.num.digit12; + imsi->digit13 = msg->UEid.imsi->u.num.digit13; + imsi->digit14 = msg->UEid.imsi->u.num.digit14; + imsi->digit15 = msg->UEid.imsi->u.num.digit15; + } else if (msg->UEid.imei) { + /* Set IMEI mobile identity */ + ImeiEpsMobileIdentity_t* imei = &emm_msg->gutiorimsi.imei; + imei->typeofidentity = EPS_MOBILE_IDENTITY_IMEI; + imei->oddeven = msg->UEid.imei->u.num.parity; + imei->digit1 = msg->UEid.imei->u.num.digit1; + imei->digit2 = msg->UEid.imei->u.num.digit2; + imei->digit3 = msg->UEid.imei->u.num.digit3; + imei->digit4 = msg->UEid.imei->u.num.digit4; + imei->digit5 = msg->UEid.imei->u.num.digit5; + imei->digit6 = msg->UEid.imei->u.num.digit6; + imei->digit7 = msg->UEid.imei->u.num.digit7; + imei->digit8 = msg->UEid.imei->u.num.digit8; + imei->digit9 = msg->UEid.imei->u.num.digit9; + imei->digit10 = msg->UEid.imei->u.num.digit10; + imei->digit11 = msg->UEid.imei->u.num.digit11; + imei->digit12 = msg->UEid.imei->u.num.digit12; + imei->digit13 = msg->UEid.imei->u.num.digit13; + imei->digit14 = msg->UEid.imei->u.num.digit14; + imei->digit15 = msg->UEid.imei->u.num.digit15; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_detach_request() ** + ** ** + ** Description: Builds Detach Request message ** + ** ** + ** The Detach Request message is sent by the UE to request ** + ** the release of an EMM context. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_detach_request(const emm_as_data_t* msg, + detach_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Detach Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = DETACH_REQUEST; + + /* Mandatory - Detach type */ + size += DETACH_TYPE_MAXIMUM_LENGTH; + if (msg->switch_off) { + emm_msg->detachtype.switchoff = DETACH_TYPE_SWITCH_OFF; + } else { + emm_msg->detachtype.switchoff = DETACH_TYPE_NORMAL_DETACH; + } + if (msg->type == EMM_DETACH_TYPE_EPS) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS; + } else if (msg->type == EMM_DETACH_TYPE_IMSI) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_IMSI; + } else if (msg->type == EMM_DETACH_TYPE_EPS_IMSI) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS_IMSI; + } else if (msg->type == EMM_DETACH_TYPE_RESERVED) { + emm_msg->detachtype.typeofdetach = DETACH_TYPE_RESERVED_1; + } else { + /* All other values are interpreted as "combined EPS/IMSI detach" */ + emm_msg->detachtype.typeofdetach = DETACH_TYPE_EPS_IMSI; + } + + /* Mandatory - NAS key set identifier */ + size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH; + if (msg->sctx.ksi != EMM_AS_NO_KEY_AVAILABLE) { + emm_msg->naskeysetidentifier.naskeysetidentifier = msg->sctx.ksi; + } else { + emm_msg->naskeysetidentifier.naskeysetidentifier = + NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE; + } + + /* Mandatory - EPS mobile identity */ + size += EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH; + if (msg->guti) { + /* Set GUTI mobile identity */ + GutiEpsMobileIdentity_t* guti = &emm_msg->gutiorimsi.guti; + guti->typeofidentity = EPS_MOBILE_IDENTITY_GUTI; + guti->oddeven = EPS_MOBILE_IDENTITY_EVEN; + guti->mmegroupid = msg->guti->gummei.MMEgid; + guti->mmecode = msg->guti->gummei.MMEcode; + guti->mtmsi = msg->guti->m_tmsi; + guti->mccdigit1 = msg->guti->gummei.plmn.MCCdigit1; + guti->mccdigit2 = msg->guti->gummei.plmn.MCCdigit2; + guti->mccdigit3 = msg->guti->gummei.plmn.MCCdigit3; + guti->mncdigit1 = msg->guti->gummei.plmn.MNCdigit1; + guti->mncdigit2 = msg->guti->gummei.plmn.MNCdigit2; + guti->mncdigit3 = msg->guti->gummei.plmn.MNCdigit3; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_initial_tau_request() ** + ** ** + ** Description: Builds Tracking Area Update Request message ** + ** ** + ** The Tracking Area Update Request message is sent by the ** + ** UE to the network to update the registration of the ac- ** + ** tual tracking area of a UE in the network and to periodi- ** + ** cally notify the availability of the UE to the network. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_initial_tau_request(const emm_as_establish_t* msg, + tracking_area_update_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Tracking Area Update Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = TRACKING_AREA_UPDATE_REQUEST; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_initial_sr_request() ** + ** ** + ** Description: Build the Service Request message ** + ** ** + ** The Service Request message is sent by the UE to the ** + ** network to request the establishment of a NAS signalling ** + ** connection and of the radio and S1 bearers. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_initial_sr_request(const emm_as_establish_t* msg, + service_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Service Request message"); + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_initial_extsr_request() ** + ** ** + ** Description: Build the Extended Service Request message ** + ** ** + ** The Extended Service Request message is sent by the UE to ** + ** the network to request the establishment of a NAS signal- ** + ** ling connection and of the radio and S1 bearers for pa- ** + ** cket services, if the UE needs to provide additional in- ** + ** formation that cannot be provided via a SERVICE REQUEST ** + ** message. + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_initial_extsr_request(const emm_as_establish_t* msg, + extended_service_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Extended Service Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = EXTENDED_SERVICE_REQUEST; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_identity_response() ** + ** ** + ** Description: Builds Identity Response message ** + ** ** + ** The Identity Response message is sent by the UE to the ** + ** network in response to an Identity Request message and ** + ** provides the requested identity. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_identity_response(const emm_as_security_t* msg, + identity_response_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Identity Response message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = IDENTITY_RESPONSE; + + /* Mandatory - Mobile identity */ + size += MOBILE_IDENTITY_MAXIMUM_LENGTH; + if (msg->identType == EMM_IDENT_TYPE_IMSI) { + if (msg->imsi) { + ImsiMobileIdentity_t* imsi = &emm_msg->mobileidentity.imsi; + imsi->typeofidentity = MOBILE_IDENTITY_IMSI; + imsi->oddeven = msg->imsi->u.num.parity; + imsi->digit1 = msg->imsi->u.num.digit1; + imsi->digit2 = msg->imsi->u.num.digit2; + imsi->digit3 = msg->imsi->u.num.digit3; + imsi->digit4 = msg->imsi->u.num.digit4; + imsi->digit5 = msg->imsi->u.num.digit5; + imsi->digit6 = msg->imsi->u.num.digit6; + imsi->digit7 = msg->imsi->u.num.digit7; + imsi->digit8 = msg->imsi->u.num.digit8; + imsi->digit9 = msg->imsi->u.num.digit9; + imsi->digit10 = msg->imsi->u.num.digit10; + imsi->digit11 = msg->imsi->u.num.digit11; + imsi->digit12 = msg->imsi->u.num.digit12; + imsi->digit13 = msg->imsi->u.num.digit13; + imsi->digit14 = msg->imsi->u.num.digit14; + imsi->digit15 = msg->imsi->u.num.digit15; + } + } else if (msg->identType == EMM_IDENT_TYPE_TMSI) { + if (msg->tmsi) { + const char *p_tmsi = (char*)(&msg->tmsi); + TmsiMobileIdentity_t* tmsi = &emm_msg->mobileidentity.tmsi; + tmsi->typeofidentity = MOBILE_IDENTITY_TMSI; + tmsi->oddeven = MOBILE_IDENTITY_EVEN; + tmsi->digit1 = 0xf; + tmsi->digit2 = (*p_tmsi & 0xf); + tmsi->digit3 = ((*p_tmsi >> 4) & 0xf); + p_tmsi++; + tmsi->digit4 = (*p_tmsi & 0xf); + tmsi->digit5 = ((*p_tmsi >> 4) & 0xf); + p_tmsi++; + tmsi->digit6 = (*p_tmsi & 0xf); + tmsi->digit7 = ((*p_tmsi >> 4) & 0xf); + p_tmsi++; + tmsi->digit8 = (*p_tmsi & 0xf); + tmsi->digit9 = ((*p_tmsi >> 4) & 0xf); + } + } else if (msg->identType == EMM_IDENT_TYPE_IMEI) { + if (msg->imei) { + ImeiMobileIdentity_t* imei = &emm_msg->mobileidentity.imei; + imei->typeofidentity = MOBILE_IDENTITY_IMEI; + imei->oddeven = msg->imei->u.num.parity; + imei->digit1 = msg->imei->u.num.digit1; + imei->digit2 = msg->imei->u.num.digit2; + imei->digit3 = msg->imei->u.num.digit3; + imei->digit4 = msg->imei->u.num.digit4; + imei->digit5 = msg->imei->u.num.digit5; + imei->digit6 = msg->imei->u.num.digit6; + imei->digit7 = msg->imei->u.num.digit7; + imei->digit8 = msg->imei->u.num.digit8; + imei->digit9 = msg->imei->u.num.digit9; + imei->digit10 = msg->imei->u.num.digit10; + imei->digit11 = msg->imei->u.num.digit11; + imei->digit12 = msg->imei->u.num.digit12; + imei->digit13 = msg->imei->u.num.digit13; + imei->digit14 = msg->imei->u.num.digit14; + imei->digit15 = msg->imei->u.num.digit15; + } + } else if (msg->identType == EMM_IDENT_TYPE_NOT_AVAILABLE) { + NoMobileIdentity_t* no_id = &emm_msg->mobileidentity.no_id; + no_id->typeofidentity = MOBILE_IDENTITY_NOT_AVAILABLE; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_authentication_response() ** + ** ** + ** Description: Builds Authentication Response message ** + ** ** + ** The Authentication Response message is sent by the UE to ** + ** the network to deliver a calculated authentication res- ** + ** ponse to the network. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_authentication_response(const emm_as_security_t* msg, + authentication_response_msg* emm_msg) +{ + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Authentication Response message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = AUTHENTICATION_RESPONSE; + + /* Mandatory - Authentication response parameter */ + size += AUTHENTICATION_RESPONSE_PARAMETER_MAXIMUM_LENGTH; + emm_msg->authenticationresponseparameter.res = *msg->res; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_authentication_failure() ** + ** ** + ** Description: Builds Authentication Failure message ** + ** ** + ** The Authentication Failure message is sent by the UE to ** + ** the network to indicate that authentication of the net- ** + ** work has failed ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_authentication_failure(const emm_as_security_t* msg, + authentication_failure_msg* emm_msg) +{ + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Authentication Failure message (cause=%d)", + msg->emm_cause); + + /* Mandatory - Message type */ + emm_msg->messagetype = AUTHENTICATION_FAILURE; + + /* Mandatory - EMM cause */ + size += EMM_CAUSE_MAXIMUM_LENGTH; + emm_msg->emmcause = msg->emm_cause; + + /* Optional - Authentication response parameter */ + if (msg->auts && msg->auts->length > 0) { + size += AUTHENTICATION_RESPONSE_PARAMETER_MAXIMUM_LENGTH; + emm_msg->presencemask |= AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT; + emm_msg->authenticationfailureparameter.auts = *msg->auts; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_security_mode_complete() ** + ** ** + ** Description: Builds Security Mode Complete message ** + ** ** + ** The Security Mode Complete message is sent by the UE to ** + ** the network in response to a Security Mode Command mes- ** + ** sage. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_security_mode_complete(const emm_as_security_t* msg, + security_mode_complete_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Security Mode Complete message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = SECURITY_MODE_COMPLETE; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_security_mode_reject() ** + ** ** + ** Description: Builds Security Mode Reject message ** + ** ** + ** The Security Mode Reject message is sent by the UE to the ** + ** network to indicate that the corresponding security mode ** + ** command has been rejected. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_security_mode_reject(const emm_as_security_t* msg, + security_mode_reject_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Security Mode Reject message (cause=%d)", + msg->emm_cause); + + /* Mandatory - Message type */ + emm_msg->messagetype = SECURITY_MODE_REJECT; + + /* Mandatory - EMM cause */ + size += EMM_CAUSE_MAXIMUM_LENGTH; + emm_msg->emmcause = msg->emm_cause; + + LOG_FUNC_RETURN (size); +} + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME to send EMM messages to the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: emm_send_attach_accept() ** + ** ** + ** Description: Builds Attach Accept message ** + ** ** + ** The Attach Accept message is sent by the network to the ** + ** UE to indicate that the corresponding attach request has ** + ** been accepted. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_attach_accept(const emm_as_establish_t* msg, + attach_accept_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Attach Accept message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = ATTACH_ACCEPT; + + /* Mandatory - EPS attach result */ + size += EPS_ATTACH_RESULT_MAXIMUM_LENGTH; + emm_msg->epsattachresult = EPS_ATTACH_RESULT_EPS; + + /* Mandatory - T3412 value */ + size += GPRS_TIMER_MAXIMUM_LENGTH; + emm_msg->t3412value.unit = GPRS_TIMER_UNIT_0S; + + /* Mandatory - Tracking area identity list */ + size += TRACKING_AREA_IDENTITY_LIST_MINIMUM_LENGTH; + emm_msg->tailist.typeoflist = + TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS; + emm_msg->tailist.numberofelements = msg->n_tacs; + emm_msg->tailist.mccdigit1 = msg->UEid.guti->gummei.plmn.MCCdigit1; + emm_msg->tailist.mccdigit2 = msg->UEid.guti->gummei.plmn.MCCdigit2; + emm_msg->tailist.mccdigit3 = msg->UEid.guti->gummei.plmn.MCCdigit3; + emm_msg->tailist.mncdigit1 = msg->UEid.guti->gummei.plmn.MNCdigit1; + emm_msg->tailist.mncdigit2 = msg->UEid.guti->gummei.plmn.MNCdigit2; + emm_msg->tailist.mncdigit3 = msg->UEid.guti->gummei.plmn.MNCdigit3; + emm_msg->tailist.tac = msg->tac; + + /* Mandatory - ESM message container */ + size += ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH + msg->NASmsg.length; + emm_msg->esmmessagecontainer.esmmessagecontainercontents = msg->NASmsg; + + /* Optional - GUTI */ + if (msg->new_guti) { + size += EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH; + emm_msg->presencemask |= ATTACH_ACCEPT_GUTI_PRESENT; + emm_msg->guti.guti.typeofidentity = EPS_MOBILE_IDENTITY_GUTI; + emm_msg->guti.guti.oddeven = EPS_MOBILE_IDENTITY_EVEN; + emm_msg->guti.guti.mmegroupid = msg->new_guti->gummei.MMEgid; + emm_msg->guti.guti.mmecode = msg->new_guti->gummei.MMEcode; + emm_msg->guti.guti.mtmsi = msg->new_guti->m_tmsi; + emm_msg->guti.guti.mccdigit1 = msg->new_guti->gummei.plmn.MCCdigit1; + emm_msg->guti.guti.mccdigit2 = msg->new_guti->gummei.plmn.MCCdigit2; + emm_msg->guti.guti.mccdigit3 = msg->new_guti->gummei.plmn.MCCdigit3; + emm_msg->guti.guti.mncdigit1 = msg->new_guti->gummei.plmn.MNCdigit1; + emm_msg->guti.guti.mncdigit2 = msg->new_guti->gummei.plmn.MNCdigit2; + emm_msg->guti.guti.mncdigit3 = msg->new_guti->gummei.plmn.MNCdigit3; + } + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_attach_reject() ** + ** ** + ** Description: Builds Attach Reject message ** + ** ** + ** The Attach Reject message is sent by the network to the ** + ** UE to indicate that the corresponding attach request has ** + ** been rejected. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_attach_reject(const emm_as_establish_t* msg, + attach_reject_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Attach Reject message (cause=%d)", + msg->emm_cause); + + /* Mandatory - Message type */ + emm_msg->messagetype = ATTACH_REJECT; + + /* Mandatory - EMM cause */ + size += EMM_CAUSE_MAXIMUM_LENGTH; + emm_msg->emmcause = msg->emm_cause; + + /* Optional - ESM message container */ + if (msg->NASmsg.length > 0) { + size += ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH + msg->NASmsg.length; + emm_msg->presencemask |= ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT; + emm_msg->esmmessagecontainer.esmmessagecontainercontents = msg->NASmsg; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_identity_request() ** + ** ** + ** Description: Builds Identity Request message ** + ** ** + ** The Identity Request message is sent by the network to ** + ** the UE to request the UE to provide the specified identi- ** + ** ty. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_identity_request(const emm_as_security_t* msg, + identity_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Identity Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = IDENTITY_REQUEST; + + /* Mandatory - Identity type 2 */ + size += IDENTITY_TYPE_2_MAXIMUM_LENGTH; + if (msg->identType == EMM_IDENT_TYPE_IMSI) { + emm_msg->identitytype = IDENTITY_TYPE_2_IMSI; + } else if (msg->identType == EMM_IDENT_TYPE_TMSI) { + emm_msg->identitytype = IDENTITY_TYPE_2_TMSI; + } else if (msg->identType == EMM_IDENT_TYPE_IMEI) { + emm_msg->identitytype = IDENTITY_TYPE_2_IMEI; + } else { + /* All other values are interpreted as "IMSI" */ + emm_msg->identitytype = IDENTITY_TYPE_2_IMSI; + } + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_authentication_request() ** + ** ** + ** Description: Builds Authentication Request message ** + ** ** + ** The Authentication Request message is sent by the network ** + ** to the UE to initiate authentication of the UE identity. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_authentication_request(const emm_as_security_t* msg, + authentication_request_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Authentication Request message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = AUTHENTICATION_REQUEST; + + /* Mandatory - NAS key set identifier */ + size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH; + emm_msg->naskeysetidentifierasme.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE; + emm_msg->naskeysetidentifierasme.naskeysetidentifier = msg->ksi; + + /* Mandatory - Authentication parameter RAND */ + size += AUTHENTICATION_PARAMETER_RAND_MAXIMUM_LENGTH; + emm_msg->authenticationparameterrand.rand = *msg->rand; + + /* Mandatory - Authentication parameter AUTN */ + size += AUTHENTICATION_PARAMETER_AUTN_MAXIMUM_LENGTH; + emm_msg->authenticationparameterautn.autn = *msg->autn; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_authentication_reject() ** + ** ** + ** Description: Builds Authentication Reject message ** + ** ** + ** The Authentication Reject message is sent by the network ** + ** to the UE to indicate that the authentication procedure ** + ** has failed and that the UE shall abort all activities. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_authentication_reject(authentication_reject_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Authentication Reject message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = AUTHENTICATION_REJECT; + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: emm_send_security_mode_command() ** + ** ** + ** Description: Builds Security Mode Command message ** + ** ** + ** The Security Mode Command message is sent by the network ** + ** to the UE to establish NAS signalling security. ** + ** ** + ** Inputs: msg: The EMMAS-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: emm_msg: The EMM message to be sent ** + ** Return: The size of the EMM message ** + ** Others: None ** + ** ** + ***************************************************************************/ +int emm_send_security_mode_command(const emm_as_security_t* msg, + security_mode_command_msg* emm_msg) +{ + LOG_FUNC_IN; + + int size = EMM_HEADER_MAXIMUM_LENGTH; + + LOG_TRACE(INFO, "EMMAS-SAP - Send Security Mode Command message"); + + /* Mandatory - Message type */ + emm_msg->messagetype = SECURITY_MODE_COMMAND; + + /* Selected NAS security algorithms */ + size += NAS_SECURITY_ALGORITHMS_MAXIMUM_LENGTH; + emm_msg->selectednassecurityalgorithms.typeofcipheringalgorithm = + NAS_SECURITY_ALGORITHMS_EEA0; + emm_msg->selectednassecurityalgorithms.typeofintegrityalgorithm = + NAS_SECURITY_ALGORITHMS_EIA0; + + /* NAS key set identifier */ + size += NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH; + emm_msg->naskeysetidentifier.tsc = NAS_KEY_SET_IDENTIFIER_NATIVE; + emm_msg->naskeysetidentifier.naskeysetidentifier = msg->ksi; + + /* Replayed UE security capabilities */ + size += UE_SECURITY_CAPABILITY_MAXIMUM_LENGTH; + emm_msg->replayeduesecuritycapabilities.eea = msg->eea; + emm_msg->replayeduesecuritycapabilities.eia = msg->eia; + emm_msg->replayeduesecuritycapabilities.uea = 0x00; + emm_msg->replayeduesecuritycapabilities.uia = 0x00; + emm_msg->replayeduesecuritycapabilities.gea = 0x00; + + LOG_FUNC_RETURN (size); +} + +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.h b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.h new file mode 100644 index 0000000000..7b4f263b7e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/emm/sap/emm_send.h @@ -0,0 +1,130 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source emm_send.h + +Version 0.1 + +Date 2013/01/30 + +Product NAS stack + +Subsystem EPS Mobility Management + +Author Frederic Maurel + +Description Defines functions executed at the EMMAS Service Access + Point to send EPS Mobility Management messages to the + Access Stratum sublayer. + +*****************************************************************************/ +#ifndef __EMM_SEND_H__ +#define __EMM_SEND_H__ + +#include "EmmStatus.h" + +#include "DetachRequest.h" +#include "DetachAccept.h" + +#ifdef NAS_UE +#include "AttachRequest.h" +#include "AttachComplete.h" +#include "TrackingAreaUpdateRequest.h" +#include "TrackingAreaUpdateComplete.h" +#include "ServiceRequest.h" +#include "ExtendedServiceRequest.h" +#include "GutiReallocationComplete.h" +#include "AuthenticationResponse.h" +#include "AuthenticationFailure.h" +#include "IdentityResponse.h" +#include "SecurityModeComplete.h" +#include "SecurityModeReject.h" +#include "UplinkNasTransport.h" +#endif + +#ifdef NAS_MME +#include "AttachAccept.h" +#include "AttachReject.h" +#include "TrackingAreaUpdateAccept.h" +#include "TrackingAreaUpdateReject.h" +#include "ServiceReject.h" +#include "GutiReallocationCommand.h" +#include "AuthenticationRequest.h" +#include "AuthenticationReject.h" +#include "IdentityRequest.h" +#include "SecurityModeCommand.h" +#include "EmmInformation.h" +#include "DownlinkNasTransport.h" +#include "CsServiceNotification.h" +#endif + +#include "emm_asDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME to send EMM messages + * -------------------------------------------------------------------------- + */ +int emm_send_status(const emm_as_status_t*, emm_status_msg*); + +int emm_send_detach_accept(const emm_as_data_t*, detach_accept_msg*); + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE to send EMM messages to the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int emm_send_attach_request(const emm_as_establish_t*, attach_request_msg*); +int emm_send_attach_complete(const emm_as_data_t*, attach_complete_msg*); + +int emm_send_initial_detach_request(const emm_as_establish_t*, detach_request_msg*); +int emm_send_detach_request(const emm_as_data_t*, detach_request_msg*); + + +int emm_send_initial_tau_request(const emm_as_establish_t*, tracking_area_update_request_msg*); + +int emm_send_initial_sr_request(const emm_as_establish_t*, service_request_msg*); + +int emm_send_initial_extsr_request(const emm_as_establish_t*, extended_service_request_msg*); + +int emm_send_identity_response(const emm_as_security_t*, identity_response_msg*); +int emm_send_authentication_response(const emm_as_security_t*, authentication_response_msg*); +int emm_send_authentication_failure(const emm_as_security_t*, authentication_failure_msg*); +int emm_send_security_mode_complete(const emm_as_security_t*, security_mode_complete_msg*); +int emm_send_security_mode_reject(const emm_as_security_t*, security_mode_reject_msg*); +#endif + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME to send EMM messages to the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +int emm_send_attach_accept(const emm_as_establish_t*, attach_accept_msg*); +int emm_send_attach_reject(const emm_as_establish_t*, attach_reject_msg*); + +int emm_send_identity_request(const emm_as_security_t*, identity_request_msg*); +int emm_send_authentication_request(const emm_as_security_t*, authentication_request_msg*); +int emm_send_authentication_reject(authentication_reject_msg*); +int emm_send_security_mode_command(const emm_as_security_t*, security_mode_command_msg*); +#endif + +#endif /* __EMM_SEND_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/DedicatedEpsBearerContextActivation.c b/openair-cn/NAS/EURECOM-NAS/src/esm/DedicatedEpsBearerContextActivation.c new file mode 100644 index 0000000000..39902ebe16 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/DedicatedEpsBearerContextActivation.c @@ -0,0 +1,635 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source DedicatedEpsBearerContextActivation.c + +Version 0.1 + +Date 2013/07/16 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the dedicated EPS bearer context activation ESM + procedure executed by the Non-Access Stratum. + + The purpose of the dedicated EPS bearer context activation + procedure is to establish an EPS bearer context with specific + QoS and TFT between the UE and the EPC. + + The procedure is initiated by the network, but may be requested + by the UE by means of the UE requested bearer resource alloca- + tion procedure or the UE requested bearer resource modification + procedure. + It can be part of the attach procedure or be initiated together + with the default EPS bearer context activation procedure when + the UE initiated stand-alone PDN connectivity procedure. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esm_cause.h" +#include "esm_ebr.h" +#include "esm_ebr_context.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the dedicated EPS bearer context activation + * procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _dedicated_eps_bearer_activate_t3485_handler(void*); + +/* Maximum value of the activate dedicated EPS bearer context request + * retransmission counter */ +#define DEDICATED_EPS_BEARER_ACTIVATE_COUNTER_MAX 5 + +static int _dedicated_eps_bearer_activate(unsigned int ueid, int ebi, + const OctetString* msg); +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Dedicated EPS bearer context activation procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context() ** + ** ** + ** Description: Allocates resources required for activation of a dedica- ** + ** ted EPS bearer context. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pid: PDN connection identifier ** + ** esm_qos: EPS bearer level QoS parameters ** + ** tft: Traffic flow template parameters ** + ** Others: None ** + ** ** + ** Outputs: ebi: EPS bearer identity assigned to the new ** + ** dedicated bearer context ** + ** default_ebi: EPS bearer identity of the associated de- ** + ** fault EPS bearer context ** + ** esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context(unsigned int ueid, int pid, + unsigned int* ebi, + unsigned int* default_ebi, + const esm_proc_qos_t* qos, + const esm_proc_tft_t* tft, + int* esm_cause) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "ESM-PROC - Dedicated EPS bearer context activation " + "(ueid=%u, pid=%d)", ueid, pid); + + /* Assign new EPS bearer context */ + *ebi = esm_ebr_assign(ueid, ESM_EBI_UNASSIGNED); + + if (*ebi != ESM_EBI_UNASSIGNED) { + /* Create dedicated EPS bearer context */ + *default_ebi = esm_ebr_context_create(ueid, pid, *ebi, FALSE, qos, tft); + if (*default_ebi == ESM_EBI_UNASSIGNED) { + /* No resource available */ + LOG_TRACE(WARNING, "ESM-PROC - Failed to create dedicated EPS " + "bearer context (ebi=%d)", *ebi); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + LOG_FUNC_RETURN (RETURNerror); + } + LOG_FUNC_RETURN (RETURNok); + } + + LOG_TRACE(WARNING, "ESM-PROC - Failed to assign new EPS bearer context"); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_request() ** + ** ** + ** Description: Initiates the dedicated EPS bearer context activation pro-** + ** cedure ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.2 ** + ** The MME initiates the dedicated EPS bearer context activa-** + ** tion procedure by sending an ACTIVATE DEDICATED EPS BEA- ** + ** RER CONTEXT REQUEST message, starting timer T3485 and en- ** + ** tering state BEARER CONTEXT ACTIVE PENDING. ** + ** ** + ** Inputs: is_standalone: Not used (always TRUE) ** + ** ueid: UE lower layer identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_request(int is_standalone, + unsigned int ueid, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO,"ESM-PROC - Initiate dedicated EPS bearer context " + "activation (ueid=%d, ebi=%d)", ueid, ebi); + + /* Send activate dedicated EPS bearer context request message and + * start timer T3485 */ + rc = _dedicated_eps_bearer_activate(ueid, ebi, msg); + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE PENDING */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_ACTIVE_PENDING, ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE PENDING state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE PENDING", + ebi); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_accept() ** + ** ** + ** Description: Performs dedicated EPS bearer context activation procedu- ** + ** re accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.3 ** + ** Upon receipt of the ACTIVATE DEDICATED EPS BEARER CONTEXT ** + ** ACCEPT message, the MME shall stop the timer T3485 and ** + ** enter the state BEARER CONTEXT ACTIVE. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_accept(unsigned int ueid, int ebi, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "ESM-PROC - Dedicated EPS bearer context activation " + "accepted by the UE (ueid=%u, ebi=%d)", ueid, ebi); + + /* Stop T3485 timer */ + rc = esm_ebr_stop_timer(ueid, ebi); + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_ACTIVE, FALSE); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE", ebi); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_reject() ** + ** ** + ** Description: Performs dedicated EPS bearer context activation procedu- ** + ** re not accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.4 ** + ** Upon receipt of the ACTIVATE DEDICATED EPS BEARER CONTEXT ** + ** REJECT message, the MME shall stop the timer T3485, enter ** + ** the state BEARER CONTEXT INACTIVE and abort the dedicated ** + ** EPS bearer context activation procedure. ** + ** The MME also requests the lower layer to release the ra- ** + ** dio resources that were established during the dedicated ** + ** EPS bearer context activation. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_reject(unsigned int ueid, int ebi, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "ESM-PROC - Dedicated EPS bearer context activation " + "not accepted by the UE (ueid=%u, ebi=%d)", ueid, ebi); + + /* Stop T3485 timer if running */ + rc = esm_ebr_stop_timer(ueid, ebi); + if (rc != RETURNerror) { + int pid, bid; + /* Release the dedicated EPS bearer context and enter state INACTIVE */ + rc = esm_proc_eps_bearer_context_deactivate(ueid, TRUE, ebi, + &pid, &bid, NULL); + if (rc != RETURNok) { + /* Failed to release the dedicated EPS bearer context */ + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME + +/* + * -------------------------------------------------------------------------- + * Dedicated EPS bearer context activation procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_request() ** + ** ** + ** Description: Creates local dedicated EPS bearer context upon receipt ** + ** of the ACTIVATE DEDICATED EPS BEARER CONTEXT REQUEST ** + ** message. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** default_ebi: EPS bearer identity of the associated de- ** + ** fault EPS bearer context ** + ** esm_qos: EPS bearer level QoS parameters ** + ** tft: Traffic flow template parameters ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_request(int ebi, int default_ebi, + const esm_proc_qos_t* qos, + const esm_proc_tft_t* tft, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - Dedicated EPS bearer context activation " + "requested by the network (ebi=%d)", ebi); + + /* Get the PDN connection the dedicated EPS bearer is linked to */ + int pid = esm_ebr_context_get_pid(default_ebi); + if (pid < 0) { + /* 3GPP TS 24.301, section 6.4.2.5, abnormal case c + * No default EPS bearer context with linked EPS bearer identity + * activated + */ + LOG_TRACE(WARNING, "ESM-PROC - Failed to get PDN connection the " + "dedicated EPS bearer is linked to (ebi=%d)", default_ebi); + *esm_cause = ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY; + LOG_FUNC_RETURN (RETURNerror); + } + + /* Assign dedicated EPS bearer context */ + int new_ebi = esm_ebr_assign(ebi, pid+1, FALSE); + if (new_ebi == ESM_EBI_UNASSIGNED) { + /* 3GPP TS 24.301, section 6.4.2.5, abnormal cases a and b + * Dedicated EPS bearer context activation request for an already + * activated default or dedicated EPS bearer context + */ + int old_pid, old_bid; + /* Locally deactivate the existing EPS bearer context and proceed + * with the requested dedicated EPS bearer context activation */ + rc = esm_proc_eps_bearer_context_deactivate(TRUE, ebi, + &old_pid, &old_bid); + if (rc != RETURNok) { + /* Failed to release EPS bearer context */ + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else { + /* Assign new dedicated EPS bearer context */ + ebi = esm_ebr_assign(ebi, pid+1, FALSE); + } + } + + if (ebi != ESM_EBI_UNASSIGNED) { + /* Check syntactical errors in packet filters */ + rc = esm_ebr_context_check_tft(pid, ebi, tft, + ESM_EBR_CONTEXT_TFT_CREATE); + if (rc != RETURNok) { + /* Syntactical errors in packet filters */ + LOG_TRACE(WARNING, "ESM-PROC - Syntactical errors in packet " + "filters"); + *esm_cause = ESM_CAUSE_SYNTACTICAL_ERROR_IN_PACKET_FILTER; + } + else { + /* Create new dedicated EPS bearer context */ + default_ebi = esm_ebr_context_create(pid, ebi, FALSE, qos, tft); + if (default_ebi != ESM_EBI_UNASSIGNED) { + /* Dedicated EPS bearer contextx successfully created */ + rc = RETURNok; + } + else { + /* No resource available */ + LOG_TRACE(WARNING, "ESM-PROC - Failed to create new dedicated " + "EPS bearer context"); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_accept() ** + ** ** + ** Description: Performs dedicated EPS bearer context activation proce- ** + ** dure accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.3 ** + ** The UE accepts dedicated EPS bearer context activation by ** + ** sending ACTIVATE DEDICATED EPS BEARER CONTEXT ACCEPT mes- ** + ** sage and entering the state BEARER CONTEXT ACTIVE. ** + ** ** + ** Inputs: is_standalone: Not used ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_accept(int is_standalone, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO,"ESM-PROC - Dedicated EPS bearer context activation " + "accepted by the UE (ebi=%d)", ebi); + + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE */ + rc = esm_ebr_set_status(ebi, ESM_EBR_ACTIVE, ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE", ebi); + /* Accept network retransmission of already accepted activate + * dedicated EPS bearer context request */ + LOG_FUNC_RETURN (RETURNok); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_dedicated_eps_bearer_context_reject() ** + ** ** + ** Description: Performs dedicated EPS bearer context activation proce- ** + ** dure not accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.4 ** + ** The UE rejects dedicated EPS bearer context activation by ** + ** sending ACTIVATE DEDICATED EPS BEARER CONTEXT REJECT mes- ** + ** sage. ** + ** ** + ** Inputs: is_standalone: Not used ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_dedicated_eps_bearer_context_reject(int is_standalone, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(WARNING, "ESM-PROC - Dedicated EPS bearer context activation " + "not accepted by the UE (ebi=%d)", ebi); + + if ( !esm_ebr_is_not_in_use(ebi) ) { + /* Release EPS bearer data currently in use */ + rc = esm_ebr_release(ebi); + } + + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer data"); + } + else { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _dedicated_eps_bearer_activate_t3485_handler() ** + ** ** + ** Description: T3485 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 6.4.2.6, case a ** + ** On the first expiry of the timer T3485, the MME shall re- ** + ** send the ACTIVATE DEDICATED EPS BEARER CONTEXT REQUEST ** + ** and shall reset and restart timer T3485. This retransmis- ** + ** sion is repeated four times, i.e. on the fifth expiry of ** + ** timer T3485, the MME shall abort the procedure, release ** + ** any resources allocated for this activation and enter the ** + ** state BEARER CONTEXT INACTIVE. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _dedicated_eps_bearer_activate_t3485_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Get retransmission timer parameters data */ + esm_ebr_timer_data_t* data = (esm_ebr_timer_data_t*)(args); + + /* Increment the retransmission counter */ + data->count += 1; + + LOG_TRACE(WARNING, "ESM-PROC - T3485 timer expired (ueid=%d, ebi=%d), " + "retransmission counter = %d", + data->ueid, data->ebi, data->count); + + if (data->count < DEDICATED_EPS_BEARER_ACTIVATE_COUNTER_MAX) { + /* Re-send activate dedicated EPS bearer context request message + * to the UE */ + rc = _dedicated_eps_bearer_activate(data->ueid, data->ebi, &data->msg); + } + else { + /* + * The maximum number of activate dedicated EPS bearer context request + * message retransmission has exceed + */ + int pid, bid; + /* Release the dedicated EPS bearer context and enter state INACTIVE */ + rc = esm_proc_eps_bearer_context_deactivate(data->ueid, TRUE, + data->ebi, &pid, &bid, + NULL); + if (rc != RETURNerror) { + /* Stop timer T3485 */ + rc = esm_ebr_stop_timer(data->ueid, data->ebi); + } + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _dedicated_eps_bearer_activate() ** + ** ** + ** Description: Sends ACTIVATE DEDICATED EPS BEREAR CONTEXT REQUEST mes- ** + ** sage and starts timer T3485 ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3485 ** + ** ** + ***************************************************************************/ +static int _dedicated_eps_bearer_activate(unsigned int ueid, int ebi, + const OctetString* msg) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify EMM that an activate dedicated EPS bearer context request + * message has to be sent to the UE + */ + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = ueid; + emm_esm->msg = *msg; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3485 retransmission timer */ + rc = esm_ebr_start_timer(ueid, ebi, msg, T3485_DEFAULT_VALUE, + _dedicated_eps_bearer_activate_t3485_handler); + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/DefaultEpsBearerContextActivation.c b/openair-cn/NAS/EURECOM-NAS/src/esm/DefaultEpsBearerContextActivation.c new file mode 100644 index 0000000000..50f9f684ec --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/DefaultEpsBearerContextActivation.c @@ -0,0 +1,757 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source DefaultEpsBearerContextActivation.c + +Version 0.1 + +Date 2013/01/28 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the default EPS bearer context activation ESM + procedure executed by the Non-Access Stratum. + + The purpose of the default bearer context activation procedure + is to establish a default EPS bearer context between the UE + and the EPC. + + The procedure is initiated by the network as a response to + the PDN CONNECTIVITY REQUEST message received from the UE. + It can be part of the attach procedure. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esm_cause.h" +#include "esm_ebr.h" +#include "esm_ebr_context.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the default EPS bearer context activation + * procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +static struct { + int ebi; /* EPS bearer identity of the default EPS bearer associated + * to the PDN connection to be activated */ +} _default_eps_bearer_context_data = {ESM_EBI_UNASSIGNED}; + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the default EPS bearer context activation + * procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _default_eps_bearer_activate_t3485_handler(void*); + +/* Maximum value of the activate default EPS bearer context request + * retransmission counter */ +#define DEFAULT_EPS_BEARER_ACTIVATE_COUNTER_MAX 5 + +static int _default_eps_bearer_activate(unsigned int ueid, int ebi, + const OctetString* msg); +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Default EPS bearer context activation procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context() ** + ** ** + ** Description: Allocates resources required for activation of a default ** + ** EPS bearer context. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pid: PDN connection identifier ** + ** qos: EPS bearer level QoS parameters ** + ** Others: None ** + ** ** + ** Outputs: ebi: EPS bearer identity assigned to the de- ** + ** fault EPS bearer context ** + ** esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context(unsigned int ueid, int pid, + unsigned int* ebi, + const esm_proc_qos_t* qos, + int* esm_cause) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "ESM-PROC - Default EPS bearer context activation " + "(ueid=%u, pid=%d)", ueid, pid); + + /* Assign new EPS bearer context */ + *ebi = esm_ebr_assign(ueid, ESM_EBI_UNASSIGNED); + + if (*ebi != ESM_EBI_UNASSIGNED) { + /* Create default EPS bearer context */ + *ebi = esm_ebr_context_create(ueid, pid, *ebi, TRUE, qos, NULL); + if (*ebi == ESM_EBI_UNASSIGNED) { + /* No resource available */ + LOG_TRACE(WARNING, "ESM-PROC - Failed to create new default EPS " + "bearer context (ebi=%d)", *ebi); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + LOG_FUNC_RETURN (RETURNerror); + } + LOG_FUNC_RETURN (RETURNok); + } + + LOG_TRACE(WARNING, "ESM-PROC - Failed to assign new EPS bearer context"); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_request() ** + ** ** + ** Description: Initiates the default EPS bearer context activation pro- ** + ** cedure ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.2 ** + ** The MME initiates the default EPS bearer context activa- ** + ** tion procedure by sending an ACTIVATE DEFAULT EPS BEARER ** + ** CONTEXT REQUEST message, starting timer T3485 and ente- ** + ** ring state BEARER CONTEXT ACTIVE PENDING. ** + ** ** + ** Inputs: is_standalone: Indicate whether the default bearer is ** + ** activated as part of the attach procedure ** + ** or as the response to a stand-alone PDN ** + ** CONNECTIVITY REQUEST message ** + ** ueid: UE lower layer identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_request(int is_standalone, + unsigned int ueid, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO,"ESM-PROC - Initiate default EPS bearer context activation " + "(ueid=%d, ebi=%d)", ueid, ebi); + + if (is_standalone) { + /* Send activate default EPS bearer context request message and + * start timer T3485 */ + rc = _default_eps_bearer_activate(ueid, ebi, msg); + } + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE PENDING */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_ACTIVE_PENDING, ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE PENDING state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE PENDING", + ebi); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_accept() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.3 ** + ** Upon receipt of the ACTIVATE DEFAULT EPS BEARER CONTEXT ** + ** ACCEPT message, the MME shall enter the state BEARER CON- ** + ** TEXT ACTIVE and stop the timer T3485, if it is running. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_accept(unsigned int ueid, int ebi, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO, "ESM-PROC - Default EPS bearer context activation " + "accepted by the UE (ueid=%u, ebi=%d)", ueid, ebi); + + /* Stop T3485 timer if running */ + rc = esm_ebr_stop_timer(ueid, ebi); + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_ACTIVE, FALSE); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE", ebi); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_reject() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** not accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.4 ** + ** Upon receipt of the ACTIVATE DEFAULT EPS BEARER CONTEXT ** + ** REJECT message, the MME shall enter the state BEARER CON- ** + ** TEXT INACTIVE and stop the timer T3485, if it is running. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_reject(unsigned int ueid, int ebi, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "ESM-PROC - Default EPS bearer context activation " + "not accepted by the UE (ueid=%u, ebi=%d)", ueid, ebi); + + /* Stop T3485 timer if running */ + rc = esm_ebr_stop_timer(ueid, ebi); + if (rc != RETURNerror) { + int pid, bid; + /* Release the default EPS bearer context and enter state INACTIVE */ + rc = esm_proc_eps_bearer_context_deactivate(ueid, TRUE, ebi, + &pid, &bid, NULL); + if (rc != RETURNok) { + /* Failed to release the default EPS bearer context */ + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_failure() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** upon receiving notification from the EPS Mobility Manage- ** + ** ment sublayer that EMM procedure that initiated EPS de- ** + ** fault bearer context activation locally failed. ** + ** ** + ** The MME releases the default EPS bearer context previous- ** + ** ly allocated when ACTIVATE DEFAULT EPS BEARER CONTEXT RE- ** + ** QUEST message was received. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection the ** + ** default EPS bearer context belongs to if ** + ** successfully released; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_failure(unsigned int ueid) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int pid; + + LOG_TRACE(WARNING, "ESM-PROC - Default EPS bearer context activation " + "failure (ueid=%u)", ueid); + + /* Get the EPS bearer identity of the EPS bearer context which is still + * pending in the active pending state */ + int ebi = esm_ebr_get_pending_ebi(ueid, ESM_EBR_ACTIVE_PENDING); + if (ebi != ESM_EBI_UNASSIGNED) { + int bid; + /* Release the default EPS bearer context and enter state INACTIVE */ + rc = esm_proc_eps_bearer_context_deactivate(ueid, TRUE, ebi, + &pid, &bid, NULL); + } + + if (rc != RETURNerror) { + LOG_FUNC_RETURN (pid); + } + LOG_FUNC_RETURN (RETURNerror); +} + +#endif // NAS_MME + +/* + * -------------------------------------------------------------------------- + * Default EPS bearer context activation procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_request() ** + ** ** + ** Description: Creates local default EPS bearer context upon receipt of ** + ** the ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST message. ** + ** ** + ** Inputs: pid: PDN connection identifier ** + ** ebi: EPS bearer identity ** + ** qos: EPS bearer level QoS parameters ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: _default_eps_bearer_context_data ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_request(int pid, int ebi, + const esm_proc_qos_t* qos, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - Default EPS bearer context activation " + "requested by the network (ebi=%d)", ebi); + + /* Assign default EPS bearer context */ + int new_ebi = esm_ebr_assign(ebi, pid+1, TRUE); + if (new_ebi == ESM_EBI_UNASSIGNED) { + /* 3GPP TS 24.301, section 6.4.1.5, abnormal cases a and b + * Default EPS bearer context activation request for an already + * activated default or dedicated EPS bearer context + */ + int old_pid, old_bid; + /* Locally deactivate the existing EPS bearer context and proceed + * with the requested default EPS bearer context activation */ + rc = esm_proc_eps_bearer_context_deactivate(TRUE, ebi, + &old_pid, &old_bid); + if (rc != RETURNok) { + /* Failed to release EPS bearer context */ + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else { + /* Assign new default EPS bearer context */ + ebi = esm_ebr_assign(ebi, pid+1, TRUE); + } + } + + if (ebi != ESM_EBI_UNASSIGNED) { + /* Create new default EPS bearer context */ + ebi = esm_ebr_context_create(pid, ebi, TRUE, qos, NULL); + if (ebi != ESM_EBI_UNASSIGNED) { + /* Default EPS bearer contextx successfully created */ + _default_eps_bearer_context_data.ebi = ebi; + rc = RETURNok; + } + else { + /* No resource available */ + LOG_TRACE(WARNING, "ESM-PROC - Failed to create new default EPS " + "bearer context"); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_accept() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.3 ** + ** The UE accepts default EPS bearer context activation by ** + ** sending ACTIVATE DEFAULT EPS BEARER CONTEXT ACCEPT mes- ** + ** sage and entering the state BEARER CONTEXT ACTIVE. ** + ** If the default bearer is activated as part of the attach ** + ** procedure, the UE shall send the accept message together ** + ** with ATTACH COMPLETE message. ** + ** ** + ** Inputs: is_standalone: Indicates whether the activate default EPS ** + ** bearer context accept has to be sent stand-** + ** alone or together within an attach comple- ** + ** te message ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE (should be always ** + ** TRUE) ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_accept(int is_standalone, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO,"ESM-PROC - Default EPS bearer context activation " + "accepted by the UE (ebi=%d)", ebi); + + if (is_standalone) { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + } + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE */ + rc = esm_ebr_set_status(ebi, ESM_EBR_ACTIVE, ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already ACTIVE", ebi); + /* Accept network retransmission of already accepted activate + * default EPS bearer context request */ + LOG_FUNC_RETURN (RETURNok); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_reject() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** not accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.4 ** + ** The UE rejects default EPS bearer context activation by ** + ** sending ACTIVATE DEFAULT EPS BEARER CONTEXT REJECT mes- ** + ** sage and entering the state BEARER CONTEXT INACTIVE. ** + ** If the default EPS bearer context activation is part of ** + ** the attach procedure, the ESM sublayer shall notify the ** + ** EMM sublayer of an ESM failure. ** + ** ** + ** Inputs: is_standalone: Indicates whether the activate default EPS ** + ** bearer context accept has to be sent stand-** + ** alone or together within an attach comple- ** + ** te message ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_reject(int is_standalone, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(WARNING, "ESM-PROC - Default EPS bearer context activation " + "not accepted by the UE (ebi=%d)", ebi); + + if ( !esm_ebr_is_not_in_use(ebi) ) { + /* Release EPS bearer data currently in use */ + rc = esm_ebr_release(ebi); + } + + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer data"); + } + else if (is_standalone) { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + } + else { + /* An error is returned to notify EMM that the default EPS bearer + * activation procedure initiated as part of the initial attach + * procedure has failed + */ + rc = RETURNerror; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_complete() ** + ** ** + ** Description: Terminates the default EPS bearer context activation pro- ** + ** cedure upon receiving indication from the EPS Mobility ** + ** Management sublayer that the ACTIVATE DEFAULT EPS BEARER ** + ** CONTEXT ACCEPT message has been successfully delivered to ** + ** the MME. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _default_eps_bearer_context_data ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_complete(void) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, + "ESM-PROC - Default EPS bearer context activation complete"); + + /* Reset default EPS bearer context internal data */ + _default_eps_bearer_context_data.ebi = ESM_EBI_UNASSIGNED; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_default_eps_bearer_context_failure() ** + ** ** + ** Description: Performs default EPS bearer context activation procedure ** + ** upon receiving transmission failure of ESM message indi- ** + ** cation from the EPS Mobility Management sublayer ** + ** ** + ** The UE releases the default EPS bearer context previously ** + ** allocated before the ACTIVATE DEFAULT EPS BEARER CONTEXT ** + ** ACCEPT message was sent. ** + ** ** + ** Inputs: None ** + ** Others: _default_eps_bearer_context_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _default_eps_bearer_context_data ** + ** ** + ***************************************************************************/ +int esm_proc_default_eps_bearer_context_failure(void) +{ + LOG_FUNC_IN; + + int ebi = _default_eps_bearer_context_data.ebi; + int pid, bid; + + LOG_TRACE(WARNING, + "ESM-PROC - Default EPS bearer context activation failure"); + + /* Release the default EPS bearer context and enter state INACTIVE */ + int rc = esm_proc_eps_bearer_context_deactivate(TRUE, ebi, &pid, &bid); + if (rc != RETURNerror) { + /* Reset default EPS bearer context internal data */ + _default_eps_bearer_context_data.ebi = ESM_EBI_UNASSIGNED; + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _default_eps_bearer_activate_t3485_handler() ** + ** ** + ** Description: T3485 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 6.4.1.6, case a ** + ** On the first expiry of the timer T3485, the MME shall re- ** + ** send the ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST and ** + ** shall reset and restart timer T3485. This retransmission ** + ** is repeated four times, i.e. on the fifth expiry of timer ** + ** T3485, the MME shall release possibly allocated resources ** + ** for this activation and shall abort the procedure. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _default_eps_bearer_activate_t3485_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Get retransmission timer parameters data */ + esm_ebr_timer_data_t* data = (esm_ebr_timer_data_t*)(args); + + /* Increment the retransmission counter */ + data->count += 1; + + LOG_TRACE(WARNING, "ESM-PROC - T3485 timer expired (ueid=%d, ebi=%d), " + "retransmission counter = %d", + data->ueid, data->ebi, data->count); + + if (data->count < DEFAULT_EPS_BEARER_ACTIVATE_COUNTER_MAX) { + /* Re-send activate default EPS bearer context request message + * to the UE */ + rc = _default_eps_bearer_activate(data->ueid, data->ebi, &data->msg); + } + else { + /* + * The maximum number of activate default EPS bearer context request + * message retransmission has exceed + */ + int pid, bid; + /* Release the default EPS bearer context and enter state INACTIVE */ + rc = esm_proc_eps_bearer_context_deactivate(data->ueid, TRUE, + data->ebi, &pid, &bid, + NULL); + if (rc != RETURNerror) { + /* Stop timer T3485 */ + rc = esm_ebr_stop_timer(data->ueid, data->ebi); + } + } + + LOG_FUNC_RETURN (NULL); +} + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _default_eps_bearer_activate() ** + ** ** + ** Description: Sends ACTIVATE DEFAULT EPS BEREAR CONTEXT REQUEST message ** + ** and starts timer T3485 ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3485 ** + ** ** + ***************************************************************************/ +static int _default_eps_bearer_activate(unsigned int ueid, int ebi, + const OctetString* msg) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify EMM that an activate default EPS bearer context request message + * has to be sent to the UE + */ + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = ueid; + emm_esm->msg = *msg; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3485 retransmission timer */ + rc = esm_ebr_start_timer(ueid, ebi, msg, T3485_DEFAULT_VALUE, + _default_eps_bearer_activate_t3485_handler); + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/EpsBearerContextDeactivation.c b/openair-cn/NAS/EURECOM-NAS/src/esm/EpsBearerContextDeactivation.c new file mode 100644 index 0000000000..2e534a58ef --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/EpsBearerContextDeactivation.c @@ -0,0 +1,749 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EpsBearerContextDeactivation.c + +Version 0.1 + +Date 2013/05/22 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the EPS bearer context deactivation ESM procedure + executed by the Non-Access Stratum. + + The purpose of the EPS bearer context deactivation procedure + is to deactivate an EPS bearer context or disconnect from a + PDN by deactivating all EPS bearer contexts to the PDN. + The EPS bearer context deactivation procedure is initiated + by the network, and it may be triggered by the UE by means + of the UE requested bearer resource modification procedure + or UE requested PDN disconnect procedure. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esmData.h" +#include "esm_cause.h" +#include "esm_ebr.h" +#include "esm_ebr_context.h" + +#ifdef NAS_UE +#include "esm_main.h" +#endif + +#include "emm_sap.h" +#include "esm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the EPS bearer context deactivation procedure + * in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +static int _eps_bearer_release(int ebi, int* pid, int* bid); +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the EPS bearer context deactivation procedure + * in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Timer handlers + */ +static void* _eps_bearer_deactivate_t3495_handler(void*); + +/* Maximum value of the deactivate EPS bearer context request + * retransmission counter */ +#define EPS_BEARER_DEACTIVATE_COUNTER_MAX 5 + +static int _eps_bearer_deactivate(unsigned int ueid, int ebi, + const OctetString* msg); +static int _eps_bearer_release(unsigned int ueid, int ebi, int* pid, int* bid); + +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * EPS bearer context deactivation procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate() ** + ** ** + ** Description: Locally releases the EPS bearer context identified by the ** + ** given EPS bearer identity, without peer-to-peer signal- ** + ** ling between the UE and the MME, or checks whether an EPS ** + ** bearer context with specified EPS bearer identity has ** + ** been activated for the given UE. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** is local: TRUE if the EPS bearer context has to be ** + ** locally released without peer-to-peer si- ** + ** gnalling between the UE and the MME ** + ** ebi: EPS bearer identity of the EPS bearer con- ** + ** text to be deactivated ** + ** Others: _esm_data ** + ** ** + ** Outputs: pid: Identifier of the PDN connection the EPS ** + ** bearer belongs to ** + ** bid: Identifier of the released EPS bearer con- ** + ** text entry ** + ** esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate(unsigned int ueid, int is_local, + int ebi, int* pid, int* bid, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (is_local) { + if (ebi != ESM_SAP_ALL_EBI) { + /* Locally release the specified EPS bearer context */ + rc = _eps_bearer_release(ueid, ebi, pid, bid); + } + else if ( (ueid < ESM_DATA_NB_UE_MAX) && _esm_data.ctx[ueid] ) { + /* Locally release all the EPS bearer contexts */ + *bid = 0; + for (*pid = 0; *pid < ESM_DATA_PDN_MAX; (*pid)++) { + if (_esm_data.ctx[ueid]->pdn[*pid].data) { + rc = _eps_bearer_release(ueid, ESM_EBI_UNASSIGNED, + pid, bid); + if (rc != RETURNok) break; + } + } + } + LOG_FUNC_RETURN (rc); + } + + LOG_TRACE(INFO, "ESM-PROC - EPS bearer context deactivation " + "(ueid=%u, ebi=%d)", ueid, ebi); + + if ( (ueid < ESM_DATA_NB_UE_MAX) && (_esm_data.ctx[ueid] != NULL) && + (*pid < ESM_DATA_PDN_MAX) ) + { + if (_esm_data.ctx[ueid]->pdn[*pid].pid != *pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d " + "is not valid", *pid); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else if (_esm_data.ctx[ueid]->pdn[*pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", *pid); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else if (!_esm_data.ctx[ueid]->pdn[*pid].is_active) { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection %d is not active", + *pid); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else { + int i; + *esm_cause = ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY; + esm_pdn_t* pdn = _esm_data.ctx[ueid]->pdn[*pid].data; + for (i = 0; i < pdn->n_bearers; i++) { + if (pdn->bearer[i]->ebi != ebi) continue; + /* The EPS bearer context to be released is valid */ + rc = RETURNok; + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate_request() ** + ** ** + ** Description: Initiates the EPS bearer context deactivation procedure ** + ** ** + ** 3GPP TS 24.301, section 6.4.4.2 ** + ** If a NAS signalling connection exists, the MME initiates ** + ** the EPS bearer context deactivation procedure by sending ** + ** a DEACTIVATE EPS BEARER CONTEXT REQUEST message to the ** + ** UE, starting timer T3495 and entering state BEARER CON- ** + ** TEXT INACTIVE PENDING. ** + ** ** + ** Inputs: is_standalone: Not used - Always TRUE ** + ** ueid: UE lower layer identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE (not used) ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate_request(int is_standalone, + unsigned int ueid, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO,"ESM-PROC - Initiate EPS bearer context deactivation " + "(ueid=%d, ebi=%d)", ueid, ebi); + + /* Send deactivate EPS bearer context request message and + * start timer T3495 */ + rc = _eps_bearer_deactivate(ueid, ebi, msg); + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to ACTIVE PENDING */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_INACTIVE_PENDING, + ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in ACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already INACTIVE PENDING", + ebi); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate_accept() ** + ** ** + ** Description: Performs EPS bearer context deactivation procedure accep- ** + ** ted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.4.3 ** + ** Upon receipt of the DEACTIVATE EPS BEARER CONTEXT ACCEPT ** + ** message, the MME shall enter the state BEARER CONTEXT ** + ** INACTIVE and stop the timer T3495. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: The identifier of the PDN connection to be ** + ** released, if it exists; ** + ** RETURNerror otherwise. ** + ** Others: T3495 ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate_accept(unsigned int ueid, int ebi, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + int pid = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - EPS bearer context deactivation " + "accepted by the UE (ueid=%u, ebi=%d)", ueid, ebi); + + /* Stop T3495 timer if running */ + rc = esm_ebr_stop_timer(ueid, ebi); + if (rc != RETURNerror) { + int bid; + /* Release the EPS bearer context */ + rc = _eps_bearer_release(ueid, ebi, &pid, &bid); + if (rc != RETURNok) { + /* Failed to release the EPS bearer context */ + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + pid = RETURNerror; + } + } + + LOG_FUNC_RETURN (pid); +} + +#endif // NAS_MME + +/* + * -------------------------------------------------------------------------- + * EPS bearer context deactivation procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate() ** + ** ** + ** Description: Locally releases the EPS bearer context identified by the ** + ** given EPS bearer identity, without peer-to-peer signal- ** + ** ling between the UE and the MME, or checks whether the UE ** + ** has an EPS bearer context with specified EPS bearer iden- ** + ** tity activated. ** + ** ** + ** Inputs: is local: TRUE if the EPS bearer context has to be ** + ** locally released without peer-to-peer si- ** + ** gnalling between the UE and the MME ** + ** ebi: EPS bearer identity of the EPS bearer con- ** + ** text to be deactivated ** + ** Others: _esm_data ** + ** ** + ** Outputs: pid: Identifier of the PDN connection the EPS ** + ** bearer belongs to ** + ** bid: Identifier of the released EPS bearer con- ** + ** text entry ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate(int is_local, int ebi, + int* pid, int* bid) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (is_local) { + if (ebi != ESM_SAP_ALL_EBI) { + /* Locally release the EPS bearer context */ + rc = _eps_bearer_release(ebi, pid, bid); + } + else { + /* Locally release all the EPS bearer contexts */ + *bid = 0; + for (*pid = 0; *pid < ESM_DATA_PDN_MAX; (*pid)++) { + if (_esm_data.pdn[*pid].data) { + rc = _eps_bearer_release(ESM_EBI_UNASSIGNED, pid, bid); + if (rc != RETURNok) break; + } + } + } + LOG_FUNC_RETURN (rc); + } + + LOG_TRACE(WARNING, "ESM-PROC - EPS bearer context deactivation (ebi=%d)", + ebi); + + if (*pid < ESM_DATA_PDN_MAX) { + if (_esm_data.pdn[*pid].pid != *pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d " + "is not valid", *pid); + } + else if (_esm_data.pdn[*pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", *pid); + } + else if (!_esm_data.pdn[*pid].is_active) { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection %d is not active", + *pid); + } + else { + esm_pdn_t* pdn = _esm_data.pdn[*pid].data; + for (int i = 0; i < pdn->n_bearers; i++) { + if (pdn->bearer[i]->ebi != ebi) continue; + /* The EPS bearer context to be released is valid */ + rc = RETURNok; + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate_request() ** + ** ** + ** Description: Deletes the EPS bearer context identified by the EPS bea- ** + ** rer identity upon receipt of the DEACTIVATE EPS BEARER ** + ** CONTEXT REQUEST message. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate_request(int ebi, int* esm_cause) +{ + LOG_FUNC_IN; + + int pid, bid; + int rc = RETURNok; + + LOG_TRACE(INFO, "ESM-PROC - EPS bearer context deactivation " + "requested by the network (ebi=%d)", ebi); + + /* Release the EPS bearer context entry */ + if (esm_ebr_context_release(ebi, &pid, &bid) == ESM_EBI_UNASSIGNED) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer context"); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (RETURNerror); + } + + if (bid == 0) { + /* The EPS bearer identity is that of the default bearer assigned to + * the PDN connection */ + if (*esm_cause == ESM_CAUSE_REACTIVATION_REQUESTED) + { + esm_sap_t esm_sap; + int active = FALSE; + + /* 3GPP TS 24.301, section 6.4.4.3 + * The UE should re-initiate the UE requested PDN connectivity + * procedure for the APN associated to the PDN it was connected + * to in order to reactivate the EPS bearer context + */ + LOG_TRACE(WARNING, "ESM-PROC - The network requests PDN " + "connection reactivation"); + + /* Get PDN context parameters */ + rc = esm_main_get_pdn(pid + 1, &esm_sap.data.pdn_connect.pdn_type, + &esm_sap.data.pdn_connect.apn, + &esm_sap.data.pdn_connect.is_emergency, + &active); + if (rc != RETURNerror) { + if (active) { + LOG_TRACE(ERROR, "ESM-PROC - Connectivity to APN %s " + "has not been deactivated", + esm_sap.data.pdn_connect.apn); + *esm_cause = ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED; + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Notify ESM to re-initiate PDN connectivity procedure + */ + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; + esm_sap.is_standalone = TRUE; + esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.data.pdn_connect.cid = pid + 1; + rc = esm_sap_send(&esm_sap); + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_eps_bearer_context_deactivate_accept() ** + ** ** + ** Description: Performs EPS bearer context deactivation procedure accep- ** + ** ted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.4.4.3 ** + ** The UE accepts EPS bearer context deactivation by sending ** + ** DEACTIVATE EPS BEARER CONTEXT ACCEPT message and entering ** + ** the state BEARER CONTEXT INACTIVE. ** + ** ** + ** Inputs: is_standalone: Should be always TRUE ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** ue_triggered: TRUE if the EPS bearer context procedure ** + ** was triggered by the UE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_eps_bearer_context_deactivate_accept(int is_standalone, int ebi, + OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO,"ESM-PROC - EPS bearer context deactivation accepted"); + + if (is_standalone) { + emm_sap_t emm_sap; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_sap.u.emm_esm.u.data.msg.length = msg->length; + emm_sap.u.emm_esm.u.data.msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + } + + if (rc != RETURNerror) { + /* Set the EPS bearer context state to INACTIVE */ + rc = esm_ebr_set_status(ebi, ESM_EBR_INACTIVE, ue_triggered); + if (rc != RETURNok) { + /* The EPS bearer context was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already INACTIVE", ebi); + /* Accept network retransmission of already accepted deactivate + * EPS bearer context request */ + LOG_FUNC_RETURN (RETURNok); + } + /* Release EPS bearer data */ + rc = esm_ebr_release(ebi); + } + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _eps_bearer_deactivate_t3495_handler() ** + ** ** + ** Description: T3495 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 6.4.4.5, case a ** + ** On the first expiry of the timer T3495, the MME shall re- ** + ** send the DEACTIVATE EPS BEARER CONTEXT REQUEST and shall ** + ** reset and restart timer T3495. This retransmission is ** + ** repeated four times, i.e. on the fifth expiry of timer ** + ** T3495, the MME shall abort the procedure and deactivate ** + ** the EPS bearer context locally. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _eps_bearer_deactivate_t3495_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Get retransmission timer parameters data */ + esm_ebr_timer_data_t* data = (esm_ebr_timer_data_t*)(args); + + /* Increment the retransmission counter */ + data->count += 1; + + LOG_TRACE(WARNING, "ESM-PROC - T3495 timer expired (ueid=%d, ebi=%d), " + "retransmission counter = %d", + data->ueid, data->ebi, data->count); + + if (data->count < EPS_BEARER_DEACTIVATE_COUNTER_MAX) { + /* Re-send deactivate EPS bearer context request message to the UE */ + rc = _eps_bearer_deactivate(data->ueid, data->ebi, &data->msg); + } + else { + /* + * The maximum number of deactivate EPS bearer context request + * message retransmission has exceed + */ + int pid, bid; + /* Deactivate the EPS bearer context locally without peer-to-peer + * signalling between the UE and the MME */ + rc = _eps_bearer_release(data->ueid, data->ebi, &pid, &bid); + if (rc != RETURNerror) { + /* Stop timer T3495 */ + rc = esm_ebr_stop_timer(data->ueid, data->ebi); + } + } + + LOG_FUNC_RETURN (NULL); +} +#endif // NAS_MME + +/* + * -------------------------------------------------------------------------- + * MME specific local functions + * -------------------------------------------------------------------------- + */ + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _eps_bearer_deactivate() ** + ** ** + ** Description: Sends DEACTIVATE EPS BEREAR CONTEXT REQUEST message and ** + ** starts timer T3495 ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** msg: Encoded ESM message to be sent ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: T3495 ** + ** ** + ***************************************************************************/ +static int _eps_bearer_deactivate(unsigned int ueid, int ebi, + const OctetString* msg) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify EMM that a deactivate EPS bearer context request message + * has to be sent to the UE + */ + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = ueid; + emm_esm->msg = *msg; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3495 retransmission timer */ + rc = esm_ebr_start_timer(ueid, ebi, msg, T3495_DEFAULT_VALUE, + _eps_bearer_deactivate_t3495_handler); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _eps_bearer_release() ** + ** ** + ** Description: Releases the EPS bearer context identified by the given ** + ** EPS bearer identity and enters state INACTIVE. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: pid: Identifier of the PDN connection the EPS ** + ** bearer belongs to ** + ** bid: Identifier of the released EPS bearer con- ** + ** text entry ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _eps_bearer_release(unsigned int ueid, int ebi, int* pid, int* bid) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + /* Release the EPS bearer context entry */ + ebi = esm_ebr_context_release(ueid, ebi, pid, bid); + if (ebi == ESM_EBI_UNASSIGNED) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer context"); + } + else { + /* Set the EPS bearer context state to INACTIVE */ + rc = esm_ebr_set_status(ueid, ebi, ESM_EBR_INACTIVE, FALSE); + if (rc != RETURNok) { + /* The EPS bearer context was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already INACTIVE", ebi); + } + else { + /* Release EPS bearer data */ + rc = esm_ebr_release(ueid, ebi); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "ESM-PROC - Failed to release EPS bearer data"); + } + } + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME + +/* + * -------------------------------------------------------------------------- + * UE specific local functions + * -------------------------------------------------------------------------- + */ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _eps_bearer_release() ** + ** ** + ** Description: Releases the EPS bearer context identified by the given ** + ** EPS bearer identity and enters state INACTIVE. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: pid: Identifier of the PDN connection the EPS ** + ** bearer belongs to ** + ** bid: Identifier of the released EPS bearer con- ** + ** text entry ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _eps_bearer_release(int ebi, int* pid, int* bid) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + /* Release the EPS bearer context entry */ + ebi = esm_ebr_context_release(ebi, pid, bid); + if (ebi == ESM_EBI_UNASSIGNED) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release EPS bearer context"); + } + else { + /* Set the EPS bearer context state to INACTIVE */ + rc = esm_ebr_set_status(ebi, ESM_EBR_INACTIVE, FALSE); + if (rc != RETURNok) { + /* The EPS bearer context was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - EBI %d was already INACTIVE", ebi); + } + else { + /* Release EPS bearer data */ + rc = esm_ebr_release(ebi); + if (rc != RETURNok) { + LOG_TRACE(WARNING, + "ESM-PROC - Failed to release EPS bearer data"); + } + } + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/EsmStatusHdl.c b/openair-cn/NAS/EURECOM-NAS/src/esm/EsmStatusHdl.c new file mode 100644 index 0000000000..4117ecea7d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/EsmStatusHdl.c @@ -0,0 +1,183 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source EsmStatus.c + +Version 0.1 + +Date 2013/06/17 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the ESM status procedure executed by the Non-Access + Stratum. + + ESM status procedure can be related to an EPS bearer context + or to a procedure transaction. + + The purpose of the sending of the ESM STATUS message is to + report at any time certain error conditions detected upon + receipt of ESM protocol data. The ESM STATUS message can be + sent by both the MME and the UE. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esm_cause.h" + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: esm_proc_status_ind() ** + ** ** + ** Description: Processes received ESM status message. ** + ** ** + ** 3GPP TS 24.301, section 6.7 ** + ** Upon receiving ESM Status message the UE/MME shall take ** + ** different actions depending on the received ESM cause ** + ** value. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** esm_cause: Received ESM cause code ** + ** failure ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_status_ind( +#ifdef NAS_MME + unsigned int ueid, +#endif + int pti, int ebi, int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(INFO,"ESM-PROC - ESM status procedure requested (cause=%d)", + *esm_cause); + + LOG_TRACE(DEBUG, "ESM-PROC - To be implemented"); + + switch (*esm_cause) + { + case ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY: + /* + * Abort any ongoing ESM procedure related to the received EPS + * bearer identity, stop any related timer, and deactivate the + * corresponding EPS bearer context locally + */ + /* TODO */ + rc = RETURNok; + break; + + case ESM_CAUSE_INVALID_PTI_VALUE: + /* + * Abort any ongoing ESM procedure related to the received PTI + * value and stop any related timer + */ + /* TODO */ + rc = RETURNok; + break; + + case ESM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED: + /* + * Abort any ongoing ESM procedure related to the PTI or + * EPS bearer identity and stop any related timer + */ + /* TODO */ + rc = RETURNok; + break; + + default: + /* + * No state transition and no specific action shall be taken; + * local actions are possible + */ + /* TODO */ + rc = RETURNok; + break; + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_status() ** + ** ** + ** Description: Initiates ESM status procedure. ** + ** ** + ** Inputs: is_standalone: Not used - Always TRUE ** + ** ueid: UE lower layer identifier ** + ** ebi: Not used ** + ** msg: Encoded ESM status message to be sent ** + ** ue_triggered: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_status(int is_standalone, +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi, OctetString* msg, + int ue_triggered) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + + LOG_TRACE(INFO,"ESM-PROC - ESM status procedure requested"); + + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; +#ifdef NAS_UE + emm_sap.u.emm_esm.ueid = 0; +#endif +#ifdef NAS_MME + emm_sap.u.emm_esm.ueid = ueid; +#endif + emm_sap.u.emm_esm.u.data.msg.length = msg->length; + emm_sap.u.emm_esm.u.data.msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/Makefile b/openair-cn/NAS/EURECOM-NAS/src/esm/Makefile new file mode 100644 index 0000000000..4a8a713143 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/Makefile @@ -0,0 +1,201 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) -I$(MMEAPIDIR) \ + -I$(EMMSAPDIR) -I$(ESMSAPDIR) -I$(ESMMSGDIR) + +all: $(OBJS) + @$(CD) $(ESMMSGDIR) && $(MAKE) + @$(CD) $(ESMSAPDIR) && $(MAKE) + +clean: + $(RM) $(OBJS) *.bak *~ + @$(CD) $(ESMSAPDIR) && $(MAKE) $@ + +veryclean: clean + @$(CD) $(ESMSAPDIR) && $(MAKE) $@ + @$(CD) $(ESMMSGDIR) && $(MAKE) $@ + $(RM) $(TARGET) + +%.o: %.c Makefile $(PROJDIR)/Makerules $(PROJDIR)/Makefile.inc + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +DedicatedEpsBearerContextActivation.o: esm_proc.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +DedicatedEpsBearerContextActivation.o: /usr/include/stdint.h +DedicatedEpsBearerContextActivation.o: /usr/include/features.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +DedicatedEpsBearerContextActivation.o: esm_ebr.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +DedicatedEpsBearerContextActivation.o: /usr/include/stdio.h +DedicatedEpsBearerContextActivation.o: /usr/include/libio.h +DedicatedEpsBearerContextActivation.o: /usr/include/_G_config.h +DedicatedEpsBearerContextActivation.o: /usr/include/wchar.h +DedicatedEpsBearerContextActivation.o: /usr/include/stdlib.h +DedicatedEpsBearerContextActivation.o: /usr/include/alloca.h +DedicatedEpsBearerContextActivation.o: esm_ebr_context.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +DedicatedEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +DefaultEpsBearerContextActivation.o: esm_proc.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +DefaultEpsBearerContextActivation.o: /usr/include/stdint.h +DefaultEpsBearerContextActivation.o: /usr/include/features.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +DefaultEpsBearerContextActivation.o: esm_ebr.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +DefaultEpsBearerContextActivation.o: /usr/include/stdio.h +DefaultEpsBearerContextActivation.o: /usr/include/libio.h +DefaultEpsBearerContextActivation.o: /usr/include/_G_config.h +DefaultEpsBearerContextActivation.o: /usr/include/wchar.h +DefaultEpsBearerContextActivation.o: /usr/include/stdlib.h +DefaultEpsBearerContextActivation.o: /usr/include/alloca.h esm_ebr_context.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +DefaultEpsBearerContextActivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +EpsBearerContextDeactivation.o: esm_proc.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsBearerContextDeactivation.o: /usr/include/stdint.h /usr/include/features.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsBearerContextDeactivation.o: esmData.h /usr/include/stdio.h +EpsBearerContextDeactivation.o: /usr/include/libio.h /usr/include/_G_config.h +EpsBearerContextDeactivation.o: /usr/include/wchar.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +EpsBearerContextDeactivation.o: esm_ebr.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +EpsBearerContextDeactivation.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsBearerContextDeactivation.o: esm_ebr_context.h esm_main.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +EpsBearerContextDeactivation.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +esm_ebr.o: esm_ebr.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +esm_ebr.o: /usr/include/stdint.h /usr/include/features.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +esm_ebr.o: /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h +esm_ebr.o: /usr/include/wchar.h /usr/include/stdlib.h /usr/include/alloca.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +esm_ebr.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/mme/mme_api.h +esm_ebr.o: /usr/include/string.h /usr/include/xlocale.h +esm_ebr_context.o: esm_ebr_context.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +esm_ebr_context.o: /usr/include/stdint.h /usr/include/features.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +esm_ebr_context.o: esmData.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +esm_ebr_context.o: /usr/include/stdio.h /usr/include/libio.h +esm_ebr_context.o: /usr/include/_G_config.h /usr/include/wchar.h esm_ebr.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +esm_ebr_context.o: /usr/include/stdlib.h /usr/include/alloca.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +esm_ebr_context.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +esm_ebr_context.o: /usr/include/string.h /usr/include/xlocale.h +esm_ip.o: esmData.h +esm_ip.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +esm_ip.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +esm_ip.o: /usr/include/stdint.h /usr/include/features.h /usr/include/stdio.h +esm_ip.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +esm_main.o: esm_main.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +esm_main.o: /usr/include/stdint.h /usr/include/features.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +esm_main.o: esmData.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +esm_main.o: /usr/include/stdio.h /usr/include/libio.h +esm_main.o: /usr/include/_G_config.h /usr/include/wchar.h esm_pt.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +esm_main.o: /usr/include/stdlib.h /usr/include/alloca.h esm_ebr.h +esm_main.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +esm_pt.o: esm_pt.h +esm_pt.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +esm_pt.o: /usr/include/stdint.h /usr/include/features.h +esm_pt.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +esm_pt.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +esm_pt.o: /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h +esm_pt.o: /usr/include/wchar.h /usr/include/stdlib.h /usr/include/alloca.h +esm_pt.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +esm_pt.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +esm_pt.o: /usr/include/string.h /usr/include/xlocale.h +EsmStatusHdl.o: esm_proc.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EsmStatusHdl.o: /usr/include/stdint.h /usr/include/features.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +EsmStatusHdl.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +PdnConnectivity.o: esm_proc.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PdnConnectivity.o: /usr/include/stdint.h /usr/include/features.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PdnConnectivity.o: esmData.h /usr/include/stdio.h /usr/include/libio.h +PdnConnectivity.o: /usr/include/_G_config.h /usr/include/wchar.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +PdnConnectivity.o: esm_pt.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +PdnConnectivity.o: /usr/include/stdlib.h /usr/include/alloca.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +PdnConnectivity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h +PdnConnectivity.o: /usr/include/string.h /usr/include/xlocale.h +PdnDisconnect.o: esm_proc.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PdnDisconnect.o: /usr/include/stdint.h /usr/include/features.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PdnDisconnect.o: esmData.h /usr/include/stdio.h /usr/include/libio.h +PdnDisconnect.o: /usr/include/_G_config.h /usr/include/wchar.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +PdnDisconnect.o: esm_pt.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +PdnDisconnect.o: /usr/include/stdlib.h /usr/include/alloca.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_sap.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_regDef.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_esmDef.h +PdnDisconnect.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/sap/emm_asDef.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/PdnConnectivity.c b/openair-cn/NAS/EURECOM-NAS/src/esm/PdnConnectivity.c new file mode 100644 index 0000000000..9bc33756c9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/PdnConnectivity.c @@ -0,0 +1,1424 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source PdnConnectivity.c + +Version 0.1 + +Date 2013/01/02 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the PDN connectivity ESM procedure executed by the + Non-Access Stratum. + + The PDN connectivity procedure is used by the UE to request + the setup of a default EPS bearer to a PDN. + + The procedure is used either to establish the 1st default + bearer by including the PDN CONNECTIVITY REQUEST message + into the initial attach message, or to establish subsequent + default bearers to additional PDNs in order to allow the UE + simultaneous access to multiple PDNs by sending the message + stand-alone. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esmData.h" +#include "esm_cause.h" +#include "esm_pt.h" + +#ifdef NAS_MME +#include "mme_api.h" +#endif + +#include "emm_sap.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memset, memcpy, memcmp + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the PDN connectivity procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * PDN connection handlers + */ +static int _pdn_connectivity_create(int pid, const OctetString* apn, esm_proc_pdn_type_t pdn_type, int is_emergency); +static int _pdn_connectivity_update(int pid, const OctetString* apn, esm_proc_pdn_type_t pdn_type, const OctetString* pdn_addr, int esm_cause); +static int _pdn_connectivity_delete(int pid); + +static int _pdn_connectivity_set_pti(int pid, int pti); +static int _pdn_connectivity_find_apn(const OctetString* apn); +static int _pdn_connectivity_find_pdn(const OctetString* apn, esm_proc_pdn_type_t pdn_type); + +/* + * Timer handlers + */ +static void* _pdn_connectivity_t3482_handler(void*); + +/* Maximum value of the PDN connectivity request retransmission counter */ +#define ESM_PDN_CONNECTIVITY_COUNTER_MAX 5 + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the PDN connectivity procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * PDN connection handlers + */ +static int _pdn_connectivity_create(unsigned int ueid, int pti, const OctetString* apn, esm_proc_pdn_type_t pdn_type, const OctetString* pdn_addr, int is_emergency); +int _pdn_connectivity_delete(unsigned int ueid, int pid); + +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * PDN connectivity procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity() ** + ** ** + ** Description: Defines a new PDN connection for the specified Access ** + ** Point Name or undefines the PDN connection with the given ** + ** identifier ** + ** ** + ** Inputs: cid: PDN connection identifier ** + ** is_to_define: Indicates whether the PDN connection has ** + ** to be defined or undefined ** + ** pdn_type: PDN connection type (IPv4, IPv6, IPv4v6) ** + ** apn: Access Point logical Name to be used ** + ** is_emergency: TRUE if the PDN connection has to be esta- ** + ** blished for emergency bearer services ** + ** Others: None ** + ** ** + ** Outputs: pti: Procedure transaction identity assigned to ** + ** the new PDN connection or the released PDN ** + ** connection ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity(int cid, int is_to_define, + esm_proc_pdn_type_t pdn_type, + const OctetString* apn, int is_emergency, + unsigned int* pti) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int pid = cid - 1; + + if (!is_to_define) { + LOG_TRACE(INFO, "ESM-PROC - Undefine PDN connection (cid=%d)", cid); + /* Delete the PDN connection entry */ + int pti = _pdn_connectivity_delete(pid); + if (pti != ESM_PT_UNASSIGNED) { + /* Release the procedure transaction data */ + rc = esm_pt_release(pti); + } + LOG_FUNC_RETURN(rc); + } + else if (pti != NULL) { + LOG_TRACE(INFO, "ESM-PROC - Assign new procedure transaction identity " + "(cid=%d)", cid); + /* Assign new procedure transaction identity */ + *pti = esm_pt_assign(); + if (*pti == ESM_PT_UNASSIGNED) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to assign new procedure " + "transaction identity"); + LOG_FUNC_RETURN (RETURNerror); + } + /* Update the PDN connection data */ + rc = _pdn_connectivity_set_pti(pid, *pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to update PDN connection"); + } + LOG_FUNC_RETURN (rc); + } + + LOG_TRACE(INFO,"ESM-PROC - Define new %s PDN connection to APN %s (cid=%d)", + (pdn_type == ESM_PDN_TYPE_IPV4)? "IPv4" : + (pdn_type == ESM_PDN_TYPE_IPV6)? "IPv6" : "IPv4v6", + apn->value, cid); + + if (is_emergency && _esm_data.emergency) { + /* The UE shall not request additional PDN connection for + * emergency bearer services */ + LOG_TRACE(WARNING, "ESM-PROC - PDN connection for emergency bearer " + "services is already active"); + LOG_FUNC_RETURN (RETURNerror); + } + else if (pid < ESM_DATA_PDN_MAX) { + if ((pid == _esm_data.pdn[pid].pid) && (_esm_data.pdn[pid].is_active)) { + /* PDN connection with the specified identifier is active */ + LOG_TRACE(WARNING, "ESM-PROC - PDN connection is active"); + LOG_FUNC_RETURN (RETURNerror); + } + } + else { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection identifier is not valid"); + LOG_FUNC_RETURN (RETURNerror); + } + + if (apn && apn->length > 0) { + /* The UE requested subsequent connectivity to additionnal PDNs */ + int pid = _pdn_connectivity_find_apn(apn); + if ( (pid >= 0) && _esm_data.pdn[pid].is_active ) { + /* An active PDN connection to this APN already exists */ + if ( (_esm_data.pdn[pid].data->type != ESM_PDN_TYPE_IPV4V6) && + (_esm_data.pdn[pid].data->type != pdn_type) ) { + /* The UE is requesting PDN connection for other IP version + * than the one already activated */ + if (!_esm_data.pdn[pid].data->addr_realloc) { + /* The network does not allow PDN connectivity using + * IPv4 and IPv6 address versions to the same APN */ + if (pdn_type != ESM_PDN_TYPE_IPV4V6) { + LOG_TRACE(WARNING, "ESM-PROC - %s PDN connectivity to " + "%s is not allowed by the network", + (pdn_type != ESM_PDN_TYPE_IPV4)? "IPv6" : + "IPv4", apn->value); + } else { + LOG_TRACE(WARNING, "ESM-PROC - %s PDN connection to %s " + "already exists", + (_esm_data.pdn[pid].data->type != + ESM_PDN_TYPE_IPV4)? "IPv6" : "IPv4", + apn->value); + } + LOG_FUNC_RETURN (RETURNerror); + } + } + else { + /* The UE is requesting PDN connection to this APN using the + * same IP version than the one already activated */ + LOG_TRACE(WARNING, "ESM-PROC - %s PDN connection to %s " + "already exists", + (_esm_data.pdn[pid].data->type != ESM_PDN_TYPE_IPV4)? + (_esm_data.pdn[pid].data->type != ESM_PDN_TYPE_IPV6)? + "IPv4v6" : "IPv6" : "IPv4", apn->value); + LOG_FUNC_RETURN (RETURNerror); + } + } + } + + /* + * New PDN context has to be defined to allow connectivity to an APN: + * The UE may attempt to attach to the network using the default APN, + * or request PDN connectivity to emergency bearer services. The UE + * may also subsequently request connectivity to additional PDNs if + * not already established, or may have been allowed to request PDN + * connectivity for other IP version than the one already activated + */ + rc = _pdn_connectivity_create(pid, apn, pdn_type, is_emergency); + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_request() ** + ** ** + ** Description: Initiates PDN connectivity procedure to request setup of ** + ** a default EPS bearer to a PDN. ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.2 ** + ** The UE requests connectivity to an additional PDN by sen- ** + ** ding a PDN CONNECTIVITY REQUEST message to the MME, star- ** + ** ting timer T3482 and entering state PROCEDURE TRANSACTION ** + ** PENDING. ** + ** ** + ** Inputs: is_standalone: Indicates whether the PDN connectivity ** + ** procedure is initiated as part of the at- ** + ** tach procedure ** + ** pti: Procedure transaction identity ** + ** msg: Encoded PDN connectivity request message ** + ** to be sent ** + ** sent_by_ue: Not used - Always TRUE ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_request(int is_standalone, int pti, + OctetString* msg, int sent_by_ue) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "ESM-PROC - Initiate PDN connectivity (pti=%d)", pti); + + if (is_standalone) + { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3482 retransmission timer */ + rc = esm_pt_start_timer(pti, msg, T3482_DEFAULT_VALUE, + _pdn_connectivity_t3482_handler); + } + } + + if (rc != RETURNerror) { + /* Set the procedure transaction state to PENDING */ + rc = esm_pt_set_status(pti, ESM_PT_PENDING); + if (rc != RETURNok) { + /* The procedure transaction was already in PENDING state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already PENDING", pti); + } + } + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_accept() ** + ** ** + ** Description: Performs PDN connectivity procedure accepted by the net- ** + ** work. ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.3 ** + ** The UE shall stop timer T3482 and enter the state PROCE- ** + ** DURE TRANSACTION INACTIVE. ** + ** ** + ** Inputs: pti: Identifies the UE requested PDN connecti- ** + ** vity procedure accepted by the network ** + ** pdn_type: PDN type value (IPv4, IPv6, IPv4v6) ** + ** pdn_addr: PDN address ** + ** apn: Access Point Name of the PDN connection ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: The identifier of the PDN connection when ** + ** successfully updated; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_accept(int pti, esm_proc_pdn_type_t pdn_type, + const OctetString* pdn_addr, + const OctetString* apn, int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + int pid = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - PDN connectivity accepted by the network " + "(pti=%d) APN = %s, IP address = %s", pti, apn->value, + (pdn_type == ESM_PDN_TYPE_IPV4)? esm_data_get_ipv4_addr(pdn_addr) : + (pdn_type == ESM_PDN_TYPE_IPV6)? esm_data_get_ipv6_addr(pdn_addr) : + esm_data_get_ipv4v6_addr(pdn_addr)); + + /* Stop T3482 timer if running */ + (void) esm_pt_stop_timer(pti); + /* Set the procedure transaction state to INACTIVE */ + rc = esm_pt_set_status(pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state + * as the request may have already been accepted; consider + * this request message with same PTI as a network re- + * transmission */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d network retransmission", pti); + *esm_cause = ESM_CAUSE_PTI_ALREADY_IN_USE; + } + else { + /* XXX - 3GPP TS 24.301, section 6.5.1.3 and 7.3.1 + * The UE should ensure that the procedure transaction identity + * (PTI) assigned to this procedure is not released immediately. + * While the PTI value is not released, the UE regards any received + * ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST message with the same + * PTI value as a network retransmission. + * The way to achieve this is implementation dependent. + */ + + /* Check whether a PDN connection exists to this APN */ + pid = _pdn_connectivity_find_pdn(apn, pdn_type); + + if (pid < 0) { + /* No any PDN connection has been defined to establish connectivity + * to this APN */ + LOG_TRACE(WARNING, "ESM-PROC - PDN connection entry for " + "APN \"%s\" (type=%d) not found", apn->value, pdn_type); + *esm_cause = ESM_CAUSE_UNKNOWN_ACCESS_POINT_NAME; + LOG_FUNC_RETURN(RETURNerror); + } + + /* Update the PDN connection */ + rc = _pdn_connectivity_update(pid, apn, pdn_type, pdn_addr, *esm_cause); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to update PDN connection " + "(pid=%d)", pid); + *esm_cause = ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED; + LOG_FUNC_RETURN(RETURNerror); + } + } + + LOG_FUNC_RETURN (pid); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_reject() ** + ** ** + ** Description: Performs PDN connectivity procedure not accepted by the ** + ** network. ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.4 ** + ** Upon receipt of the PDN CONNECTIVITY REJECT message, the ** + ** UE shall stop timer T3482 and enter the state PROCEDURE ** + ** TRANSACTION INACTIVE. ** + ** ** + ** Inputs: pti: Identifies the UE requested PDN connecti- ** + ** vity procedure rejected by the network ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_reject(int pti, int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "ESM-PROC - PDN connectivity rejected by " + "the network (pti=%d), ESM cause = %d", pti, *esm_cause); + + /* Stop T3482 timer if running */ + (void) esm_pt_stop_timer(pti); + /* Set the procedure transaction state to INACTIVE */ + rc = esm_pt_set_status(pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already INACTIVE", pti); + *esm_cause = ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + } + else { + /* Release the procedure transaction identity */ + rc = esm_pt_release(pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", pti); + *esm_cause = ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED; + } + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_complete() ** + ** ** + ** Description: Terminates the PDN connectivity procedure upon receiving ** + ** indication from the EPS Mobility Management sublayer that ** + ** the ACTIVATE DEFAULT EPS BEARER CONTEXT ACCEPT message ** + ** has been successfully delivered to the MME. ** + ** ** + ** The UE releases the transaction identity assigned to this ** + ** PDN connectivity procedure. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_complete(void) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - PDN connectivity complete"); + + /* Get the procedure transaction identity assigned to the PDN connection + * entry which is still pending in the inactive state */ + int pti = esm_pt_get_pending_pti(ESM_PT_INACTIVE); + if (pti != ESM_PT_UNASSIGNED) { + /* Release the procedure transaction identity */ + rc = esm_pt_release(pti); + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_failure() ** + ** ** + ** Description: Performs PDN connectivity procedure upon receiving trans- ** + ** mission failure of ESM message indication from the EPS ** + ** Mobility Management sublayer ** + ** ** + ** The UE releases the transaction identity allocated to the ** + ** PDN connectivity procedure which is still pending in the ** + ** PROCEDURE TRANSACTION INACTIVE or PENDING state. ** + ** ** + ** Inputs: is_pending: TRUE if this PDN connectivity procedure ** + ** transaction is in the PENDING state ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_failure(int is_pending) +{ + LOG_FUNC_IN; + + int rc; + int pti; + + LOG_TRACE(WARNING, "ESM-PROC - PDN connectivity failure in state %s", + (is_pending)? "PENDING" : "INACTIVE"); + + if (is_pending) + { + /* Get the procedure transaction identity assigned to the pending PDN + * connection entry */ + pti = esm_pt_get_pending_pti(ESM_PT_PENDING); + if (pti == ESM_PT_UNASSIGNED) { + LOG_TRACE(ERROR, "ESM-PROC - No procedure transaction is PENDING"); + return (RETURNerror); + } + /* Set the procedure transaction state to INACTIVE */ + (void) esm_pt_set_status(pti, ESM_PT_INACTIVE); + } + else { + /* Get the procedure transaction identity assigned to the PDN + * connection entry which is still pending in the inactive state */ + pti = esm_pt_get_pending_pti(ESM_PT_INACTIVE); + } + + /* Release the procedure transaction identity */ + rc = esm_pt_release(pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", pti); + } + + LOG_FUNC_RETURN(rc); +} + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * PDN connectivity procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_request() ** + ** ** + ** Description: Performs PDN connectivity procedure requested by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.3 ** + ** Upon receipt of the PDN CONNECTIVITY REQUEST message, the ** + ** MME checks if connectivity with the requested PDN can be ** + ** established. If no requested APN is provided the MME ** + ** shall use the default APN as the requested APN if the ** + ** request type is different from "emergency", or the APN ** + ** configured for emergency bearer services if the request ** + ** type is "emergency". ** + ** If connectivity with the requested PDN is accepted by the ** + ** network, the MME shall initiate the default EPS bearer ** + ** context activation procedure. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Identifies the PDN connectivity procedure ** + ** requested by the UE ** + ** request_type: Type of the PDN request ** + ** pdn_type: PDN type value (IPv4, IPv6, IPv4v6) ** + ** apn: Requested Access Point Name ** + ** Others: _esm_data ** + ** ** + ** Outputs: apn: Default Access Point Name ** + ** pdn_addr: Assigned IPv4 address and/or IPv6 suffix ** + ** esm_qos: EPS bearer level QoS parameters ** + ** esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: The identifier of the PDN connection if ** + ** successfully created; ** + ** RETURNerror otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_request(unsigned int ueid, int pti, + esm_proc_pdn_request_t request_type, + OctetString* apn, + esm_proc_pdn_type_t pdn_type, + OctetString* pdn_addr, + esm_proc_qos_t* esm_qos, + int* esm_cause) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int pid = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - PDN connectivity requested by the UE " + "(ueid=%u, pti=%d) PDN type = %s, APN = %s", ueid, pti, + (pdn_type == ESM_PDN_TYPE_IPV4)? "IPv4" : + (pdn_type == ESM_PDN_TYPE_IPV6)? "IPv6" : "IPv4v6", + (apn)? (char*)(apn->value) : "null"); + + /* UE identifier sanity check */ + if (ueid >= ESM_DATA_NB_UE_MAX) { + LOG_TRACE(WARNING, "ESM-PROC - Number of connected UEs exceeded"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* + * Check network IP capabilities + */ + *esm_cause = ESM_CAUSE_SUCCESS; + switch (_esm_data.conf.features & (MME_API_IPV4 | MME_API_IPV6)) + { + case (MME_API_IPV4 | MME_API_IPV6): + /* The network supports both IPv4 and IPv6 connection */ + if ( (pdn_type == ESM_PDN_TYPE_IPV4V6) && + (_esm_data.conf.features & MME_API_SINGLE_ADDR_BEARERS) ) { + /* The network supports single IP version bearers only */ + *esm_cause = ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED; + } + rc = RETURNok; + break; + + case MME_API_IPV6: + /* The network supports connection to IPv6 only */ + *esm_cause = ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED; + if (pdn_type != ESM_PDN_TYPE_IPV4) { + rc = RETURNok; + } + break; + + case MME_API_IPV4: + /* The network supports connection to IPv4 only */ + *esm_cause = ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED; + if (pdn_type != ESM_PDN_TYPE_IPV6) { + rc = RETURNok; + } + break; + } + + if (rc != RETURNerror) + { + int is_emergency = (request_type == ESM_PDN_REQUEST_EMERGENCY); + mme_api_qos_t qos; + + /* Check if connectivity with the requested PDN can be established */ + rc = mme_api_subscribe(apn, pdn_addr, is_emergency, &qos); + + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Connectivity to the requested PDN " + "cannot be established"); + *esm_cause = ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED; + LOG_FUNC_RETURN (RETURNerror); + } + + /* Create new ESM context for the UE within the MME */ + if (_esm_data.ctx[ueid] == NULL) { + _esm_data.ctx[ueid] = + (esm_data_context_t*)malloc(sizeof(esm_data_context_t)); + memset(_esm_data.ctx[ueid], 0 , sizeof(esm_data_context_t)); + } + if (_esm_data.ctx[ueid]) { + /* Create new PDN connection */ + pid = _pdn_connectivity_create(ueid, pti, apn, pdn_type, + pdn_addr, is_emergency); + /* Setup ESM QoS parameters */ + if (esm_qos) { + esm_qos->gbrUL = qos.gbr[MME_API_UPLINK]; + esm_qos->gbrDL = qos.gbr[MME_API_DOWNLINK]; + esm_qos->mbrUL = qos.mbr[MME_API_UPLINK]; + esm_qos->mbrDL = qos.mbr[MME_API_DOWNLINK]; + esm_qos->qci = qos.qci; + } + } + + if (pid < 0) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to create PDN connection"); + *esm_cause = ESM_CAUSE_INSUFFICIENT_RESOURCES; + LOG_FUNC_RETURN(RETURNerror); + } + } + + LOG_FUNC_RETURN(pid); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_reject() ** + ** ** + ** Description: Performs PDN connectivity procedure not accepted by the ** + ** network. ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.4 ** + ** If connectivity with the requested PDN cannot be accepted ** + ** by the network, the MME shall send a PDN CONNECTIVITY RE- ** + ** JECT message to the UE. ** + ** ** + ** Inputs: is_standalone: Indicates whether the PDN connectivity ** + ** procedure was initiated as part of the at- ** + ** tach procedure ** + ** ueid: UE lower layer identifier ** + ** ebi: Not used ** + ** msg: Encoded PDN connectivity reject message to ** + ** be sent ** + ** ue_triggered: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_reject(int is_standalone, unsigned int ueid, + int ebi, OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + LOG_TRACE(WARNING, "ESM-PROC - PDN connectivity not accepted by the " + "network (ueid=%d)", ueid); + + if (is_standalone) { + emm_sap_t emm_sap; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = ueid; + emm_sap.u.emm_esm.u.data.msg.length = msg->length; + emm_sap.u.emm_esm.u.data.msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + } + + /* If the PDN connectivity procedure initiated as part of the initial + * attach procedure has failed, an error is returned to notify EMM that + * the ESM sublayer did not accept UE requested PDN connectivity */ + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_connectivity_failure() ** + ** ** + ** Description: Performs PDN connectivity procedure upon receiving noti- ** + ** fication from the EPS Mobility Management sublayer that ** + ** EMM procedure that initiated PDN connectivity activation ** + ** locally failed. ** + ** ** + ** The MME releases the PDN connection entry allocated when ** + ** the PDN connectivity procedure was requested by the UE. ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pid: Identifier of the PDN connection to be ** + ** released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_connectivity_failure(unsigned int ueid, int pid) +{ + LOG_FUNC_IN; + + LOG_TRACE(WARNING, "ESM-PROC - PDN connectivity failure (ueid=%u, pid=%d)", + ueid, pid); + + /* Delete the PDN connection entry */ + int pti = _pdn_connectivity_delete(ueid, pid); + if (pti != ESM_PT_UNASSIGNED) { + LOG_FUNC_RETURN (RETURNok); + } + LOG_FUNC_RETURN (RETURNerror); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + *--------------------------------------------------------------------------- + * Timer handlers + *--------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_t3482_handler() ** + ** ** + ** Description: T3482 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 6.5.1.5, case a ** + ** On the first expiry of the timer T3482, the UE shall re- ** + ** send the PDN CONNECTIVITY REQUEST and shall reset and re- ** + ** start timer T3482. This retransmission is repeated four ** + ** times, i.e. on the fifth expiry of timer T3482, the UE ** + ** shall abort the procedure, release the PTI allocated for ** + ** this invocation and enter the state PROCEDURE TRANSACTION ** + ** INACTIVE. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _pdn_connectivity_t3482_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Get retransmission timer parameters data */ + esm_pt_timer_data_t* data = (esm_pt_timer_data_t*)(args); + + /* Increment the retransmission counter */ + data->count += 1; + + LOG_TRACE(WARNING, "ESM-PROC - T3482 timer expired (pti=%d), " + "retransmission counter = %d", data->pti, data->count); + + if (data->count < ESM_PDN_CONNECTIVITY_COUNTER_MAX) { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notify EMM that the PDN connectivity request message + * has to be sent again + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = data->msg.length; + emm_esm->msg.value = data->msg.value; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Restart the timer T3482 */ + rc = esm_pt_start_timer(data->pti, &data->msg, T3482_DEFAULT_VALUE, + _pdn_connectivity_t3482_handler); + } + } + else { + /* Set the procedure transaction state to INACTIVE */ + rc = esm_pt_set_status(data->pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already INACTIVE", + data->pti); + } + else { + /* Release the transaction identity assigned to this procedure */ + rc = esm_pt_release(data->pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", + data->pti); + } + } + } + + LOG_FUNC_RETURN(NULL); +} + +/* + *--------------------------------------------------------------------------- + * PDN connection handlers + *--------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_create() ** + ** ** + ** Description: Creates a new PDN connection entry or updates existing ** + ** non-active PDN connection entry ** + ** ** + ** Inputs: pid: Identifier of the PDN connection entry ** + ** apn: Access Point Name of the PDN connection ** + ** pdn_type: PDN type (IPv4, IPv6, IPv4v6) ** + ** is_emergency: TRUE if the PDN connection has to be esta- ** + ** blished for emergency bearer services ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_create(int pid, const OctetString* apn, + esm_proc_pdn_type_t pdn_type, + int is_emergency) +{ + esm_pdn_t* pdn = NULL; + + LOG_TRACE(INFO, "ESM-PROC - Create new PDN connection (pid=%d)", pid); + + if (pid >= ESM_DATA_PDN_MAX) { + return (RETURNerror); + } + else if (_esm_data.pdn[pid].is_active) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection is active"); + return (RETURNerror); + } + + if (_esm_data.pdn[pid].data != NULL) { + /* Update existing non-active PDN connection */ + pdn = _esm_data.pdn[pid].data; + } else { + /* Create new PDN connection */ + pdn = (esm_pdn_t*)malloc(sizeof(esm_pdn_t)); + if (pdn == NULL) { + LOG_TRACE(WARNING, "ESM-PROC - " + "Failed to create new PDN connection"); + return (RETURNerror); + } + memset(pdn, 0, sizeof(esm_pdn_t)); + /* Increment the number of PDN connections */ + _esm_data.n_pdns += 1; + /* Set the PDN connection identifier */ + _esm_data.pdn[pid].pid = pid; + /* Reset the PDN connection active indicator */ + _esm_data.pdn[pid].is_active = FALSE; + /* Setup the PDN connection data */ + _esm_data.pdn[pid].data = pdn; + } + + /* Update the PDN connection data */ + pdn->is_emergency = is_emergency; + if ( apn && (apn->length > 0) ) { + if (pdn->apn.length > 0) { + free(pdn->apn.value); + pdn->apn.length = 0; + } + pdn->apn.value = (uint8_t*)malloc(apn->length + 1); + if (pdn->apn.value) { + pdn->apn.length = apn->length; + memcpy(pdn->apn.value, apn->value, apn->length); + pdn->apn.value[pdn->apn.length] = '\0'; + } + } + pdn->type = pdn_type; + pdn->addr_realloc = FALSE; + + return (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_update() ** + ** ** + ** Description: Updates PDN connection entry with the given identifier ** + ** ** + ** Inputs: pid: Identifier of the PDN connection entry ** + ** pdn_type: PDN type (IPv4, IPv6, IPv4v6) ** + ** pdn_addr: Network allocated PDN IPv4 or IPv6 address ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_update(int pid, const OctetString* apn, + esm_proc_pdn_type_t pdn_type, + const OctetString* pdn_addr, + int esm_cause) +{ + LOG_TRACE(INFO, "ESM-PROC - Update PDN connection (pid=%d)", pid); + + if (pid >= ESM_DATA_PDN_MAX) { + return (RETURNerror); + } + else if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier is not valid"); + return (RETURNerror); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection has not been allocated"); + return (RETURNerror); + } + else if (_esm_data.pdn[pid].is_active) { + LOG_TRACE(WARNING, "ESM-PROC - Active %s PDN connection to %s already " + "exists", (_esm_data.pdn[pid].data->type != ESM_PDN_TYPE_IPV4)? + "IPv6" : "IPv4", _esm_data.pdn[pid].data->apn.value); + return (RETURNerror); + } + + /* Get the PDN connection */ + esm_pdn_t* pdn = _esm_data.pdn[pid].data; + /* Setup the Access Point Name value */ + if ( apn && (apn->length > 0) ) { + if (pdn->apn.length > 0) { + free(pdn->apn.value); + pdn->apn.length = 0; + } + pdn->apn.value = (uint8_t*)malloc(apn->length + 1); + if (pdn->apn.value) { + pdn->apn.length = apn->length; + memcpy(pdn->apn.value, apn->value, apn->length); + pdn->apn.value[pdn->apn.length] = '\0'; + } + } + /* Setup the IP address allocated by the network */ + if ( pdn_addr && (pdn_addr->length > 0) ) { + int length = ((pdn_addr->length < ESM_DATA_IP_ADDRESS_SIZE) ? + pdn_addr->length : ESM_DATA_IP_ADDRESS_SIZE); + memcpy(pdn->ip_addr, pdn_addr->value, length); + pdn->type = pdn_type; + } + /* + * 3GPP TS 24.301, section 6.2.2 + * Update the address re-allocation indicator + */ + if (esm_cause == ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED) { + /* The UE requested IPv4 or IPv6 address and the network allows + * single addressing per bearer: + * The UE should subsequently request another PDN connection for + * the other IP version using the UE requested PDN connectivity + * procedure to the same APN with a single address PDN type + * (IPv4 or IPv6) other than the one already activated */ + pdn->addr_realloc = TRUE; + } + else if ( (esm_cause == ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED) || + (esm_cause == ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED) ) { + /* The UE requested IPv4 or IPv6 address and the network allows + * IPv4 or IPv6 PDN address only: + * The UE shall not subsequently initiate another UE requested + * PDN connectivity procedure to the same APN to obtain a PDN + * type different from the one allowed by the network */ + pdn->addr_realloc = FALSE; + } + else if (pdn_type != ESM_PDN_TYPE_IPV4V6) { + pdn->addr_realloc = TRUE; + } + + return (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_delete() ** + ** ** + ** Description: Deletes the PDN connection entry with given identifier ** + ** ** + ** Inputs: pid: Identifier of the PDN connection to be ** + ** released ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identity of the procedure transaction ** + ** assigned to the PDN connection when suc- ** + ** cessfully released; ** + ** UNASSIGNED value otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_delete(int pid) +{ + int pti = ESM_PT_UNASSIGNED; + + if (pid < ESM_DATA_PDN_MAX) + { + if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection identifier is not valid"); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection has not been allocated"); + } + else if (_esm_data.pdn[pid].is_active) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection is active"); + } + else { + /* Get the identity of the procedure transaction that created + * the PDN connection */ + pti = _esm_data.pdn[pid].data->pti; + } + } + + if (pti != ESM_PT_UNASSIGNED) { + /* Decrement the number of PDN connections */ + _esm_data.n_pdns -= 1; + /* Set the PDN connection as available */ + _esm_data.pdn[pid].pid = -1; + /* Release allocated PDN connection data */ + if (_esm_data.pdn[pid].data->apn.length > 0) { + free(_esm_data.pdn[pid].data->apn.value); + } + free(_esm_data.pdn[pid].data); + _esm_data.pdn[pid].data = NULL; + LOG_TRACE(WARNING, "ESM-PROC - PDN connection %d released", pid); + } + + /* Return the procedure transaction identity */ + return (pti); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_set_pti() ** + ** ** + ** Description: Update the procedure transaction identity assigned to the ** + ** PDN connection entry with the given identifier ** + ** ** + ** Inputs: pid: PDN connection identifier ** + ** pti: Procedure transaction identity ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_set_pti(int pid, int pti) +{ + if (pid < ESM_DATA_PDN_MAX) + { + if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection identifier is not valid"); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection has not been allocated"); + } + else if (_esm_data.pdn[pid].is_active) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection is active"); + } + else { + /* Update the identity of the procedure transaction assigned to + * the PDN connection */ + _esm_data.pdn[pid].data->pti = pti; + return (RETURNok); + } + } + + return (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_find_apn() ** + ** ** + ** Description: Search the list of PDN connections for an entry defined ** + ** for the specified APN ** + ** ** + ** Inputs: apn: Access Point Name of the PDN connection ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection if ** + ** found in the list; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_find_apn(const OctetString* apn) +{ + int i; + + for (i = 0; i < ESM_DATA_PDN_MAX; i++) + { + if ( (_esm_data.pdn[i].pid != -1) && _esm_data.pdn[i].data ) { + if (_esm_data.pdn[i].data->apn.length != apn->length) { + continue; + } + if (memcmp(_esm_data.pdn[i].data->apn.value, + apn->value, apn->length) != 0) { + continue; + } + /* PDN entry found */ + break; + } + } + + /* Return the identifier of the PDN connection */ + return (_esm_data.pdn[i].pid); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_find_pdn() ** + ** ** + ** Description: Search the list of PDN connections for an entry defined ** + ** for the specified APN with the same PDN type ** + ** ** + ** Inputs: apn: Access Point Name of the PDN connection ** + ** pdn_type: PDN address type ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection if ** + ** found in the list; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_find_pdn(const OctetString* apn, + const esm_proc_pdn_type_t pdn_type) +{ + int i; + + for (i = 0; i < ESM_DATA_PDN_MAX; i++) + { + if ( (_esm_data.pdn[i].pid != -1) && _esm_data.pdn[i].data ) { + /* PDN connection established during initial network attachment */ + if (_esm_data.pdn[i].data->apn.length == 0) { + break; + } + /* Subsequent PDN connection established for the specified APN */ + if (_esm_data.pdn[i].data->apn.length != apn->length) { + continue; + } + if (memcmp(_esm_data.pdn[i].data->apn.value, + apn->value, apn->length) != 0) { + continue; + } + if (_esm_data.pdn[i].data->type == ESM_PDN_TYPE_IPV4V6) { + break; + } + if (_esm_data.pdn[i].data->type == pdn_type) { + break; + } + } + } + + /* Return the identifier of the PDN connection */ + return (_esm_data.pdn[i].pid); +} +#endif // NAS_UE + +#ifdef NAS_MME +/* + *--------------------------------------------------------------------------- + * PDN connection handlers + *--------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_create() ** + ** ** + ** Description: Creates a new PDN connection entry for the specified UE ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** apn: Access Point Name of the PDN connection ** + ** pdn_type: PDN type (IPv4, IPv6, IPv4v6) ** + ** pdn_addr: Network allocated PDN IPv4 or IPv6 address ** + ** is_emergency: TRUE if the PDN connection has to be esta- ** + ** blished for emergency bearer services ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection if ** + ** successfully created; -1 otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +static int _pdn_connectivity_create(unsigned int ueid, int pti, + const OctetString* apn, + esm_proc_pdn_type_t pdn_type, + const OctetString* pdn_addr, + int is_emergency) +{ + int pid = ESM_DATA_PDN_MAX; + + LOG_TRACE(INFO, "ESM-PROC - Create new PDN connection " + "(pti=%d) APN = %s, IP address = %s (ueid=%u)", pti, apn->value, + (pdn_type == ESM_PDN_TYPE_IPV4)? esm_data_get_ipv4_addr(pdn_addr) : + (pdn_type == ESM_PDN_TYPE_IPV6)? esm_data_get_ipv6_addr(pdn_addr) : + esm_data_get_ipv4v6_addr(pdn_addr), ueid); + + if (ueid < ESM_DATA_NB_UE_MAX) + { + if (_esm_data.ctx[ueid] == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - ESM context has not been allocated"); + } + else if (_esm_data.ctx[ueid]->n_pdns > ESM_DATA_PDN_MAX) { + LOG_TRACE(WARNING, "ESM-PROC - Number of PDN connection exceeded"); + } + else if (_esm_data.ctx[ueid]->emergency && is_emergency) { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection for emergency bearer " + "services already established"); + } + else { + /* Search for an available PDN connection entry */ + for (pid = 0; pid < ESM_DATA_PDN_MAX; pid++) { + if (_esm_data.ctx[ueid]->pdn[pid].data != NULL) continue; + break; + } + } + } + + if (pid < ESM_DATA_PDN_MAX) + { + /* Create new PDN connection */ + esm_pdn_t* pdn = (esm_pdn_t*)malloc(sizeof(esm_pdn_t)); + if (pdn != NULL) { + memset(pdn, 0, sizeof(esm_pdn_t)); + /* Increment the number of PDN connections */ + _esm_data.ctx[ueid]->n_pdns += 1; + /* Set the PDN connection identifier */ + _esm_data.ctx[ueid]->pdn[pid].pid = pid; + /* Reset the PDN connection active indicator */ + _esm_data.ctx[ueid]->pdn[pid].is_active = FALSE; + /* Setup the PDN connection data */ + _esm_data.ctx[ueid]->pdn[pid].data = pdn; + + /* Set the procedure transaction identity */ + pdn->pti = pti; + /* Set the emergency bearer services indicator */ + pdn->is_emergency = is_emergency; + /* Setup the Access Point Name */ + if ( apn && (apn->length > 0) ) { + pdn->apn.value = (uint8_t*)malloc(apn->length + 1); + if (pdn->apn.value) { + pdn->apn.length = apn->length; + memcpy(pdn->apn.value, apn->value, apn->length); + pdn->apn.value[pdn->apn.length] = '\0'; + } + } + /* Setup the IP address allocated by the network */ + if ( pdn_addr && (pdn_addr->length > 0) ) { + int length = + ((pdn_addr->length < ESM_DATA_IP_ADDRESS_SIZE) ? + pdn_addr->length : ESM_DATA_IP_ADDRESS_SIZE); + memcpy(pdn->ip_addr, pdn_addr->value, length); + pdn->type = pdn_type; + } + /* Return the identifier of the new PDN connection */ + return (_esm_data.ctx[ueid]->pdn[pid].pid); + } + LOG_TRACE(WARNING, "ESM-PROC - Failed to create new PDN connection " + "(pid=%d)", pid); + } + + return (-1); +} + +/**************************************************************************** + ** ** + ** Name: _pdn_connectivity_delete() ** + ** ** + ** Description: Deletes PDN connection to the specified UE associated to ** + ** PDN connection entry with given identifier ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pid: Identifier of the PDN connection to be ** + ** released ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identity of the procedure transaction ** + ** assigned to the PDN connection when suc- ** + ** cessfully released; ** + ** UNASSIGNED value otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +int _pdn_connectivity_delete(unsigned int ueid, int pid) +{ + int pti = ESM_PT_UNASSIGNED; + + if (ueid < ESM_DATA_NB_UE_MAX) + { + if (_esm_data.ctx[ueid] == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - ESM context has not been allocated"); + } + else if (pid < ESM_DATA_PDN_MAX) { + if (pid != _esm_data.ctx[ueid]->pdn[pid].pid) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection identifier is not valid"); + } + else if (_esm_data.ctx[ueid]->pdn[pid].data == NULL) { + LOG_TRACE(ERROR, + "ESM-PROC - PDN connection has not been allocated"); + } + else if (_esm_data.ctx[ueid]->pdn[pid].is_active) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection is active"); + } + else { + /* Get the identity of the procedure transaction that created + * the PDN connection */ + pti = _esm_data.ctx[ueid]->pdn[pid].data->pti; + } + } + } + + if (pti != ESM_PT_UNASSIGNED) + { + /* Decrement the number of PDN connections */ + _esm_data.ctx[ueid]->n_pdns -= 1; + /* Set the PDN connection as available */ + _esm_data.ctx[ueid]->pdn[pid].pid = -1; + /* Release allocated PDN connection data */ + if (_esm_data.ctx[ueid]->pdn[pid].data->apn.length > 0) { + free(_esm_data.ctx[ueid]->pdn[pid].data->apn.value); + } + free(_esm_data.ctx[ueid]->pdn[pid].data); + _esm_data.ctx[ueid]->pdn[pid].data = NULL; + LOG_TRACE(WARNING, "ESM-PROC - PDN connection %d released", pid); + } + + /* Return the procedure transaction identity */ + return (pti); +} + +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/PdnDisconnect.c b/openair-cn/NAS/EURECOM-NAS/src/esm/PdnDisconnect.c new file mode 100644 index 0000000000..6feb909a03 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/PdnDisconnect.c @@ -0,0 +1,702 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source PdnDisconnect.c + +Version 0.1 + +Date 2013/05/15 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the PDN disconnect ESM procedure executed by the + Non-Access Stratum. + + The PDN disconnect procedure is used by the UE to request + disconnection from one PDN. + + All EPS bearer contexts established towards this PDN, inclu- + ding the default EPS bearer context, are released. + +*****************************************************************************/ + +#include "esm_proc.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esmData.h" +#include "esm_cause.h" +#include "esm_pt.h" + +#ifdef NAS_UE +#include "esm_sap.h" +#endif + +#include "emm_sap.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#ifdef NAS_MME +extern int _pdn_connectivity_delete(unsigned int ueid, int pid); +#endif + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the PDN disconnect procedure in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * PDN disconnection handlers + */ +static int _pdn_disconnect_get_default_ebi(int pti); + +/* + * Timer handlers + */ +static void* _pdn_disconnect_t3492_handler(void*); + +/* Maximum value of the PDN disconnect request retransmission counter */ +#define ESM_PDN_DISCONNECT_COUNTER_MAX 5 + +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Internal data handled by the PDN disconnect procedure in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * PDN disconnection handlers + */ +static int _pdn_disconnect_get_pid(unsigned int ueid, int pti); + +#endif // NAS_MME + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * PDN disconnect procedure executed by the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect() ** + ** ** + ** Description: Return the procedure transaction identity assigned to the ** + ** PDN connection and the EPS bearer identity of the default ** + ** bearer associated to the PDN context with specified iden- ** + ** tifier ** + ** ** + ** Inputs: cid: PDN context identifier ** + ** Others: _esm_data ** + ** ** + ** Outputs: pti: Procedure transaction identity assigned to ** + ** the PDN connection to be released ** + ** ebi: EPS bearer identity of the default bearer ** + ** associated to the specified PDN context ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect(int cid, unsigned int* pti, unsigned int* ebi) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int pid = cid - 1; + + if (pid < ESM_DATA_PDN_MAX) { + if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection identifier %d is " + "not valid", pid); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", pid); + } + else if (!_esm_data.pdn[pid].is_active) { + LOG_TRACE(WARNING, "ESM-PROC - PDN connection is not active"); + } + else { + /* Get the procedure transaction identity assigned to the PDN + * connection to be released */ + *pti = _esm_data.pdn[pid].data->pti; + /* Get the EPS bearer identity of the default bearer associated + * with the PDN to disconnect from */ + *ebi = _esm_data.pdn[pid].data->bearer[0]->ebi; + rc = RETURNok; + } + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_request() ** + ** ** + ** Description: Initiates PDN disconnection procedure in order to request ** + ** disconnection from a PDN. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.2 ** + ** The UE requests PDN disconnection from a PDN by sending a ** + ** PDN DISCONNECT REQUEST message to the MME, starting timer ** + ** T3492 and entering state PROCEDURE TRANSACTION PENDING. ** + ** ** + ** Inputs: is_standalone: Should be always TRUE ** + ** pti: Procedure transaction identity ** + ** msg: Encoded PDN disconnect request message to ** + ** be sent ** + ** sent_by_ue: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_request(int is_standalone, int pti, + OctetString* msg, int sent_by_ue) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + LOG_TRACE(INFO, "ESM-PROC - Initiate PDN disconnection (pti=%d)", pti); + + if (is_standalone) + { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = msg->length; + emm_esm->msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Start T3482 retransmission timer */ + rc = esm_pt_start_timer(pti, msg, T3492_DEFAULT_VALUE, + _pdn_disconnect_t3492_handler); + } + } + + if (rc != RETURNerror) { + /* Set the procedure transaction state to PENDING */ + rc = esm_pt_set_status(pti, ESM_PT_PENDING); + if (rc != RETURNok) { + /* The procedure transaction was already in PENDING state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already PENDING", pti); + } + } + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_accept() ** + ** ** + ** Description: Performs PDN disconnection procedure accepted by the net- ** + ** work. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.3 ** + ** The shall stop timer T3492 and enter the state PROCEDURE ** + ** TRANSACTION INACTIVE. ** + ** ** + ** Inputs: pti: Identifies the UE requested PDN disconnect ** + ** procedure accepted by the network ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: The identifier of the PDN context to de- ** + ** activate when successfully found; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_accept(int pti, int* esm_cause) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "ESM-PROC - PDN disconnection accepted by the network " + "(pti=%d)", pti); + + /* Stop T3492 timer if running */ + (void) esm_pt_stop_timer(pti); + /* Set the procedure transaction state to INACTIVE */ + int rc = esm_pt_set_status(pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already INACTIVE", pti); + *esm_cause = ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + } + else { + /* Immediately release the transaction identity assigned to this + * procedure */ + rc = esm_pt_release(pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", pti); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_reject() ** + ** ** + ** Description: Performs PDN disconnection procedure not accepted by the ** + ** network. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.4 ** + ** Upon receipt of the PDN DISCONNECT REJECT message, the UE ** + ** shall stop timer T3492 and enter the state PROCEDURE ** + ** TRANSACTION INACTIVE and abort the PDN disconnection pro- ** + ** cedure. ** + ** ** + ** Inputs: pti: Identifies the UE requested PDN disconnec- ** + ** tion procedure rejected by the network ** + ** Others: None ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_reject(int pti, int* esm_cause) +{ + LOG_FUNC_IN; + + int rc; + + LOG_TRACE(WARNING, "ESM-PROC - PDN disconnection rejected by the network " + "(pti=%d), ESM cause = %d", pti, *esm_cause); + + /* Stop T3492 timer if running */ + (void) esm_pt_stop_timer(pti); + /* Set the procedure transaction state to INACTIVE */ + rc = esm_pt_set_status(pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state + * as the request may have already been rejected */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already INACTIVE", pti); + *esm_cause = ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE; + } + else { + /* Release the transaction identity assigned to this procedure */ + rc = esm_pt_release(pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", pti); + *esm_cause = ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED; + } + else if (*esm_cause != ESM_CAUSE_LAST_PDN_DISCONNECTION_NOT_ALLOWED) + { + /* Get the identity of the default EPS bearer context allocated to + * the PDN connection entry assigned to this procedure transaction */ + int ebi = _pdn_disconnect_get_default_ebi(pti); + if (ebi < 0) { + LOG_TRACE(ERROR, "ESM-PROC - No default EPS bearer found"); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (RETURNerror); + } + /* + * Notify ESM that all EPS bearer contexts to this PDN have to be + * locally deactivated + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; + esm_sap.is_standalone = TRUE; + esm_sap.recv = NULL; + esm_sap.send.length = 0; + esm_sap.data.eps_bearer_context_deactivate.ebi = ebi; + rc = esm_sap_send(&esm_sap); + + if (rc != RETURNok) { + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + } + + LOG_FUNC_RETURN(rc); +} + +#endif // NAS_UE + + +/* + * -------------------------------------------------------------------------- + * PDN disconnect procedure executed by the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_request() ** + ** ** + ** Description: Performs PDN disconnect procedure requested by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.3 ** + ** Upon receipt of the PDN DISCONNECT REQUEST message, if it ** + ** is accepted by the network, the MME shall initiate the ** + ** bearer context deactivation procedure. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** pti: Identifies the PDN disconnect procedure ** + ** requested by the UE ** + ** Others: _esm_data ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: The identifier of the PDN connection to be ** + ** released, if it exists; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_request(unsigned int ueid, int pti, int* esm_cause) +{ + LOG_FUNC_IN; + + int pid = RETURNerror; + + LOG_TRACE(INFO, "ESM-PROC - PDN disconnect requested by the UE " + "(ueid=%d, pti=%d)", ueid, pti); + + if (ueid < ESM_DATA_NB_UE_MAX) + { + /* Get UE's ESM context */ + esm_data_context_t* ctx = _esm_data.ctx[ueid]; + if (_esm_data.ctx[ueid] == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - No ESM context exists"); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + else if (ctx->n_pdns > 1) { + /* Get the identifier of the PDN connection entry assigned to the + * procedure transaction identity */ + pid = _pdn_disconnect_get_pid(ueid, pti); + if (pid < 0) { + LOG_TRACE(ERROR, "ESM-PROC - No PDN connection found (pti=%d)", + pti); + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (RETURNerror); + } + } + else { + /* Attempt to disconnect from the last PDN disconnection + * is not allowed */ + *esm_cause = ESM_CAUSE_LAST_PDN_DISCONNECTION_NOT_ALLOWED; + } + } + + LOG_FUNC_RETURN(pid); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_accept() ** + ** ** + ** Description: Performs PDN disconnect procedure accepted by the UE. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.3 ** + ** On reception of DEACTIVATE EPS BEARER CONTEXT ACCEPT mes- ** + ** sage from the UE, the MME releases all the resources re- ** + ** served for the PDN in the network. ** + ** ** + ** Inputs: ueid: UE lower layer identifier ** + ** pid: Identifier of the PDN connection to be ** + ** released ** + ** Others: _esm_data ** + ** ** + ** Outputs: esm_cause: Cause code returned upon ESM procedure ** + ** failure ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_accept(unsigned int ueid, int pid, int* esm_cause) +{ + LOG_FUNC_IN; + + LOG_TRACE(INFO, "ESM-PROC - PDN disconnect accepted by the UE " + "(ueid=%d, pid=%d)", ueid, pid); + + /* Release the connectivity with the requested PDN */ + int rc = mme_api_unsubscribe(NULL); + if (rc != RETURNerror) { + /* Delete the PDN connection entry */ + int pti = _pdn_connectivity_delete(ueid, pid); + if (pti != ESM_PT_UNASSIGNED) { + LOG_FUNC_RETURN (RETURNok); + } + } + *esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_proc_pdn_disconnect_reject() ** + ** ** + ** Description: Performs PDN disconnect procedure not accepted by the ** + ** network. ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.4 ** + ** Upon receipt of the PDN DISCONNECT REQUEST message, if it ** + ** is not accepted by the network, the MME shall send a PDN ** + ** DISCONNECT REJECT message to the UE. ** + ** ** + ** Inputs: is_standalone: Not used - Always TRUE ** + ** ueid: UE lower layer identifier ** + ** ebi: Not used ** + ** msg: Encoded PDN disconnect reject message to ** + ** be sent ** + ** ue_triggered: Not used ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_proc_pdn_disconnect_reject(int is_standalone, unsigned int ueid, + int ebi, OctetString* msg, int ue_triggered) +{ + LOG_FUNC_IN; + + int rc; + emm_sap_t emm_sap; + + LOG_TRACE(WARNING, "ESM-PROC - PDN disconnect not accepted by the network " + "(ueid=%d)", ueid); + + /* + * Notity EMM that ESM PDU has to be forwarded to lower layers + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = ueid; + emm_sap.u.emm_esm.u.data.msg.length = msg->length; + emm_sap.u.emm_esm.u.data.msg.value = msg->value; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN(rc); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Timer handlers + * -------------------------------------------------------------------------- + */ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _pdn_disconnect_t3492_handler() ** + ** ** + ** Description: T3492 timeout handler ** + ** ** + ** 3GPP TS 24.301, section 6.5.2.5, case a ** + ** On the first expiry of the timer T3492, the UE shall re- ** + ** send the PDN DISCONNECT REQUEST and shall reset and re- ** + ** start timer T3492. This retransmission is repeated four ** + ** times, i.e. on the fifth expiry of timer T3492, the UE ** + ** shall abort the procedure, deactivate all EPS bearer con- ** + ** texts for this PDN connection locally, release the PTI ** + ** allocated for this invocation and enter the state PROCE- ** + ** DURE TRANSACTION INACTIVE. ** + ** ** + ** Inputs: args: handler parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void* _pdn_disconnect_t3492_handler(void* args) +{ + LOG_FUNC_IN; + + int rc; + + /* Get retransmission timer parameters data */ + esm_pt_timer_data_t* data = (esm_pt_timer_data_t*)(args); + + /* Increment the retransmission counter */ + data->count += 1; + + LOG_TRACE(WARNING, "ESM-PROC - T3492 timer expired (pti=%d), " + "retransmission counter = %d", data->pti, data->count); + + if (data->count < ESM_PDN_DISCONNECT_COUNTER_MAX) { + emm_sap_t emm_sap; + emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data; + /* + * Notify EMM that the PDN connectivity request message + * has to be sent again + */ + emm_sap.primitive = EMMESM_UNITDATA_REQ; + emm_sap.u.emm_esm.ueid = 0; + emm_esm->msg.length = data->msg.length; + emm_esm->msg.value = data->msg.value; + rc = emm_sap_send(&emm_sap); + + if (rc != RETURNerror) { + /* Restart the timer T3492 */ + rc = esm_pt_start_timer(data->pti, &data->msg, T3492_DEFAULT_VALUE, + _pdn_disconnect_t3492_handler); + } + } + else { + /* Set the procedure transaction state to INACTIVE */ + rc = esm_pt_set_status(data->pti, ESM_PT_INACTIVE); + if (rc != RETURNok) { + /* The procedure transaction was already in INACTIVE state */ + LOG_TRACE(WARNING, "ESM-PROC - PTI %d was already INACTIVE", + data->pti); + } + else { + /* Release the transaction identity assigned to this procedure */ + rc = esm_pt_release(data->pti); + if (rc != RETURNok) { + LOG_TRACE(WARNING, "ESM-PROC - Failed to release PTI %d", + data->pti); + } + else { + /* Get the identity of the default EPS bearer context + * allocated to the PDN connection entry assigned to + * this procedure transaction */ + int ebi = _pdn_disconnect_get_default_ebi(data->pti); + if (ebi < 0) { + LOG_TRACE(ERROR, "ESM-PROC - No default EPS bearer found"); + LOG_FUNC_RETURN (NULL); + } + /* + * Notify ESM that all EPS bearer contexts to this PDN have + * to be locally deactivated + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ; + esm_sap.is_standalone = TRUE; + esm_sap.recv = NULL; + esm_sap.send.length = 0; + esm_sap.data.eps_bearer_context_deactivate.ebi = ebi; + rc = esm_sap_send(&esm_sap); + } + } + } + + LOG_FUNC_RETURN(NULL); +} +#endif // NAS_UE + +/* + *--------------------------------------------------------------------------- + * PDN disconnection handlers + *--------------------------------------------------------------------------- + */ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _pdn_disconnect_get_default_ebi() ** + ** ** + ** Description: Returns the EPS bearer identity of the default EPS bearer ** + ** context allocated to the PDN connection to which the gi- ** + ** ven procedure transaction identity has been assigned ** + ** ** + ** Inputs: pti: The procedure transaction identity ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The EPS bearer identity of the default EPS ** + ** bearer context, if it exists; -1 otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _pdn_disconnect_get_default_ebi(int pti) +{ + int ebi = -1; + + for (int i = 0; i < ESM_DATA_PDN_MAX; i++) { + if ( (_esm_data.pdn[i].pid != -1) && _esm_data.pdn[i].data ) { + if (_esm_data.pdn[i].data->pti != pti) continue; + /* PDN entry found */ + if (_esm_data.pdn[i].data->bearer[0] != NULL) { + /* Get the EPS bearer identity of the default EPS bearer + * context associated to the PDN connection */ + ebi = _esm_data.pdn[i].data->bearer[0]->ebi; + } + break; + } + } + + return (ebi); +} +#endif // NAS_UE + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: _pdn_disconnect_get_pid() ** + ** ** + ** Description: Returns the identifier of the PDN connection to which the ** + ** given procedure transaction identity has been assigned ** + ** to establish connectivity to the specified UE ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: The procedure transaction identity ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection if ** + ** found in the list; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _pdn_disconnect_get_pid(unsigned int ueid, int pti) +{ + int i = ESM_DATA_PDN_MAX; + + if ( (ueid < ESM_DATA_NB_UE_MAX) && (_esm_data.ctx[ueid] != NULL) ) { + for (i = 0; i < ESM_DATA_PDN_MAX; i++) { + if ( (_esm_data.ctx[ueid]->pdn[i].pid != -1) && + (_esm_data.ctx[ueid]->pdn[i].data != NULL) ) { + if (_esm_data.ctx[ueid]->pdn[i].data->pti != pti) continue; + /* PDN entry found */ + break; + } + } + } + + /* Return the identifier of the PDN connection */ + return (_esm_data.ctx[ueid]->pdn[i].pid); +} +#endif // NAS_MME diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esmData.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esmData.h new file mode 100644 index 0000000000..1136e6dac3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esmData.h @@ -0,0 +1,181 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esmData.h + +Version 0.1 + +Date 2012/12/04 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines internal private data handled by EPS Session + Management sublayer. + +*****************************************************************************/ +#ifndef __ESMDATA_H__ +#define __ESMDATA_H__ + +#include "networkDef.h" +#include "OctetString.h" + +#ifdef NAS_MME +#include "mme_api.h" +#endif + +#include <stdio.h> // sprintf + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Total number of active EPS bearers */ +#define ESM_DATA_EPS_BEARER_TOTAL 11 + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Structure of data handled by EPS Session Management sublayer in the UE + * and in the MME + * -------------------------------------------------------------------------- + */ + +/* + * Structure of an EPS bearer + * -------------------------- + * An EPS bearer is a logical concept which applies to the connection + * between two endpoints (UE and PDN Gateway) with specific QoS attri- + * butes. An EPS bearer corresponds to one Quality of Service policy + * applied within the EPC and E-UTRAN. + */ +typedef struct { + int bid; /* Identifier of the EPS bearer */ + unsigned int ebi; /* EPS bearer identity */ + network_qos_t qos; /* EPS bearer level QoS parameters */ + network_tft_t tft; /* Traffic Flow Template for packet filtering */ +} esm_bearer_t; + +/* + * Structure of a PDN connection + * ----------------------------- + * A PDN connection is the association between a UE represented by + * one IPv4 address and/or one IPv6 prefix and a PDN represented by + * an Access Point Name (APN). + */ +typedef struct { + unsigned int pti; /* Identity of the procedure transaction executed + * to activate the PDN connection entry */ + int is_emergency; /* Emergency bearer services indicator */ + OctetString apn; /* Access Point Name currently in used */ + int ambr; /* Aggregate Maximum Bit Rate of this APN */ + int type; /* Address PDN type (IPv4, IPv6, IPv4v6) */ +#define ESM_DATA_IPV4_ADDRESS_SIZE 4 +#define ESM_DATA_IPV6_ADDRESS_SIZE 8 +#define ESM_DATA_IP_ADDRESS_SIZE (ESM_DATA_IPV4_ADDRESS_SIZE + \ + ESM_DATA_IPV6_ADDRESS_SIZE) + /* IPv4 PDN address and/or IPv6 prefix */ + char ip_addr[ESM_DATA_IP_ADDRESS_SIZE+1]; + int addr_realloc; /* Indicates whether the UE is allowed to subsequently + * request another PDN connectivity to the same APN + * using an address PDN type (IPv4 or IPv6) other + * than the one already activated */ + int n_bearers; /* Number of allocated EPS bearers; + * default EPS bearer is defined at index 0 */ +#define ESM_DATA_EPS_BEARER_MAX 4 + esm_bearer_t* bearer[ESM_DATA_EPS_BEARER_MAX]; +} esm_pdn_t; + +/* + * Structure of the ESM data + * ------------------------- + * The EPS Session Management sublayer handles data related to PDN + * connections and EPS bearers. Each active PDN connection has a de- + * fault EPS bearer. Several dedicated EPS bearers may exist within + * a PDN connection. + */ +typedef struct { + int n_ebrs; /* Total number of active EPS bearer contexts */ + int n_pdns; /* Number of active PDN connections */ + int emergency; /* Indicates whether a PDN connection for emergency + * bearer services is established */ +#define ESM_DATA_PDN_MAX 4 + struct { + int pid; /* Identifier of the PDN connection */ + int is_active; /* TRUE/FALSE if the PDN connection is active/inactive + * or the process to activate/deactivate the PDN + * connection is in progress */ + esm_pdn_t* data; /* Active PDN connection data */ + } pdn[ESM_DATA_PDN_MAX+1]; +} esm_data_context_t; + +/* + * -------------------------------------------------------------------------- + * ESM internal data handled by EPS Session Management sublayer in the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Structure of the ESM data + * ------------------------- + */ +typedef esm_data_context_t esm_data_t; +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * ESM internal data handled by EPS Session Management sublayer in the MME + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Structure of the ESM data + * ------------------------- + */ +typedef struct { + /* + * MME configuration + * ----------------- + */ + mme_api_esm_config_t conf; + /* + * ESM contexts + * ------------ + */ +#define ESM_DATA_NB_UE_MAX (MME_API_NB_UE_MAX + 1) + esm_data_context_t* ctx[ESM_DATA_NB_UE_MAX]; + +} esm_data_t; + +#endif //NAS_MME + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/* + * ESM internal data (used within ESM only) + * ---------------------------------------- + */ +esm_data_t _esm_data; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +extern char ip_addr_str[100]; + +extern inline char* esm_data_get_ipv4_addr(const OctetString* ip_addr); + +extern inline char* esm_data_get_ipv6_addr(const OctetString* ip_addr); + +extern inline char* esm_data_get_ipv4v6_addr(const OctetString* ip_addr); + +#endif /* __ESMDATA_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.c b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.c new file mode 100644 index 0000000000..55cc629dfd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.c @@ -0,0 +1,704 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_ebr.c + +Version 0.1 + +Date 2013/01/29 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle state of EPS bearer contexts + and manage ESM messages re-transmission. + +*****************************************************************************/ + +#include "esm_ebr.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "mme_api.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/* + * Minimal and maximal value of an EPS bearer identity: + * The EPS Bearer Identity (EBI) identifies a message flow + */ +#define ESM_EBI_MIN (EPS_BEARER_IDENTITY_FIRST) +#define ESM_EBI_MAX (EPS_BEARER_IDENTITY_LAST) + +#ifdef NAS_UE +#define ESM_EBR_NB_UE_MAX 1 +#endif +#ifdef NAS_MME +#define ESM_EBR_NB_UE_MAX (MME_API_NB_UE_MAX + 1) +#endif + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* String representation of EPS bearer context status */ +static const char* _esm_ebr_state_str[ESM_EBR_STATE_MAX] = { + "BEARER CONTEXT INACTIVE", + "BEARER CONTEXT ACTIVE", +#ifdef NAS_MME + "BEARER CONTEXT INACTIVE PENDING", + "BEARER CONTEXT MODIFY PENDING", + "BEARER CONTEXT ACTIVE PENDING" +#endif +}; + +/* + * ----------------------- + * EPS bearer context data + * ----------------------- + */ +typedef struct { + unsigned char ebi; /* EPS bearer identity */ + esm_ebr_state status; /* EPS bearer context status */ +#ifdef NAS_UE + int is_default_ebr; /* TRUE if the bearer context is associated + * to a default EPS bearer */ + char cid; /* Identifier of the PDN context the EPS + * bearer context has been assigned to */ +#endif +#ifdef NAS_MME + struct nas_timer_t timer; /* Retransmission timer */ + esm_ebr_timer_data_t* args; /* Retransmission timer parameters data */ +#endif +} esm_ebr_context_t; + +/* + * ---------------------------------- + * List of EPS bearer contexts per UE + * ---------------------------------- + */ +static struct { + unsigned char index; /* Index of the next EPS bearer context + * identity to be used */ +#define ESM_EBR_DATA_SIZE (ESM_EBI_MAX - ESM_EBI_MIN + 1) + esm_ebr_context_t* context[ESM_EBR_DATA_SIZE + 1]; +} _esm_ebr_data[ESM_EBR_NB_UE_MAX]; + +/* + * ---------------------- + * User notification data + * ---------------------- + */ +#ifdef NAS_UE +/* User notification callback executed whenever an EPS bearer context becomes + * active or inactive */ +static esm_indication_callback_t _esm_ebr_callback; +/* PDN connection and EPS bearer status [NW/UE][Dedicated/Default][status] */ +static const network_pdn_state_t _esm_ebr_pdn_state[2][2][2] = { + /* Status modification triggerer by the network */ + { + /* Dedicated EPS bearer */ + {NET_PDN_NW_DEDICATED_DEACT, NET_PDN_NW_DEDICATED_ACT}, + /* Default EPS bearer */ + {NET_PDN_NW_DEFAULT_DEACT, 0} + }, + /* Status modification triggered by the UE */ + { + /* Dedicated EPS bearer */ + {NET_PDN_MT_DEDICATED_DEACT, NET_PDN_MT_DEDICATED_ACT}, + /* Default EPS bearer */ + {NET_PDN_MT_DEFAULT_DEACT, NET_PDN_MT_DEFAULT_ACT} + } +}; +#endif + +/* Returns the index of the next available entry in the list of EPS bearer + * context data */ +static int _esm_ebr_get_available_entry(unsigned int ueid); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: esm_ebr_initialize() ** + ** ** + ** Description: Initialize EPS bearer context data ** + ** ** + ** Inputs: cb: User notification callback ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +void esm_ebr_initialize( +#ifdef NAS_UE + esm_indication_callback_t cb +#endif + ) +{ + int ueid, i; + LOG_FUNC_IN; + + for (ueid = 0; ueid < ESM_EBR_NB_UE_MAX; ueid++) { + _esm_ebr_data[ueid].index = 0; + /* Initialize EPS bearer context data */ + for (i = 0; i < ESM_EBR_DATA_SIZE + 1; i++) { + _esm_ebr_data[ueid].context[i] = NULL; + } + } +#ifdef NAS_UE + /* Initialize the user notification callback */ + _esm_ebr_callback = *cb; +#endif + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_assign() ** + ** ** + ** Description: Assigns a new EPS bearer context ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: Identity of the new EPS bearer context ** + ** cid: Identifier of the PDN context the EPS bea- ** + ** rer context is associated to ** + ** default_ebr TRUE if the new bearer context is associa- ** + ** ted to a default EPS bearer ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The identity of the new EPS bearer context ** + ** if successfully assigned; ** + ** the not assigned EBI (0) otherwise. ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +#ifdef NAS_UE +int esm_ebr_assign(int ebi, int cid, int default_ebr) +#endif +#ifdef NAS_MME +int esm_ebr_assign(unsigned int ueid, int ebi) +#endif +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + + int i; + + if (ueid >= ESM_EBR_NB_UE_MAX) { + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } + + if (ebi != ESM_EBI_UNASSIGNED) { + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } + else if (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN] != NULL) { + LOG_TRACE(WARNING, "ESM-FSM - EPS bearer context already " + "assigned (ebi=%d)", ebi); + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } + /* The specified EPS bearer context is available */ + i = ebi - ESM_EBI_MIN; + } + else + { + /* Search for an available EPS bearer identity */ + i = _esm_ebr_get_available_entry(ueid); + if (i < 0) { + LOG_FUNC_RETURN(ESM_EBI_UNASSIGNED); + } + /* An available EPS bearer context is found */ + ebi = i + ESM_EBI_MIN; + } + + /* Assign new EPS bearer context */ + _esm_ebr_data[ueid].context[i] = + (esm_ebr_context_t*)malloc(sizeof(esm_ebr_context_t)); + if (_esm_ebr_data[ueid].context[i] == NULL) { + LOG_FUNC_RETURN(ESM_EBI_UNASSIGNED); + } + /* Store the index of the next available EPS bearer identity */ + _esm_ebr_data[ueid].index = i + 1; + + /* Set the EPS bearer identity */ + _esm_ebr_data[ueid].context[i]->ebi = ebi; + /* Set the EPS bearer context status to INACTIVE */ + _esm_ebr_data[ueid].context[i]->status = ESM_EBR_INACTIVE; +#ifdef NAS_UE + /* Set the default EPS bearer indicator */ + _esm_ebr_data[ueid].context[i]->is_default_ebr = default_ebr; + /* Set the identifier of the PDN context the EPS bearer is assigned to */ + _esm_ebr_data[ueid].context[i]->cid = cid; +#endif +#ifdef NAS_MME + /* Disable the retransmission timer */ + _esm_ebr_data[ueid].context[i]->timer.id = NAS_TIMER_INACTIVE_ID; + /* Setup retransmission timer parameters */ + _esm_ebr_data[ueid].context[i]->args = NULL; +#endif + + LOG_TRACE(INFO, "ESM-FSM - EPS bearer context %d assigned", ebi); + LOG_FUNC_RETURN(_esm_ebr_data[ueid].context[i]->ebi); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_release() ** + ** ** + ** Description: Release the given EPS bearer identity ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer context to ** + ** be released ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok if the EPS bearer context has ** + ** been successfully released; ** + ** RETURNerror otherwise. ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +int esm_ebr_release( +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + + if (ueid >= ESM_EBR_NB_UE_MAX) { + LOG_FUNC_RETURN (RETURNerror); + } + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get EPS bearer context data */ + esm_ebr_context_t* ctx = _esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]; + if ( (ctx == NULL) || (ctx->ebi != ebi) ) { + /* EPS bearer context not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + /* Do not release active EPS bearer context */ + if (ctx->status != ESM_EBR_INACTIVE) { + LOG_TRACE(ERROR, "ESM-FSM - EPS bearer context is not INACTIVE"); + LOG_FUNC_RETURN (RETURNerror); + } + +#ifdef NAS_MME + /* Stop the retransmission timer if still running */ + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d", + ctx->timer.id); + ctx->timer.id = nas_timer_stop(ctx->timer.id); + } + /* Release the retransmisison timer parameters */ + if (ctx->args) { + if (ctx->args->msg.length > 0) { + free(ctx->args->msg.value); + } + free(ctx->args); + ctx->args = NULL; + } +#endif + + /* Release EPS bearer context data */ + free(_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]); + _esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN] = NULL; + + LOG_TRACE(INFO, "ESM-FSM - EPS bearer context %d released", ebi); + LOG_FUNC_RETURN (RETURNok); +} + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_ebr_start_timer() ** + ** ** + ** Description: Start the timer of the specified EPS bearer context to ** + ** expire after a given time interval. Timer expiration will ** + ** schedule execution of the callback function where stored ** + ** ESM message should be re-transmit. ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer ** + ** msg: The encoded ESM message to be stored ** + ** sec: The value of the time interval in seconds ** + ** cb: Function executed upon timer expiration ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +int esm_ebr_start_timer( unsigned int ueid, int ebi, const OctetString* msg, + long sec, nas_timer_callback_t cb) +{ + LOG_FUNC_IN; + + if (ueid >= ESM_EBR_NB_UE_MAX) { + LOG_FUNC_RETURN (RETURNerror); + } + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get EPS bearer context data */ + esm_ebr_context_t* ctx = _esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]; + if ( (ctx == NULL) || (ctx->ebi != ebi) ) { + /* EPS bearer context not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + if (ctx->args) { + /* Re-start the retransmission timer */ + ctx->timer.id = nas_timer_restart(ctx->timer.id); + } + } + else { + /* Setup the retransmission timer parameters */ + ctx->args = (esm_ebr_timer_data_t*)malloc(sizeof(esm_ebr_timer_data_t)); + if (ctx->args) { + /* Set the UE identifier */ + ctx->args->ueid = ueid; + /* Set the EPS bearer identity */ + ctx->args->ebi = ebi; + /* Reset the retransmission counter */ + ctx->args->count = 0; + /* Set the ESM message to be re-transmited */ + ctx->args->msg.value = (uint8_t*)malloc(msg->length); + ctx->args->msg.length = 0; + if (ctx->args->msg.value) { + memcpy(ctx->args->msg.value, msg->value, msg->length); + ctx->args->msg.length = msg->length; + } + /* Setup the retransmission timer to expire at the given + * time interval */ + ctx->timer.id = nas_timer_start(sec, cb, ctx->args); + ctx->timer.sec = sec; + } + } + + if ( (ctx->args != NULL) && (ctx->timer.id != NAS_TIMER_INACTIVE_ID) ) { + LOG_TRACE(INFO, "ESM-FSM - Retransmission timer %d expires in " + "%ld seconds", ctx->timer.id, ctx->timer.sec); + LOG_FUNC_RETURN (RETURNok); + } + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_stop_timer() ** + ** ** + ** Description: Stop the timer previously started for the given EPS bea- ** + ** rer context ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +int esm_ebr_stop_timer( unsigned int ueid, int ebi) +{ + LOG_FUNC_IN; + + if (ueid >= ESM_EBR_NB_UE_MAX) { + LOG_FUNC_RETURN (RETURNerror); + } + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get EPS bearer context data */ + esm_ebr_context_t* ctx = _esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]; + if ( (ctx == NULL) || (ctx->ebi != ebi) ) { + /* EPS bearer context not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + + /* Stop the retransmission timer if still running */ + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d", + ctx->timer.id); + ctx->timer.id = nas_timer_stop(ctx->timer.id); + } + + /* Release the retransmisison timer parameters */ + if (ctx->args) { + if (ctx->args->msg.length > 0) { + free(ctx->args->msg.value); + } + free(ctx->args); + ctx->args = NULL; + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_get_pending_ebi() ** + ** ** + ** Description: Returns the EPS bearer identity assigned to the first EPS ** + ** bearer context entry which is pending in the given state ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** status: The EPS bearer context status ** + ** Others: _esm_ebr_data ** + ** ** + ** Outputs: None ** + ** Return: The EPS bearer identity of the EPS bearer ** + ** context entry if it exists; ** + ** the not assigned EBI (0) otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_ebr_get_pending_ebi(unsigned int ueid, esm_ebr_state status) +{ + LOG_FUNC_IN; + + int i; + for (i = 0; i < ESM_EBR_DATA_SIZE; i++) { + if (_esm_ebr_data[ueid].context[i] == NULL) continue; + if (_esm_ebr_data[ueid].context[i]->status != status) continue; + /* EPS bearer context entry found */ + break; + } + + if (i < ESM_EBR_DATA_SIZE) { + LOG_FUNC_RETURN (_esm_ebr_data[ueid].context[i]->ebi); + } + /* EPS bearer context entry not found */ + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); +} +#endif + +/**************************************************************************** + ** ** + ** Name: esm_ebr_set_status() ** + ** ** + ** Description: Set the status of the specified EPS bearer context to the ** + ** given state ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer ** + ** status: The new EPS bearer context status ** + ** ue_requested: TRUE/FALSE if the modification of the EPS ** + ** bearer context status was requested by the ** + ** UE/network ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_ebr_data ** + ** ** + ***************************************************************************/ +int esm_ebr_set_status( +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi, esm_ebr_state status, int ue_requested) +{ + LOG_FUNC_IN; + + esm_ebr_state old_status; + +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + + if (ueid >= ESM_EBR_NB_UE_MAX) { + LOG_FUNC_RETURN (RETURNerror); + } + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get EPS bearer context data */ + esm_ebr_context_t* ctx = _esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]; + if ( (ctx == NULL) || (ctx->ebi != ebi) ) { + /* EPS bearer context not assigned */ + LOG_TRACE(ERROR, "ESM-FSM - EPS bearer context not assigned " + "(ebi=%d)", ebi); + LOG_FUNC_RETURN (RETURNerror); + } + + old_status = ctx->status; + if (status < ESM_EBR_STATE_MAX) { + LOG_TRACE(INFO, "ESM-FSM - Status of EPS bearer context %d changed:" + " %s ===> %s", ebi, + _esm_ebr_state_str[old_status], _esm_ebr_state_str[status]); + if (status != old_status) { + ctx->status = status; +#ifdef NAS_UE + /* + * Notify the user that the state of the EPS bearer has changed + */ + (*_esm_ebr_callback)(ctx->cid, + _esm_ebr_pdn_state[ue_requested][ctx->is_default_ebr][status]); +#endif + LOG_FUNC_RETURN (RETURNok); + } + } + + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_get_status() ** + ** ** + ** Description: Get the current status value of the specified EPS bearer ** + ** context ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer ** + ** Others: _esm_ebr_data ** + ** ** + ** Outputs: None ** + ** Return: The current value of the EPS bearer con- ** + ** text status ** + ** Others: None ** + ** ** + ***************************************************************************/ +esm_ebr_state esm_ebr_get_status( +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi) +{ +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + + if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { + return (ESM_EBR_INACTIVE); + } + if (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN] == NULL) { + /* EPS bearer context not allocated */ + return (ESM_EBR_INACTIVE); + } + if (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]->ebi != ebi) { + /* EPS bearer context not assigned */ + return (ESM_EBR_INACTIVE); + } + return (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]->status); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_is_reserved() ** + ** ** + ** Description: Check whether the given EPS bearer identity is a reserved ** + ** value ** + ** ** + ** Inputs: ebi: The identity of the EPS bearer ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE, FALSE ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_ebr_is_reserved(int ebi) +{ + return ( (ebi != ESM_EBI_UNASSIGNED) && (ebi < ESM_EBI_MIN) ); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_is_not_in_use() ** + ** ** + ** Description: Check whether the given EPS bearer identity does not ** + ** match an assigned EBI value currently in use ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** ebi: The identity of the EPS bearer ** + ** Others: _esm_ebr_data ** + ** ** + ** Outputs: None ** + ** Return: TRUE, FALSE ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_ebr_is_not_in_use( +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi) +{ +#ifdef NAS_UE + unsigned int ueid = 0; +#endif + + return ( (ebi == ESM_EBI_UNASSIGNED) || + (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN] == NULL) || + (_esm_ebr_data[ueid].context[ebi - ESM_EBI_MIN]->ebi) != ebi); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _esm_ebr_get_available_entry() ** + ** ** + ** Description: Returns the index of the next available entry in the list ** + ** of EPS bearer context data ** + ** ** + ** Inputs: ueid: Lower layers UE identifier ** + ** Others: _esm_ebr_data ** + ** ** + ** Outputs: None ** + ** Return: The index of the next available EPS bearer ** + ** context data entry; -1 if no any entry is ** + ** available. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_ebr_get_available_entry(unsigned int ueid) +{ + int i; + for (i = _esm_ebr_data[ueid].index; i < ESM_EBR_DATA_SIZE; i++) { + if (_esm_ebr_data[ueid].context[i] != NULL) continue; + return i; + } + for (i = 0; i < _esm_ebr_data[ueid].index; i++) { + if (_esm_ebr_data[ueid].context[i] != NULL) continue; + return i; + } + /* No available EBI entry found */ + return (-1); + } diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.h new file mode 100644 index 0000000000..f3943c2b3a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr.h @@ -0,0 +1,107 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_ebr.h + +Version 0.1 + +Date 2013/01/29 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle state of EPS bearer contexts + and manage ESM messages re-transmission. + +*****************************************************************************/ +#ifndef __ESM_EBR_H__ +#define __ESM_EBR_H__ + +#include "OctetString.h" + +#ifdef NAS_UE +#include "networkDef.h" +#endif + +#include "nas_timer.h" +#include "EpsBearerIdentity.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Unassigned EPS bearer identity value */ +#define ESM_EBI_UNASSIGNED (EPS_BEARER_IDENTITY_UNASSIGNED) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* EPS bearer context states */ +typedef enum { + ESM_EBR_INACTIVE, /* No EPS bearer context exists */ + ESM_EBR_ACTIVE, /* The EPS bearer context is active, + * in the UE, in the network */ +#ifdef NAS_MME + ESM_EBR_INACTIVE_PENDING, /* The network has initiated an EPS bearer + * context deactivation towards the UE */ + ESM_EBR_MODIFY_PENDING, /* The network has initiated an EPS bearer + * context modification towards the UE */ + ESM_EBR_ACTIVE_PENDING, /* The network has initiated an EPS bearer + * context activation towards the UE */ +#endif + ESM_EBR_STATE_MAX +} esm_ebr_state; + +#ifdef NAS_MME +/* ESM message timer retransmission data */ +typedef struct { + unsigned int ueid; /* Lower layers UE identifier */ + unsigned int ebi; /* EPS bearer identity */ + unsigned int count; /* Retransmission counter */ + OctetString msg; /* Encoded ESM message to re-transmit */ +} esm_ebr_timer_data_t; +#endif + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int esm_ebr_is_reserved(int ebi); + +#ifdef NAS_UE +void esm_ebr_initialize(esm_indication_callback_t cb); +int esm_ebr_assign(int ebi, int cid, int default_ebr); +int esm_ebr_release(int ebi); + +int esm_ebr_set_status(int ebi, esm_ebr_state status, int ue_requested); +esm_ebr_state esm_ebr_get_status(int ebi); + +int esm_ebr_is_not_in_use(int ebi); +#endif + +#ifdef NAS_MME +void esm_ebr_initialize(void); +int esm_ebr_assign(unsigned int ueid, int ebi); +int esm_ebr_release(unsigned int ueid, int ebi); + +int esm_ebr_start_timer(unsigned int ueid, int ebi, const OctetString* msg, long sec, nas_timer_callback_t cb); +int esm_ebr_stop_timer(unsigned int ueid, int ebi); + +int esm_ebr_get_pending_ebi(unsigned int ueid, esm_ebr_state status); + +int esm_ebr_set_status(unsigned int ueid, int ebi, esm_ebr_state status, int ue_requested); +esm_ebr_state esm_ebr_get_status(unsigned int ueid, int ebi); + +int esm_ebr_is_not_in_use(unsigned int ueid, int ebi); +#endif + +#endif /* __ESM_EBR_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.c b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.c new file mode 100644 index 0000000000..500bb1e04a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.c @@ -0,0 +1,593 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_ebr_context.h + +Version 0.1 + +Date 2013/05/28 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle EPS bearer contexts. + +*****************************************************************************/ + +#include "esm_ebr_context.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esmData.h" +#include "esm_ebr.h" + +#include "emm_sap.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memset + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +static int _esm_ebr_context_check_identifiers(const network_tft_t*, const network_tft_t*); +static int _esm_ebr_context_check_precedence(const network_tft_t*, const network_tft_t*); +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: esm_ebr_context_create() ** + ** ** + ** Description: Creates a new EPS bearer context to the PDN with the spe- ** + ** cified PDN connection identifier ** + ** ** + ** Inputs: ueid: UE identifier ** + ** pid: PDN connection identifier ** + ** ebi: EPS bearer identity ** + ** is_default: TRUE if the new bearer is a default EPS ** + ** bearer context ** + ** esm_qos: EPS bearer level QoS parameters ** + ** tft: Traffic flow template parameters ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The EPS bearer identity of the default EPS ** + ** bearer associated to the new EPS bearer ** + ** context if successfully created; ** + ** UNASSIGN EPS bearer value otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +int esm_ebr_context_create( +#ifdef NAS_MME + unsigned int ueid, +#endif + int pid, int ebi, int is_default, + const network_qos_t* qos, const network_tft_t* tft) +{ + LOG_FUNC_IN; + + esm_data_context_t* ctx; + +#ifdef NAS_UE + ctx = &_esm_data; +#endif +#ifdef NAS_MME + if (ueid < ESM_DATA_NB_UE_MAX) { + ctx = _esm_data.ctx[ueid]; + } else { + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } +#endif + + int bid = ESM_DATA_EPS_BEARER_MAX; + esm_pdn_t* pdn = NULL; + + LOG_TRACE(INFO, "ESM-PROC - Create new %s EPS bearer context (ebi=%d) " + "for PDN connection (pid=%d)", + (is_default)? "default" : "dedicated", ebi, pid); + + if (pid < ESM_DATA_PDN_MAX) { + if (pid != ctx->pdn[pid].pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d is " + "not valid", pid); + } + else if (ctx->pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", pid); + } + /* Check the total number of active EPS bearers */ + else if (ctx->n_ebrs > ESM_DATA_EPS_BEARER_TOTAL) { + LOG_TRACE(WARNING, "ESM-PROC - The total number of active EPS" + "bearers is exeeded"); + } + else { + /* Get the PDN connection entry */ + pdn = ctx->pdn[pid].data; + if (is_default) { + /* Default EPS bearer entry is defined at index 0 */ + bid = 0; + if (pdn->bearer[bid] != NULL) { + LOG_TRACE(ERROR, "ESM-PROC - A default EPS bearer context " + "is already allocated"); + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } + } + else { + /* Search for an available EPS bearer context entry */ + for (bid = 1; bid < ESM_DATA_EPS_BEARER_MAX; bid++) { + if (pdn->bearer[bid] != NULL) continue; + break; + } + } + } + } + + if (bid < ESM_DATA_EPS_BEARER_MAX) { + /* Create new EPS bearer context */ + esm_bearer_t* ebr = (esm_bearer_t*)malloc(sizeof(esm_bearer_t)); + if (ebr != NULL) { + memset(ebr, 0 , sizeof(esm_bearer_t)); + /* Increment the total number of active EPS bearers */ + ctx->n_ebrs += 1; + /* Increment the number of EPS bearer for this PDN connection */ + pdn->n_bearers += 1; + /* Setup the EPS bearer data */ + pdn->bearer[bid] = ebr; + ebr->bid = bid; + ebr->ebi = ebi; + if (qos != NULL) { + /* EPS bearer level QoS parameters */ + ebr->qos = *qos; + } + if ( (tft != NULL) && (tft->n_pkfs < NET_PACKET_FILTER_MAX) ) { + int i; + /* Traffic flow template parameters */ + for (i = 0; i < tft->n_pkfs; i++) + { + ebr->tft.pkf[i] = + (network_pkf_t*)malloc(sizeof(network_pkf_t)); + if (ebr->tft.pkf[i] != NULL) { + *(ebr->tft.pkf[i]) = *(tft->pkf[i]); + ebr->tft.n_pkfs += 1; + } + } + } + + if (is_default) { + /* Set the PDN connection activation indicator */ + ctx->pdn[pid].is_active = TRUE; + /* Update the emergency bearer services indicator */ + if (pdn->is_emergency) { + ctx->emergency = TRUE; + } + } + + /* Return the EPS bearer identity of the default EPS bearer + * associated to the new EPS bearer context */ + LOG_FUNC_RETURN (pdn->bearer[0]->ebi); + } + LOG_TRACE(WARNING, "ESM-PROC - Failed to create new EPS bearer " + "context (ebi=%d)", ebi); + } + + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_context_release() ** + ** ** + ** Description: Releases EPS bearer context entry previously allocated ** + ** to the EPS bearer with the specified EPS bearer identity ** + ** ** + ** Inputs: ueid: UE identifier ** + ** ebi: EPS bearer identity ** + ** Others: _esm_data ** + ** ** + ** Outputs: pid: Identifier of the PDN connection entry the ** + ** EPS bearer context belongs to ** + ** bid: Identifier of the released EPS bearer con- ** + ** text entry ** + ** Return: The EPS bearer identity associated to the ** + ** EPS bearer context if successfully relea- ** + ** sed; UNASSIGN EPS bearer value otherwise. ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +int esm_ebr_context_release( +#ifdef NAS_MME + unsigned int ueid, +#endif + int ebi, int* pid, int* bid) +{ + LOG_FUNC_IN; + + esm_data_context_t* ctx; + +#ifdef NAS_UE + ctx = &_esm_data; +#endif +#ifdef NAS_MME + if (ueid < ESM_DATA_NB_UE_MAX) { + ctx = _esm_data.ctx[ueid]; + } else { + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } +#endif + + int found = FALSE; + esm_pdn_t* pdn = NULL; + + if (ebi != ESM_EBI_UNASSIGNED) { + /* + * The identity of the EPS bearer to released is given; + * Release the EPS bearer context entry that match the specified EPS + * bearer identity + */ + + /* Search for active PDN connection */ + for (*pid = 0; *pid < ESM_DATA_PDN_MAX; (*pid)++) { + if ( !ctx->pdn[*pid].is_active ) continue; + /* An active PDN connection is found */ + if (ctx->pdn[*pid].data != NULL) { + pdn = ctx->pdn[*pid].data; + /* Search for the specified EPS bearer context entry */ + for (*bid = 0; *bid < pdn->n_bearers; (*bid)++) { + if (pdn->bearer[*bid] != NULL) { + if (pdn->bearer[*bid]->ebi != ebi) continue; + /* The EPS bearer context entry is found */ + found = TRUE; + break; + } + } + } + if (found) break; + } + } + else { + /* + * The identity of the EPS bearer to released is not given; + * Release the EPS bearer context entry allocated with the EPS + * bearer context identifier (bid) to establish connectivity to + * the PDN identified by the PDN connection identifier (pid). + * Default EPS bearer to a given PDN is always identified by the + * first EPS bearer context entry at index bid = 0 + */ + if (*pid < ESM_DATA_PDN_MAX) { + if (*pid != ctx->pdn[*pid].pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d " + "is not valid", *pid); + } + else if (!ctx->pdn[*pid].is_active) { + LOG_TRACE(WARNING,"ESM-PROC - PDN connection %d is not active", + *pid); + } + else if (ctx->pdn[*pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", *pid); + } + else { + pdn = ctx->pdn[*pid].data; + if (pdn->bearer[*bid] != NULL) { + ebi = pdn->bearer[*bid]->ebi; + found = TRUE; + } + } + } + } + + if (found) { + int i, j; + /* + * Delete the specified EPS bearer context entry + */ + if (pdn->bearer[*bid]->bid != *bid) { + LOG_TRACE(ERROR, "ESM-PROC - EPS bearer identifier %d is " + "not valid", *bid); + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); + } + + LOG_TRACE(WARNING, "ESM-PROC - Release EPS bearer context " + "(ebi=%d)", ebi); + + /* Delete the TFT */ + for (i = 0; i < pdn->bearer[*bid]->tft.n_pkfs; i++) { + free(pdn->bearer[*bid]->tft.pkf[i]); + } + /* Release the specified EPS bearer data */ + free(pdn->bearer[*bid]); + pdn->bearer[*bid] = NULL; + /* Decrement the number of EPS bearer context allocated + * to the PDN connection */ + pdn->n_bearers -= 1; + /* Decrement the total number of active EPS bearers */ + ctx->n_ebrs -= 1; + + if (*bid == 0) { + /* 3GPP TS 24.301, section 6.4.4.3, 6.4.4.6 + * If the EPS bearer identity is that of the default bearer to a + * PDN, the UE shall delete all EPS bearer contexts associated to + * that PDN connection. + */ + for (i = 1; pdn->n_bearers > 0; i++) { + if (pdn->bearer[i]) { + + LOG_TRACE(WARNING, "ESM-PROC - Release EPS bearer context " + "(ebi=%d)", pdn->bearer[i]->ebi); + + /* Delete the TFT */ + for (j = 0; j < pdn->bearer[i]->tft.n_pkfs; j++) { + free(pdn->bearer[i]->tft.pkf[j]); + } + /* Set the EPS bearer context state to INACTIVE */ +#ifdef NAS_UE + (void) esm_ebr_set_status(pdn->bearer[i]->ebi, + ESM_EBR_INACTIVE, TRUE); +#endif +#ifdef NAS_MME + (void) esm_ebr_set_status(ueid, pdn->bearer[i]->ebi, + ESM_EBR_INACTIVE, TRUE); +#endif + /* Release EPS bearer data */ +#ifdef NAS_UE + (void) esm_ebr_release(pdn->bearer[i]->ebi); +#endif +#ifdef NAS_MME + (void) esm_ebr_release(ueid, pdn->bearer[i]->ebi); +#endif + // esm_ebr_release() + /* Release dedicated EPS bearer data */ + free(pdn->bearer[i]); + pdn->bearer[i] = NULL; + /* Decrement the number of EPS bearer context allocated + * to the PDN connection */ + pdn->n_bearers -= 1; + /* Decrement the total number of active EPS bearers */ + ctx->n_ebrs -= 1; + } + } + /* Reset the PDN connection activation indicator */ + ctx->pdn[*pid].is_active = FALSE; + /* Update the emergency bearer services indicator */ + if (pdn->is_emergency) { + ctx->emergency = FALSE; + } + } + +#ifdef NAS_UE + /* 3GPP TS 24.301, section 6.4.4.6 + * If the UE locally deactivated all EPS bearer contexts, the UE + * shall perform a local detach and enter state EMM-DEREGISTERED. + */ + if (ctx->n_ebrs == 0) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMESM_ESTABLISH_CNF; + emm_sap.u.emm_esm.u.establish.is_attached = FALSE; + (void) emm_sap_send(&emm_sap); + } + /* 3GPP TS 24.301, section 6.4.4.3, 6.4.4.6 + * If due to the EPS bearer context deactivation only the PDN + * connection for emergency bearer services remains established, + * the UE shall consider itself attached for emergency bearer + * services only. + */ + else if ( ctx->emergency && (ctx->n_ebrs == 1) ) { + emm_sap_t emm_sap; + emm_sap.primitive = EMMESM_ESTABLISH_CNF; + emm_sap.u.emm_esm.u.establish.is_attached = TRUE; + emm_sap.u.emm_esm.u.establish.is_emergency = TRUE; + (void) emm_sap_send(&emm_sap); + } +#endif // NAS_UE +#ifdef NAS_MME + if (ctx->n_ebrs == 0) { + /* TODO: Release the PDN connection and marked the UE as inactive + * in the network for EPS services (is_attached = FALSE) */ + } +#endif + + LOG_FUNC_RETURN (ebi); + } + + LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_ebr_context_get_pid() ** + ** ** + ** Description: Returns the identifier of the PDN connection entry the ** + ** default EPS bearer context with the specified EPS bearer ** + ** identity belongs to ** + ** ** + ** Inputs: ebi: The EPS bearer identity of the default EPS ** + ** bearer context ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the PDN connection entry ** + ** associated to the specified default EPS ** + ** bearer context if it exists; -1 otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_ebr_context_get_pid(int ebi) +{ + LOG_FUNC_IN; + + int pid; + + for (pid = 0; pid < ESM_DATA_PDN_MAX; pid++) { + if (_esm_data.pdn[pid].data == NULL) continue; + if (_esm_data.pdn[pid].data->bearer[0] == NULL) continue; + if (_esm_data.pdn[pid].data->bearer[0]->ebi == ebi) break; + } + + if (pid < ESM_DATA_PDN_MAX) { + LOG_FUNC_RETURN (pid); + } + LOG_FUNC_RETURN (-1); +} + +/**************************************************************************** + ** ** + ** Name: esm_ebr_context_check_tft() ** + ** ** + ** Description: Checks syntactical errors in packet filters associated to ** + ** the EPS bearer context with the specified EPS bearer ** + ** identity for the PDN connection entry with the given ** + ** identifier ** + ** ** + ** Inputs: pid: Identifier of the PDN connection entry the ** + ** EPS bearer context belongs to ** + ** ebi: The EPS bearer identity of the EPS bearer ** + ** context with associated packet filter list ** + ** tft: The traffic flow template (set of packet ** + ** filters) to be checked ** + ** operation: Traffic flow template operation ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_ebr_context_check_tft(int pid, int ebi, + const network_tft_t* tft, + esm_ebr_context_tft_t operation) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (pid < ESM_DATA_PDN_MAX) { + if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d " + "is not valid", pid); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been " + "allocated", pid); + } + else if (operation == ESM_EBR_CONTEXT_TFT_CREATE) { + esm_pdn_t* pdn = _esm_data.pdn[pid].data; + /* For each EPS bearer context associated to the PDN connection */ + for (int i = 0; i < pdn->n_bearers; i++) { + if (pdn->bearer[i]) { + if (pdn->bearer[i]->ebi == ebi) { + /* Check the packet filter identifiers */ + rc = _esm_ebr_context_check_identifiers(tft, + &pdn->bearer[i]->tft); + if (rc != RETURNok) break; + } + /* Check the packet filter precedence values */ + rc = _esm_ebr_context_check_precedence(tft, + &pdn->bearer[i]->tft); + if (rc != RETURNok) break; + } + } + } + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _esm_ebr_context_check_identifiers() ** + ** ** + ** Description: Compares traffic flow templates to check whether two or ** + ** more packet filters have identical packet filter identi- ** + ** fiers ** + ** ** + ** Inputs: tft1: The first set of packet filters ** + ** tft2: The second set of packet filters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNerror if at least one packet filter ** + ** has same identifier in both traffic flow ** + ** templates; RETURNok otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_ebr_context_check_identifiers(const network_tft_t* tft1, + const network_tft_t* tft2) +{ + if ( (tft1 == NULL) || (tft2 == NULL) ) { + return (RETURNok); + } + for (int i = 0; i < tft1->n_pkfs; i++) { + for (int j = 0; j < tft2->n_pkfs; j++) { + /* Packet filters should have been allocated */ + if (tft1->pkf[i]->id == tft2->pkf[i]->id) { + /* 3GPP TS 24.301, section 6.4.2.5, abnormal cases d.1 + * Packet filters have same identifier */ + return (RETURNerror); + } + } + } + return (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: _esm_ebr_context_check_precedence() ** + ** ** + ** Description: Compares traffic flow templates to check whether two or ** + ** more packet filters have identical precedence values ** + ** ** + ** Inputs: tft1: The first set of packet filters ** + ** tft2: The second set of packet filters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNerror if at least one packet filter ** + ** has same precedence value in both traffic ** + ** flow templates; RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_ebr_context_check_precedence(const network_tft_t* tft1, + const network_tft_t* tft2) +{ + if ( (tft1 == NULL) || (tft2 == NULL) ) { + return (RETURNok); + } + for (int i = 0; i < tft1->n_pkfs; i++) { + for (int j = 0; j < tft2->n_pkfs; j++) { + /* Packet filters should have been allocated */ + if (tft1->pkf[i]->precedence == tft2->pkf[i]->precedence) { + /* 3GPP TS 24.301, section 6.4.2.5, abnormal cases d.2 + * Packet filters have same precedence value */ + /* TODO: Actually if the old packet filters do not belong + * to the default EPS bearer context, the UE shall not + * diagnose an error (see 6.4.2.5, abnormal cases d.2) */ + return (RETURNerror); + } + } + } + return (RETURNok); +} +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.h new file mode 100644 index 0000000000..543335c8b5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ebr_context.h @@ -0,0 +1,68 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_ebr_context.h + +Version 0.1 + +Date 2013/05/28 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle EPS bearer contexts. + +*****************************************************************************/ +#ifndef __ESM_EBR_CONTEXT_H__ +#define __ESM_EBR_CONTEXT_H__ + +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* Traffic flow template operation */ +typedef enum { + ESM_EBR_CONTEXT_TFT_CREATE, + ESM_EBR_CONTEXT_TFT_DELETE, + ESM_EBR_CONTEXT_TFT_ADD_PACKET, + ESM_EBR_CONTEXT_TFT_REPLACE_PACKET, + ESM_EBR_CONTEXT_TFT_DELETE_PACKET, +} esm_ebr_context_tft_t; +#endif + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +int esm_ebr_context_create(int pid, int ebi, int is_default, const network_qos_t* qos, const network_tft_t* tft); + +int esm_ebr_context_release(int ebi, int* pid, int* bid); + +int esm_ebr_context_get_pid(int ebi); + +int esm_ebr_context_check_tft(int pid, int ebi, const network_tft_t* tft, esm_ebr_context_tft_t operation); +#endif + +#ifdef NAS_MME +int esm_ebr_context_create(unsigned int ueid, int pid, int ebi, int is_default, const network_qos_t* qos, const network_tft_t* tft); + +int esm_ebr_context_release(unsigned int ueid, int ebi, int* pid, int* bid); +#endif + +#endif /* __ESM_EBR_CONTEXT_H__ */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ip.c b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ip.c new file mode 100644 index 0000000000..1c158a8a6b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_ip.c @@ -0,0 +1,43 @@ + +#include "esmData.h" + +char ip_addr_str[100]; + +inline char* esm_data_get_ipv4_addr(const OctetString* ip_addr) +{ + if (ip_addr->length > 0) { + sprintf(ip_addr_str, "%u.%u.%u.%u", + ip_addr->value[0], ip_addr->value[1], + ip_addr->value[2], ip_addr->value[3]); + return ip_addr_str; + } + return (NULL); +} + +inline char* esm_data_get_ipv6_addr(const OctetString* ip_addr) +{ + if (ip_addr->length > 0) { + sprintf(ip_addr_str, "%x%.2x:%x%.2x:%x%.2x:%x%.2x", + ip_addr->value[0], ip_addr->value[1], + ip_addr->value[2], ip_addr->value[3], + ip_addr->value[4], ip_addr->value[5], + ip_addr->value[6], ip_addr->value[7]); + return ip_addr_str; + } + return (NULL); +} + +inline char* esm_data_get_ipv4v6_addr(const OctetString* ip_addr) +{ + if (ip_addr->length > 0) { + sprintf(ip_addr_str, "%u.%u.%u.%u / %x%.2x:%x%.2x:%x%.2x:%x%.2x", + ip_addr->value[0], ip_addr->value[1], + ip_addr->value[2], ip_addr->value[3], + ip_addr->value[4], ip_addr->value[5], + ip_addr->value[6], ip_addr->value[7], + ip_addr->value[8], ip_addr->value[9], + ip_addr->value[10], ip_addr->value[11]); + return ip_addr_str; + } + return (NULL); +} diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.c b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.c new file mode 100644 index 0000000000..85b9e72d84 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.c @@ -0,0 +1,398 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_main.c + +Version 0.1 + +Date 2012/12/04 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the EPS Session Management procedure call manager, + the main entry point for elementary ESM processing. + +*****************************************************************************/ + +#include "esm_main.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esmData.h" +#include "esm_pt.h" +#include "esm_ebr.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_main_initialize() ** + ** ** + ** Description: Initializes ESM internal data ** + ** ** + ** Inputs: cb: The user notification callback ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _esm_data ** + ** ** + ***************************************************************************/ +void esm_main_initialize(esm_indication_callback_t cb) +{ + LOG_FUNC_IN; + + /* Total number of active EPS bearer contexts */ + _esm_data.n_ebrs = 0; + /* List of active PDN connections */ + _esm_data.n_pdns = 0; + for (int i = 0; i < ESM_DATA_PDN_MAX + 1; i++) { + _esm_data.pdn[i].pid = -1; + _esm_data.pdn[i].is_active = FALSE; + _esm_data.pdn[i].data = NULL; + } + /* Emergency bearer services indicator */ + _esm_data.emergency = FALSE; + + /* Initialize the procedure transaction identity manager */ + esm_pt_initialize(); + + /* Initialize the EPS bearer context manager */ + esm_ebr_initialize(cb); + + LOG_FUNC_OUT; +} +#endif +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_main_initialize() ** + ** ** + ** Description: Initializes ESM internal data ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void esm_main_initialize(void) +{ + int i; + + LOG_FUNC_IN; + + /* Retreive MME supported configuration data */ + if (mme_api_get_esm_config(&_esm_data.conf) != RETURNok) { + LOG_TRACE(ERROR, "ESM-MAIN - Failed to get MME configuration data"); + } + + /* Initialize ESM contexts */ + for (i = 0; i < ESM_DATA_NB_UE_MAX; i++) { + _esm_data.ctx[i] = NULL; + } + + /* Initialize the EPS bearer context manager */ + esm_ebr_initialize(); + + LOG_FUNC_OUT; +} +#endif + +/**************************************************************************** + ** ** + ** Name: esm_main_cleanup() ** + ** ** + ** Description: Performs the EPS Session Management clean up procedure ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void esm_main_cleanup(void) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + /* De-activate EPS bearers and clean up PDN connections */ + for (int pid = 0; pid < ESM_DATA_PDN_MAX; pid++) { + if (_esm_data.pdn[pid].data) { + esm_pdn_t* pdn = _esm_data.pdn[pid].data; + if (pdn->apn.length > 0) { + free(pdn->apn.value); + } + /* Release EPS bearer contexts */ + for (int bid = 0; bid < pdn->n_bearers; bid++) { + if (pdn->bearer[bid]) { + LOG_TRACE(WARNING, "ESM-MAIN - Release EPS bearer " + "context (ebi=%d)", pdn->bearer[bid]->ebi); + /* Delete the TFT */ + for (int i = 0; i < pdn->bearer[bid]->tft.n_pkfs; i++) { + if (pdn->bearer[bid]->tft.pkf[i]) { + free(pdn->bearer[bid]->tft.pkf[i]); + } + } + free(pdn->bearer[bid]); + } + } + /* Release the PDN connection */ + free(_esm_data.pdn[pid].data); + } + } +#endif + + LOG_FUNC_OUT; +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_main_get_nb_pdn_max() ** + ** ** + ** Description: Get the maximum number of PDN connections that may be in ** + ** a defined state at the same time ** + ** ** + ** Inputs: None ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The maximum number of PDN connections that ** + ** may be defined ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_get_nb_pdns_max(void) +{ + LOG_FUNC_IN; + + LOG_FUNC_RETURN (ESM_DATA_PDN_MAX); +} + +/**************************************************************************** + ** ** + ** Name: esm_main_get_nb_pdns() ** + ** ** + ** Description: Get the number of active PDN connections ** + ** ** + ** Inputs: None ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: The number of active PDN connections ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_get_nb_pdns(void) +{ + LOG_FUNC_IN; + + LOG_FUNC_RETURN (_esm_data.n_pdns); +} + +/**************************************************************************** + ** ** + ** Name: esm_main_has_emergency() ** + ** ** + ** Description: Check whether a PDN connection for emergency bearer ser- ** + ** vices is established ** + ** ** + ** Inputs: None ** + ** Others: _esm_data ** + ** ** + ** Outputs: None ** + ** Return: TRUE if a PDN connection for emergency ** + ** bearer services is established ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_has_emergency(void) +{ + LOG_FUNC_IN; + + LOG_FUNC_RETURN (_esm_data.emergency); +} + +/**************************************************************************** + ** ** + ** Name: esm_main_get_pdn_status() ** + ** ** + ** Description: Get the status of the specified PDN connection ** + ** ** + ** Inputs: cid: PDN connection identifier ** + ** Others: _esm_data ** + ** ** + ** Outputs: state: TRUE if the current state of the PDN con- ** + ** nection is ACTIVE; FALSE otherwise. ** + ** Return: TRUE if the specified PDN connection has a ** + ** PDN context defined; FALSE if no any PDN ** + ** context has been defined for the specified ** + ** connection. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_get_pdn_status(int cid, int* state) +{ + LOG_FUNC_IN; + + unsigned int pid = cid - 1; + + if (pid >= ESM_DATA_PDN_MAX) { + return (FALSE); + } + else if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid); + return (FALSE); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated", + cid); + return (FALSE); + } + + if (_esm_data.pdn[pid].data->bearer[0] != NULL) { + /* The status of a PDN connection is the status of the default EPS bearer + * that has been assigned to this PDN connection at activation time */ + int ebi = _esm_data.pdn[pid].data->bearer[0]->ebi; + *state = (esm_ebr_get_status(ebi) == ESM_EBR_ACTIVE); + } + /* The PDN connection has not been activated yet */ + LOG_FUNC_RETURN (TRUE); +} + +/**************************************************************************** + ** ** + ** Name: esm_main_get_pdn() ** + ** ** + ** Description: Get parameters defined for the specified PDN connection ** + ** ** + ** Inputs: cid: PDN connection identifier ** + ** Others: _esm_data ** + ** ** + ** Outputs: type: PDN connection type (IPv4, IPv6, IPv4v6) ** + ** apn: Access Point logical Name in used ** + ** is_emergency: Emergency bearer services indicator ** + ** is_active: Active PDN connection indicator ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_get_pdn(int cid, int* type, const char** apn, + int* is_emergency, int* is_active) +{ + LOG_FUNC_IN; + + unsigned int pid = cid - 1; + + if (pid >= ESM_DATA_PDN_MAX) { + return (RETURNerror); + } + else if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid); + return (RETURNerror); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated", + cid); + return (RETURNerror); + } + + /* Get the PDN type */ + *type = _esm_data.pdn[pid].data->type; + /* Get the Access Point Name */ + if (_esm_data.pdn[pid].data->apn.length > 0) { + *apn = (char*)(_esm_data.pdn[pid].data->apn.value); + } else { + *apn = NULL; + } + /* Get the emergency bearer services indicator */ + *is_emergency = _esm_data.pdn[pid].data->is_emergency; + /* Get the active PDN connection indicator */ + *is_active = _esm_data.pdn[pid].is_active; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_main_get_pdn_addr() ** + ** ** + ** Description: Get IP address(es) assigned to the specified PDN connec- ** + ** tion ** + ** ** + ** Inputs: cid: PDN connection identifier ** + ** Others: _esm_data ** + ** ** + ** Outputs: ipv4adddr: IPv4 address ** + ** ipv6adddr: IPv6 address ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_main_get_pdn_addr(int cid, const char** ipv4addr, const char** ipv6addr) +{ + LOG_FUNC_IN; + + unsigned int pid = cid - 1; + + if (pid >= ESM_DATA_PDN_MAX) { + return (RETURNerror); + } + else if (pid != _esm_data.pdn[pid].pid) { + LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid); + return (RETURNerror); + } + else if (_esm_data.pdn[pid].data == NULL) { + LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated", + cid); + return (RETURNerror); + } + else if (!_esm_data.pdn[pid].is_active) { + /* No any IP address has been assigned to this PDN connection */ + return (RETURNok); + } + + if (_esm_data.pdn[pid].data->type == NET_PDN_TYPE_IPV4) { + /* Get IPv4 address */ + *ipv4addr = _esm_data.pdn[pid].data->ip_addr; + } + else if (_esm_data.pdn[pid].data->type == NET_PDN_TYPE_IPV6) { + /* Get IPv6 address */ + *ipv6addr = _esm_data.pdn[pid].data->ip_addr; + } + else { + /* IPv4v6 dual-stack terminal */ + *ipv4addr = _esm_data.pdn[pid].data->ip_addr; + *ipv6addr = _esm_data.pdn[pid].data->ip_addr+ESM_DATA_IPV4_ADDRESS_SIZE; + } + + LOG_FUNC_RETURN (RETURNok); +} + +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.h new file mode 100644 index 0000000000..16c058cf04 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_main.h @@ -0,0 +1,63 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_main.h + +Version 0.1 + +Date 2012/12/04 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the EPS Session Management procedure call manager, + the main entry point for elementary ESM processing. + +*****************************************************************************/ + +#ifndef __ESM_MAIN_H__ +#define __ESM_MAIN_H__ + +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +void esm_main_initialize(esm_indication_callback_t cb); +#endif +#ifdef NAS_MME +void esm_main_initialize(void); +#endif +void esm_main_cleanup(void); + +#ifdef NAS_UE + +/* User's getter for PDN connections and EPS bearer contexts */ +int esm_main_get_nb_pdns_max(void); +int esm_main_get_nb_pdns(void); +int esm_main_has_emergency(void); +int esm_main_get_pdn_status(int cid, int* state); +int esm_main_get_pdn(int cid, int* type, const char** apn, int* is_emergency, int* is_active); +int esm_main_get_pdn_addr(int cid, const char** ipv4addr, const char** ipv6addr); + +#endif // NAS_UE + +#endif /* __ESM_MAIN_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_proc.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_proc.h new file mode 100644 index 0000000000..f9c7dc181a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_proc.h @@ -0,0 +1,216 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_proc.h + +Version 0.1 + +Date 2013/01/02 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the EPS Session Management procedures executed at + the ESM Service Access Points. + +*****************************************************************************/ +#ifndef __ESM_PROC_H__ +#define __ESM_PROC_H__ + +#include "networkDef.h" +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * ESM retransmission timers + * ------------------------- + */ +#ifdef NAS_UE +#define T3482_DEFAULT_VALUE 8 /* PDN connectivity request */ +#define T3492_DEFAULT_VALUE 6 /* PDN disconnect request */ +#endif + +#ifdef NAS_MME +#define T3485_DEFAULT_VALUE 8 /* Activate EPS bearer request */ +#define T3495_DEFAULT_VALUE 8 /* Deactivate EPS bearer request */ +#endif + +/* Type of PDN address */ +typedef enum { + ESM_PDN_TYPE_IPV4 = NET_PDN_TYPE_IPV4, + ESM_PDN_TYPE_IPV6 = NET_PDN_TYPE_IPV6, + ESM_PDN_TYPE_IPV4V6 = NET_PDN_TYPE_IPV4V6 +} esm_proc_pdn_type_t; + +/* Type of PDN request */ +typedef enum { + ESM_PDN_REQUEST_INITIAL = 1, + ESM_PDN_REQUEST_HANDOVER, + ESM_PDN_REQUEST_EMERGENCY +} esm_proc_pdn_request_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Type of the ESM procedure callback executed when requested by the UE + * or initiated by the network + */ +#ifdef NAS_UE +typedef int (*esm_proc_procedure_t) (int, int, OctetString*, int); +#endif +#ifdef NAS_MME +typedef int (*esm_proc_procedure_t) (int, unsigned int, int, OctetString*, int); +#endif + +/* EPS bearer level QoS parameters */ +typedef network_qos_t esm_proc_qos_t; + +/* Traffic Flow Template for packet filtering */ +typedef network_tft_t esm_proc_tft_t; + +/* PDN connection and EPS bearer context data */ +typedef struct { + OctetString apn; + esm_proc_pdn_type_t pdn_type; + OctetString pdn_addr; + esm_proc_qos_t qos; + esm_proc_tft_t tft; +} esm_proc_data_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * ESM status procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int esm_proc_status_ind(int pti, int ebi, int* esm_cause); +int esm_proc_status(int is_standalone, int pti, OctetString* msg, int sent_by_ue); +#endif + +#ifdef NAS_MME +int esm_proc_status_ind(unsigned int ueid, int pti, int ebi, int* esm_cause); +int esm_proc_status(int is_standalone, unsigned int ueid, int pti, OctetString* msg, int sent_by_ue); +#endif + + +/* + * -------------------------------------------------------------------------- + * PDN connectivity procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int esm_proc_pdn_connectivity(int cid, int to_define, esm_proc_pdn_type_t pdn_type, const OctetString* apn, int is_emergency, unsigned int* pti); +int esm_proc_pdn_connectivity_request(int is_standalone, int pti, OctetString* msg, int sent_by_ue); +int esm_proc_pdn_connectivity_accept(int pti, esm_proc_pdn_type_t pdn_type, const OctetString* pdn_address, const OctetString* apn, int* esm_cause); +int esm_proc_pdn_connectivity_reject(int pti, int* esm_cause); +int esm_proc_pdn_connectivity_complete(void); +int esm_proc_pdn_connectivity_failure(int is_pending); +#endif + +#ifdef NAS_MME +int esm_proc_pdn_connectivity_request(unsigned int ueid, int pti, esm_proc_pdn_request_t request_type, OctetString* apn, esm_proc_pdn_type_t pdn_type, OctetString* pdn_addr, esm_proc_qos_t* esm_qos, int* esm_cause); + +int esm_proc_pdn_connectivity_reject(int is_standalone, unsigned int ueid, int ebi, OctetString* msg, int ue_triggered); +int esm_proc_pdn_connectivity_failure(unsigned int ueid, int pid); +#endif + +/* + * -------------------------------------------------------------------------- + * PDN disconnect procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int esm_proc_pdn_disconnect(int cid, unsigned int* pti, unsigned int* ebi); +int esm_proc_pdn_disconnect_request(int is_standalone, int pti, OctetString* msg, int sent_by_ue); + +int esm_proc_pdn_disconnect_accept(int pti, int* esm_cause); +int esm_proc_pdn_disconnect_reject(int pti, int* esm_cause); +#endif + +#ifdef NAS_MME +int esm_proc_pdn_disconnect_request(unsigned int ueid, int pti, int* esm_cause); + +int esm_proc_pdn_disconnect_accept(unsigned int ueid, int pid, int* esm_cause); +int esm_proc_pdn_disconnect_reject(int is_standalone, unsigned int ueid, int ebi, OctetString* msg, int ue_triggered); +#endif + +/* + * -------------------------------------------------------------------------- + * Default EPS bearer context activation procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +int esm_proc_default_eps_bearer_context(unsigned int ueid, int pid, unsigned int* ebi, const esm_proc_qos_t* esm_qos, int* esm_cause); +int esm_proc_default_eps_bearer_context_request(int is_standalone, unsigned int ueid, int ebi, OctetString* msg, int ue_triggered); +int esm_proc_default_eps_bearer_context_failure(unsigned int ueid); + +int esm_proc_default_eps_bearer_context_accept(unsigned int ueid, int ebi, int* esm_cause); +int esm_proc_default_eps_bearer_context_reject(unsigned int ueid, int ebi, int* esm_cause); +#endif + +#ifdef NAS_UE +int esm_proc_default_eps_bearer_context_request(int pid, int ebi, const esm_proc_qos_t* esm_qos, int* esm_cause); +int esm_proc_default_eps_bearer_context_complete(void); +int esm_proc_default_eps_bearer_context_failure(void); + +int esm_proc_default_eps_bearer_context_accept(int is_standalone, int ebi, OctetString* msg, int ue_triggered); +int esm_proc_default_eps_bearer_context_reject(int is_standalone, int ebi, OctetString* msg, int ue_triggered); +#endif + +/* + * -------------------------------------------------------------------------- + * Dedicated EPS bearer context activation procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +int esm_proc_dedicated_eps_bearer_context(unsigned int ueid, int pid, unsigned int* ebi, unsigned int* default_ebi, const esm_proc_qos_t* qos, const esm_proc_tft_t* tft, int* esm_cause); +int esm_proc_dedicated_eps_bearer_context_request(int is_standalone, unsigned int ueid, int ebi, OctetString* msg, int ue_triggered); + +int esm_proc_dedicated_eps_bearer_context_accept(unsigned int ueid, int ebi, int* esm_cause); +int esm_proc_dedicated_eps_bearer_context_reject(unsigned int ueid, int ebi, int* esm_cause); +#endif + +#ifdef NAS_UE +int esm_proc_dedicated_eps_bearer_context_request(int ebi, int default_ebi, const esm_proc_qos_t* qos, const esm_proc_tft_t* tft, int* esm_cause); + +int esm_proc_dedicated_eps_bearer_context_accept(int is_standalone, int ebi, OctetString* msg, int ue_triggered); +int esm_proc_dedicated_eps_bearer_context_reject(int is_standalone, int ebi, OctetString* msg, int ue_triggered); +#endif + +/* + * -------------------------------------------------------------------------- + * EPS bearer context deactivation procedure + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +int esm_proc_eps_bearer_context_deactivate(unsigned int ueid, int is_local, int ebi, int* pid, int* bid, int* esm_cause); +int esm_proc_eps_bearer_context_deactivate_request(int is_standalone, unsigned int ueid, int ebi, OctetString* msg, int ue_triggered); + +int esm_proc_eps_bearer_context_deactivate_accept(unsigned int ueid, int ebi, int* esm_cause); +#endif + +#ifdef NAS_UE +int esm_proc_eps_bearer_context_deactivate(int is_local, int ebi, int* pid, int* bid); +int esm_proc_eps_bearer_context_deactivate_request(int ebi, int* esm_cause); + +int esm_proc_eps_bearer_context_deactivate_accept(int is_standalone, int ebi, OctetString* msg, int ue_triggered); +#endif + +#endif /* __ESM_PROC_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.c b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.c new file mode 100644 index 0000000000..ff325fb9ff --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.c @@ -0,0 +1,543 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_pt.c + +Version 0.1 + +Date 2013/01/03 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle ESM procedure transactions. + +*****************************************************************************/ + +#include "esm_pt.h" + +#ifdef NAS_UE +#include "commonDef.h" +#include "nas_log.h" + +#include <stdlib.h> // malloc, free +#include <string.h> // memcpy +#endif // NAS_UE + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/* + * Minimal and maximal value of a procedure transaction identity: + * The Procedure Transaction Identity (PTI) identifies bi-directional + * messages flows + */ +#define ESM_PTI_MIN (PROCEDURE_TRANSACTION_IDENTITY_FIRST) +#define ESM_PTI_MAX (PROCEDURE_TRANSACTION_IDENTITY_LAST) + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* String representation of ESM procedure transaction status */ +static const char* _esm_pt_state_str[ESM_PT_STATE_MAX] = { + "PROCEDURE TRANSACTION INACTIVE", + "PROCEDURE TRANSACTION PENDING" +}; + +/* + * -------------------------- + * Procedure transaction data + * -------------------------- + */ +typedef struct { + unsigned char pti; /* Procedure transaction identity */ + esm_pt_state status; /* Procedure transaction status */ + struct nas_timer_t timer; /* Retransmission timer */ + esm_pt_timer_data_t* args; /* Retransmission timer parameters data */ +} esm_pt_context_t; + +/* + * ------------------------------ + * List of procedure transactions + * ------------------------------ + */ +static struct { + unsigned char index; /* Index of the next procedure transaction + * identity to be used */ +#define ESM_PT_DATA_SIZE (ESM_PTI_MAX - ESM_PTI_MIN + 1) + esm_pt_context_t* context[ESM_PT_DATA_SIZE + 1]; +} _esm_pt_data; + +/* Return the index of the next available entry in the list of procedure + * transaction data */ +static int _esm_pt_get_available_entry(void); +#endif // NAS_UE + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_pt_initialize() ** + ** ** + ** Description: Initialize ESM procedure transaction data ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +void esm_pt_initialize(void) +{ + LOG_FUNC_IN; + + _esm_pt_data.index = 0; + for (int i = 0; i < ESM_PT_DATA_SIZE + 1; i++) { + _esm_pt_data.context[i] = NULL; + } + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_assign() ** + ** ** + ** Description: Assigns a new procedure transaction identity ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The identity of the new procedure transac- ** + ** tion when successfully assigned; ** + ** the unassigned PTI (0) otherwise. ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +int esm_pt_assign(void) +{ + LOG_FUNC_IN; + + /* Search for an available procedure transaction identity */ + int i = _esm_pt_get_available_entry(); + if (i < 0) { + LOG_FUNC_RETURN (ESM_PT_UNASSIGNED); + } + + /* Assign new procedure transaction */ + _esm_pt_data.context[i] = + (esm_pt_context_t*)malloc(sizeof(esm_pt_context_t)); + if (_esm_pt_data.context[i] == NULL) { + LOG_FUNC_RETURN (ESM_PT_UNASSIGNED); + } + + /* Store the index of the next available procedure transaction identity */ + _esm_pt_data.index = i + 1; + + /* An available procedure transaction identity is found */ + _esm_pt_data.context[i]->pti = i + ESM_PTI_MIN; + /* Set the procedure transaction status to INACTIVE */ + _esm_pt_data.context[i]->status = ESM_PT_INACTIVE; + /* Disable the retransmission timer */ + _esm_pt_data.context[i]->timer.id = NAS_TIMER_INACTIVE_ID; + /* Setup retransmission timer parameters */ + _esm_pt_data.context[i]->args = NULL; + + LOG_TRACE(INFO, "ESM-FSM - Procedure transaction identity %d assigned", + _esm_pt_data.context[i]->pti); + LOG_FUNC_RETURN (_esm_pt_data.context[i]->pti); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_release() ** + ** ** + ** Description: Release the given procedure transaction identity ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** to release ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok if the procedure transaction iden-** + ** tity has been successfully released; ** + ** RETURNerror otherwise. ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +int esm_pt_release(int pti) +{ + LOG_FUNC_IN; + + if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get procedure transaction data */ + esm_pt_context_t* ctx = _esm_pt_data.context[pti - ESM_PTI_MIN]; + if ( (ctx == NULL) || (ctx->pti != pti) ) { + /* Procedure transaction not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + /* Do not release active procedure transaction */ + if (ctx->status != ESM_PT_INACTIVE) { + LOG_TRACE(ERROR, "ESM-FSM - Procedure transaction is not INACTIVE"); + LOG_FUNC_RETURN (RETURNerror); + } + + /* Stop the retransmission timer if still running */ + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d", + ctx->timer.id); + ctx->timer.id = nas_timer_stop(ctx->timer.id); + } + /* Release the retransmisison timer parameters */ + if (ctx->args) { + if (ctx->args->msg.length > 0) { + free(ctx->args->msg.value); + } + free(ctx->args); + ctx->args = NULL; + } + + /* Release transaction procedure data */ + free(_esm_pt_data.context[pti - ESM_PTI_MIN]); + _esm_pt_data.context[pti - ESM_PTI_MIN] = NULL; + + LOG_TRACE(INFO, "ESM-FSM - Procedure transaction %d released", pti); + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_start_timer() ** + ** ** + ** Description: Start the timer of the specified procedure transaction to ** + ** expire after a given time interval. Timer expiration will ** + ** schedule execution of the callback function where stored ** + ** ESM message should be re-transmit. ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** msg: The encoded ESM message to be stored ** + ** sec: The value of the time interval in seconds ** + ** cb: Function executed upon timer expiration ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +int esm_pt_start_timer(int pti, const OctetString* msg, + long sec, nas_timer_callback_t cb) +{ + LOG_FUNC_IN; + + if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get procedure transaction data */ + esm_pt_context_t* ctx = _esm_pt_data.context[pti - ESM_PTI_MIN]; + if ( (ctx == NULL) || (ctx->pti != pti) ) { + /* Procedure transaction not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + if (ctx->args) { + /* Re-start the retransmission timer */ + ctx->timer.id = nas_timer_restart(ctx->timer.id); + } + } + else { + /* Setup the retransmission timer parameters */ + ctx->args = (esm_pt_timer_data_t*)malloc(sizeof(esm_pt_timer_data_t)); + if (ctx->args) { + /* Set the EPS bearer identity */ + ctx->args->pti = pti; + /* Reset the retransmission counter */ + ctx->args->count = 0; + /* Set the ESM message to be re-transmited */ + ctx->args->msg.value = (uint8_t*)malloc(msg->length); + ctx->args->msg.length = 0; + if (ctx->args->msg.value) { + memcpy(ctx->args->msg.value, msg->value, msg->length); + ctx->args->msg.length = msg->length; + } + /* Setup the retransmission timer to expire at the given + * time interval */ + ctx->timer.id = nas_timer_start(sec, cb, ctx->args); + ctx->timer.sec = sec; + } + } + + if ( (ctx->args != NULL) && (ctx->timer.id != NAS_TIMER_INACTIVE_ID) ) { + LOG_TRACE(INFO, "ESM-FSM - Retransmission timer %d expires in " + "%ld seconds", ctx->timer.id, ctx->timer.sec); + LOG_FUNC_RETURN (RETURNok); + } + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_stop_timer() ** + ** ** + ** Description: Stop the timer previously started for the given procedure ** + ** transaction ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +int esm_pt_stop_timer(int pti) +{ + LOG_FUNC_IN; + + if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get procedure transaction data */ + esm_pt_context_t* ctx = _esm_pt_data.context[pti - ESM_PTI_MIN]; + if ( (ctx == NULL) || (ctx->pti != pti) ) { + /* Procedure transaction not assigned */ + LOG_FUNC_RETURN (RETURNerror); + } + + /* Stop the retransmission timer if still running */ + if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { + LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d", + ctx->timer.id); + ctx->timer.id = nas_timer_stop(ctx->timer.id); + } + + /* Release the retransmisison timer parameters */ + if (ctx->args) { + if (ctx->args->msg.length > 0) { + free(ctx->args->msg.value); + } + free(ctx->args); + ctx->args = NULL; + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_set_status() ** + ** ** + ** Description: Set the status of the specified procedure transaction to ** + ** the given state ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** status: The new ESM procedure transaction status ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_pt_data ** + ** ** + ***************************************************************************/ +int esm_pt_set_status(int pti, esm_pt_state status) +{ + LOG_FUNC_IN; + + esm_pt_state old_status; + + if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { + LOG_FUNC_RETURN (RETURNerror); + } + + /* Get procedure transaction data */ + esm_pt_context_t* ctx = _esm_pt_data.context[pti - ESM_PTI_MIN]; + if ( (ctx == NULL) || (ctx->pti != pti) ) { + /* Procedure transaction not assigned */ + LOG_TRACE(ERROR, "ESM-FSM - Procedure transaction not assigned " + "(pti=%d)", pti); + LOG_FUNC_RETURN (RETURNerror); + } + + old_status = ctx->status; + if (status < ESM_PT_STATE_MAX) { + LOG_TRACE(INFO, "ESM-FSM - Status of procedure transaction %d changed:" + " %s ===> %s", pti, + _esm_pt_state_str[old_status], _esm_pt_state_str[status]); + if (status != old_status) { + ctx->status = status; + LOG_FUNC_RETURN (RETURNok); + } + } + + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_get_status() ** + ** ** + ** Description: Get the current status value of the specified procedure ** + ** transaction ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** Others: _esm_pt_data ** + ** ** + ** Outputs: None ** + ** Return: The current value of the ESM procedure ** + ** transaction status ** + ** Others: None ** + ** ** + ***************************************************************************/ +esm_pt_state esm_pt_get_status(int pti) +{ + if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { + return (ESM_PT_INACTIVE); + } + if (_esm_pt_data.context[pti - ESM_PTI_MIN] == NULL) { + /* Procedure transaction not allocated */ + return (ESM_PT_INACTIVE); + } + if (_esm_pt_data.context[pti - ESM_PTI_MIN]->pti != pti) { + /* Procedure transaction not assigned */ + return (ESM_PT_INACTIVE); + } + return (_esm_pt_data.context[pti - ESM_PTI_MIN]->status); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_get_pending_pti() ** + ** ** + ** Description: Returns the procedure transaction identity assigned to ** + ** the first PDN connection entry which is pending in the ** + ** given state ** + ** ** + ** Inputs: status: The PDN connection status ** + ** Others: _esm_pt_data ** + ** ** + ** Outputs: None ** + ** Return: The procedure transaction identity of the ** + ** PDN connection entry if it exists; ** + ** the unassigned PTI (0) otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_pt_get_pending_pti(esm_pt_state status) +{ + LOG_FUNC_IN; + + int i; + for (i = 0; i < ESM_PT_DATA_SIZE; i++) { + if (_esm_pt_data.context[i] == NULL) continue; + if (_esm_pt_data.context[i]->status != status) continue; + /* PDN connection entry found */ + break; + } + + if (i < ESM_PT_DATA_SIZE) { + LOG_FUNC_RETURN (_esm_pt_data.context[i]->pti); + } + /* PDN connection entry not found */ + LOG_FUNC_RETURN (ESM_PT_UNASSIGNED); +} + +/**************************************************************************** + ** ** + ** Name: esm_pt_is_not_in_use() ** + ** ** + ** Description: Check whether the given procedure transaction identity ** + ** does not match an assigned PTI value currently in use ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** Others: _esm_pt_data ** + ** ** + ** Outputs: None ** + ** Return: TRUE, FALSE ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_pt_is_not_in_use(int pti) +{ + return ( (pti == ESM_PT_UNASSIGNED) || + (_esm_pt_data.context[pti - ESM_PTI_MIN] == NULL) || + (_esm_pt_data.context[pti - ESM_PTI_MIN]->pti) != pti); +} +#endif // NAS_UE + +/**************************************************************************** + ** ** + ** Name: esm_pt_is_reserved() ** + ** ** + ** Description: Check whether the given procedure transaction identity is ** + ** a reserved value ** + ** ** + ** Inputs: pti: The identity of the procedure transaction ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE, FALSE ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_pt_is_reserved(int pti) +{ + return ( (pti != ESM_PT_UNASSIGNED) && (pti > ESM_PTI_MAX) ); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _esm_pt_get_available_entry() ** + ** ** + ** Description: Returns the index of the next available entry in the list ** + ** of procedure transaction data ** + ** ** + ** Inputs: None ** + ** Others: _esm_pt_data ** + ** ** + ** Outputs: None ** + ** Return: The index of the next available procedure ** + ** transaction data entry; -1 if no any entry ** + ** is available. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_pt_get_available_entry(void) +{ + int i; + for (i = _esm_pt_data.index; i < ESM_PT_DATA_SIZE; i++) { + if (_esm_pt_data.context[i] != NULL) continue; + return i; + } + for (i = 0; i < _esm_pt_data.index; i++) { + if (_esm_pt_data.context[i] != NULL) continue; + return i; + } + /* No available PTI entry found */ + return (-1); + } +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.h b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.h new file mode 100644 index 0000000000..5cae104e34 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/esm_pt.h @@ -0,0 +1,84 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_pt.h + +Version 0.1 + +Date 2013/01/03 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions used to handle ESM procedure transactions. + +*****************************************************************************/ +#ifndef __ESM_PT_H__ +#define __ESM_PT_H__ + +#ifdef NAS_UE +#include "OctetString.h" +#include "nas_timer.h" +#endif + +#include "ProcedureTransactionIdentity.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Unassigned procedure transaction identity value */ +#define ESM_PT_UNASSIGNED (PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* Procedure transaction states */ +typedef enum { + ESM_PT_INACTIVE, /* No procedure transaction exists */ + ESM_PT_PENDING, /* The UE has initiated a procedure transaction + * towards the network */ + ESM_PT_STATE_MAX +} esm_pt_state; + +/* ESM message timer retransmission data */ +typedef struct { + unsigned char pti; /* Procedure transaction identity */ + unsigned int count; /* Retransmission counter */ + OctetString msg; /* Encoded ESM message to re-transmit */ +} esm_pt_timer_data_t; +#endif // NAS_UE + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int esm_pt_is_reserved(int pti); + +#ifdef NAS_UE +void esm_pt_initialize(void); + +int esm_pt_assign(void); +int esm_pt_release(int pti); + +int esm_pt_start_timer(int pti, const OctetString* msg, long sec, nas_timer_callback_t cb); +int esm_pt_stop_timer(int pti); + +int esm_pt_set_status(int pti, esm_pt_state status); +esm_pt_state esm_pt_get_status(int pti); +int esm_pt_get_pending_pti(esm_pt_state status); + +int esm_pt_is_not_in_use(int pti); +#endif // NAS_UE + +#endif /* __ESM_PT_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.c new file mode 100644 index 0000000000..21fb5b2b8b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDedicatedEpsBearerContextAccept.h" + +int decode_activate_dedicated_eps_bearer_context_accept(activate_dedicated_eps_bearer_context_accept_msg *activate_dedicated_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_accept->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_accept->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_dedicated_eps_bearer_context_accept(activate_dedicated_eps_bearer_context_accept_msg *activate_dedicated_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + if ((activate_dedicated_eps_bearer_context_accept->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_accept->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h new file mode 100644 index 0000000000..307f712b56 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_H_ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_MAXIMUM_LENGTH ( \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum activate_dedicated_eps_bearer_context_accept_iei_tag { + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_dedicated_eps_bearer_context_accept_iei; + +/* + * Message name: Activate dedicated EPS bearer context accept + * Description: This message is sent by the UE to the network to acknowledge activation of a dedicated EPS bearer context associated with the same PDN address(es) and APN as an already active EPS bearer context. See table 8.3.1.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct activate_dedicated_eps_bearer_context_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_dedicated_eps_bearer_context_accept_msg; + +int decode_activate_dedicated_eps_bearer_context_accept(activate_dedicated_eps_bearer_context_accept_msg *activatededicatedepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +int encode_activate_dedicated_eps_bearer_context_accept(activate_dedicated_eps_bearer_context_accept_msg *activatededicatedepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.c new file mode 100644 index 0000000000..858e69aaf4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDedicatedEpsBearerContextReject.h" + +int decode_activate_dedicated_eps_bearer_context_reject(activate_dedicated_eps_bearer_context_reject_msg *activate_dedicated_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&activate_dedicated_eps_bearer_context_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_reject->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_reject->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_dedicated_eps_bearer_context_reject(activate_dedicated_eps_bearer_context_reject_msg *activate_dedicated_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&activate_dedicated_eps_bearer_context_reject->esmcause, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((activate_dedicated_eps_bearer_context_reject->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_reject->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h new file mode 100644 index 0000000000..072644d66b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_H_ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum activate_dedicated_eps_bearer_context_reject_iei_tag { + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_dedicated_eps_bearer_context_reject_iei; + +/* + * Message name: Activate dedicated EPS bearer context reject + * Description: This message is sent by UE to the network to reject activation of a dedicated EPS bearer context. See table 8.3.2.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct activate_dedicated_eps_bearer_context_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_dedicated_eps_bearer_context_reject_msg; + +int decode_activate_dedicated_eps_bearer_context_reject(activate_dedicated_eps_bearer_context_reject_msg *activatededicatedepsbearercontextreject, uint8_t *buffer, uint32_t len); + +int encode_activate_dedicated_eps_bearer_context_reject(activate_dedicated_eps_bearer_context_reject_msg *activatededicatedepsbearercontextreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.c new file mode 100644 index 0000000000..88b0713323 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.c @@ -0,0 +1,215 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDedicatedEpsBearerContextRequest.h" + +int decode_activate_dedicated_eps_bearer_context_request(activate_dedicated_eps_bearer_context_request_msg *activate_dedicated_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_linked_eps_bearer_identity(&activate_dedicated_eps_bearer_context_request->linkedepsbeareridentity, 0, *(buffer + decoded), len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_eps_quality_of_service(&activate_dedicated_eps_bearer_context_request->epsqos, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_traffic_flow_template(&activate_dedicated_eps_bearer_context_request->tft, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI: + if ((decoded_result = + decode_transaction_identifier(&activate_dedicated_eps_bearer_context_request->transactionidentifier, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT; + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI: + if ((decoded_result = + decode_quality_of_service(&activate_dedicated_eps_bearer_context_request->negotiatedqos, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT; + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI: + if ((decoded_result = + decode_llc_service_access_point_identifier(&activate_dedicated_eps_bearer_context_request->negotiatedllcsapi, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT; + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI: + if ((decoded_result = + decode_radio_priority(&activate_dedicated_eps_bearer_context_request->radiopriority, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT; + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI: + if ((decoded_result = + decode_packet_flow_identifier(&activate_dedicated_eps_bearer_context_request->packetflowidentifier, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT; + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_request->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_dedicated_eps_bearer_context_request->presencemask |= ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_dedicated_eps_bearer_context_request(activate_dedicated_eps_bearer_context_request_msg *activate_dedicated_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = encode_u8_linked_eps_bearer_identity(&activate_dedicated_eps_bearer_context_request->linkedepsbeareridentity) & 0x0f; + encoded++; + if ((encode_result = + encode_eps_quality_of_service(&activate_dedicated_eps_bearer_context_request->epsqos, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_traffic_flow_template(&activate_dedicated_eps_bearer_context_request->tft, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_transaction_identifier(&activate_dedicated_eps_bearer_context_request->transactionidentifier, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT) + { + if ((encode_result = + encode_quality_of_service(&activate_dedicated_eps_bearer_context_request->negotiatedqos, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + { + if ((encode_result = + encode_llc_service_access_point_identifier(&activate_dedicated_eps_bearer_context_request->negotiatedllcsapi, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + { + if ((encode_result = + encode_radio_priority(&activate_dedicated_eps_bearer_context_request->radiopriority, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_packet_flow_identifier(&activate_dedicated_eps_bearer_context_request->packetflowidentifier, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_dedicated_eps_bearer_context_request->presencemask & ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_dedicated_eps_bearer_context_request->protocolconfigurationoptions, + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h new file mode 100644 index 0000000000..c56a627ba7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "LinkedEpsBearerIdentity.h" +#include "EpsQualityOfService.h" +#include "TrafficFlowTemplate.h" +#include "TransactionIdentifier.h" +#include "QualityOfService.h" +#include "LlcServiceAccessPointIdentifier.h" +#include "RadioPriority.h" +#include "PacketFlowIdentifier.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_H_ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH ( \ + EPS_QUALITY_OF_SERVICE_MINIMUM_LENGTH + \ + TRAFFIC_FLOW_TEMPLATE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_MAXIMUM_LENGTH ( \ + EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + TRAFFIC_FLOW_TEMPLATE_MAXIMUM_LENGTH + \ + TRANSACTION_IDENTIFIER_MAXIMUM_LENGTH + \ + QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MAXIMUM_LENGTH + \ + RADIO_PRIORITY_MAXIMUM_LENGTH + \ + PACKET_FLOW_IDENTIFIER_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT (1<<0) +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT (1<<1) +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT (1<<2) +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT (1<<3) +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT (1<<4) +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<5) + +typedef enum activate_dedicated_eps_bearer_context_request_iei_tag { + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI = 0x5D, /* 0x5D = 93 */ + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI = 0x30, /* 0x30 = 48 */ + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI = 0x32, /* 0x32 = 50 */ + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI = 0x80, /* 0x80 = 128 */ + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI = 0x34, /* 0x34 = 52 */ + ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_dedicated_eps_bearer_context_request_iei; + +/* + * Message name: Activate dedicated EPS bearer context request + * Description: This message is sent by the network to the UE to request activation of a dedicated EPS bearer context associated with the same PDN address(es) and APN as an already active default EPS bearer context. See table 8.3.3.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct activate_dedicated_eps_bearer_context_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + LinkedEpsBearerIdentity linkedepsbeareridentity; + EpsQualityOfService epsqos; + TrafficFlowTemplate tft; + /* Optional fields */ + uint32_t presencemask; + TransactionIdentifier transactionidentifier; + QualityOfService negotiatedqos; + LlcServiceAccessPointIdentifier negotiatedllcsapi; + RadioPriority radiopriority; + PacketFlowIdentifier packetflowidentifier; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_dedicated_eps_bearer_context_request_msg; + +int decode_activate_dedicated_eps_bearer_context_request(activate_dedicated_eps_bearer_context_request_msg *activatededicatedepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +int encode_activate_dedicated_eps_bearer_context_request(activate_dedicated_eps_bearer_context_request_msg *activatededicatedepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.c new file mode 100644 index 0000000000..5a10cd46fb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDefaultEpsBearerContextAccept.h" + +int decode_activate_default_eps_bearer_context_accept(activate_default_eps_bearer_context_accept_msg *activate_default_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_default_eps_bearer_context_accept->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_accept->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_default_eps_bearer_context_accept(activate_default_eps_bearer_context_accept_msg *activate_default_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + if ((activate_default_eps_bearer_context_accept->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_default_eps_bearer_context_accept->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h new file mode 100644 index 0000000000..b1f02c484e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_H_ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_MAXIMUM_LENGTH ( \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum activate_default_eps_bearer_context_accept_iei_tag { + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_default_eps_bearer_context_accept_iei; + +/* + * Message name: Activate default EPS bearer context accept + * Description: This message is sent by the UE to the network to acknowledge activation of a default EPS bearer context. See table 8.3.4.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct activate_default_eps_bearer_context_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_default_eps_bearer_context_accept_msg; + +int decode_activate_default_eps_bearer_context_accept(activate_default_eps_bearer_context_accept_msg *activatedefaultepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +int encode_activate_default_eps_bearer_context_accept(activate_default_eps_bearer_context_accept_msg *activatedefaultepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.c new file mode 100644 index 0000000000..ce5a3d087d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDefaultEpsBearerContextReject.h" + +int decode_activate_default_eps_bearer_context_reject(activate_default_eps_bearer_context_reject_msg *activate_default_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&activate_default_eps_bearer_context_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_default_eps_bearer_context_reject->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_reject->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_default_eps_bearer_context_reject(activate_default_eps_bearer_context_reject_msg *activate_default_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&activate_default_eps_bearer_context_reject->esmcause, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((activate_default_eps_bearer_context_reject->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_default_eps_bearer_context_reject->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h new file mode 100644 index 0000000000..613c07d2b4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_H_ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum activate_default_eps_bearer_context_reject_iei_tag { + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_default_eps_bearer_context_reject_iei; + +/* + * Message name: Activate default EPS bearer context reject + * Description: This message is sent by UE to the network to reject activation of a default EPS bearer context. See table 8.3.5.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct activate_default_eps_bearer_context_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_default_eps_bearer_context_reject_msg; + +int decode_activate_default_eps_bearer_context_reject(activate_default_eps_bearer_context_reject_msg *activatedefaultepsbearercontextreject, uint8_t *buffer, uint32_t len); + +int encode_activate_default_eps_bearer_context_reject(activate_default_eps_bearer_context_reject_msg *activatedefaultepsbearercontextreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.c new file mode 100644 index 0000000000..e99c238e9c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.c @@ -0,0 +1,267 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ActivateDefaultEpsBearerContextRequest.h" + +int decode_activate_default_eps_bearer_context_request(activate_default_eps_bearer_context_request_msg *activate_default_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_eps_quality_of_service(&activate_default_eps_bearer_context_request->epsqos, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_access_point_name(&activate_default_eps_bearer_context_request->accesspointname, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_pdn_address(&activate_default_eps_bearer_context_request->pdnaddress, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI: + if ((decoded_result = + decode_transaction_identifier(&activate_default_eps_bearer_context_request->transactionidentifier, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI: + if ((decoded_result = + decode_quality_of_service(&activate_default_eps_bearer_context_request->negotiatedqos, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI: + if ((decoded_result = + decode_llc_service_access_point_identifier(&activate_default_eps_bearer_context_request->negotiatedllcsapi, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI: + if ((decoded_result = + decode_radio_priority(&activate_default_eps_bearer_context_request->radiopriority, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI: + if ((decoded_result = + decode_packet_flow_identifier(&activate_default_eps_bearer_context_request->packetflowidentifier, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI: + if ((decoded_result = + decode_apn_aggregate_maximum_bit_rate(&activate_default_eps_bearer_context_request->apnambr, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_IEI: + if ((decoded_result = + decode_esm_cause(&activate_default_eps_bearer_context_request->esmcause, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT; + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&activate_default_eps_bearer_context_request->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + activate_default_eps_bearer_context_request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_activate_default_eps_bearer_context_request(activate_default_eps_bearer_context_request_msg *activate_default_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_eps_quality_of_service(&activate_default_eps_bearer_context_request->epsqos, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_access_point_name(&activate_default_eps_bearer_context_request->accesspointname, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_pdn_address(&activate_default_eps_bearer_context_request->pdnaddress, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_transaction_identifier(&activate_default_eps_bearer_context_request->transactionidentifier, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT) + { + if ((encode_result = + encode_quality_of_service(&activate_default_eps_bearer_context_request->negotiatedqos, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + { + if ((encode_result = + encode_llc_service_access_point_identifier(&activate_default_eps_bearer_context_request->negotiatedllcsapi, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + { + if ((encode_result = + encode_radio_priority(&activate_default_eps_bearer_context_request->radiopriority, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_packet_flow_identifier(&activate_default_eps_bearer_context_request->packetflowidentifier, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT) + { + if ((encode_result = + encode_apn_aggregate_maximum_bit_rate(&activate_default_eps_bearer_context_request->apnambr, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT) + { + if ((encode_result = + encode_esm_cause(&activate_default_eps_bearer_context_request->esmcause, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((activate_default_eps_bearer_context_request->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&activate_default_eps_bearer_context_request->protocolconfigurationoptions, + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h new file mode 100644 index 0000000000..d2ef0182af --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h @@ -0,0 +1,100 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EpsQualityOfService.h" +#include "AccessPointName.h" +#include "PdnAddress.h" +#include "TransactionIdentifier.h" +#include "QualityOfService.h" +#include "LlcServiceAccessPointIdentifier.h" +#include "RadioPriority.h" +#include "PacketFlowIdentifier.h" +#include "ApnAggregateMaximumBitRate.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_H_ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH ( \ + EPS_QUALITY_OF_SERVICE_MINIMUM_LENGTH + \ + ACCESS_POINT_NAME_MINIMUM_LENGTH + \ + PDN_ADDRESS_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MAXIMUM_LENGTH ( \ + EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + ACCESS_POINT_NAME_MAXIMUM_LENGTH + \ + PDN_ADDRESS_MAXIMUM_LENGTH + \ + TRANSACTION_IDENTIFIER_MAXIMUM_LENGTH + \ + QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MAXIMUM_LENGTH + \ + RADIO_PRIORITY_MAXIMUM_LENGTH + \ + PACKET_FLOW_IDENTIFIER_MAXIMUM_LENGTH + \ + APN_AGGREGATE_MAXIMUM_BIT_RATE_MAXIMUM_LENGTH + \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_PRESENT (1<<0) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_PRESENT (1<<1) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT (1<<2) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT (1<<3) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT (1<<4) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT (1<<5) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT (1<<6) +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<7) + +typedef enum activate_default_eps_bearer_context_request_iei_tag { + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_TRANSACTION_IDENTIFIER_IEI = 0x5D, /* 0x5D = 93 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_QOS_IEI = 0x30, /* 0x30 = 48 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI = 0x32, /* 0x32 = 50 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI = 0x80, /* 0x80 = 128 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI = 0x34, /* 0x34 = 52 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI = 0x5E, /* 0x5E = 94 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_IEI = 0x58, /* 0x58 = 88 */ + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} activate_default_eps_bearer_context_request_iei; + +/* + * Message name: Activate default EPS bearer context request + * Description: This message is sent by the network to the UE to request activation of a default EPS bearer context. See table 8.3.6.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct activate_default_eps_bearer_context_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EpsQualityOfService epsqos; + AccessPointName accesspointname; + PdnAddress pdnaddress; + /* Optional fields */ + uint32_t presencemask; + TransactionIdentifier transactionidentifier; + QualityOfService negotiatedqos; + LlcServiceAccessPointIdentifier negotiatedllcsapi; + RadioPriority radiopriority; + PacketFlowIdentifier packetflowidentifier; + ApnAggregateMaximumBitRate apnambr; + EsmCause esmcause; + ProtocolConfigurationOptions protocolconfigurationoptions; +} activate_default_eps_bearer_context_request_msg; + +int decode_activate_default_eps_bearer_context_request(activate_default_eps_bearer_context_request_msg *activatedefaultepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +int encode_activate_default_eps_bearer_context_request(activate_default_eps_bearer_context_request_msg *activatedefaultepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.c new file mode 100644 index 0000000000..1dfc2a89f4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "BearerResourceAllocationReject.h" + +int decode_bearer_resource_allocation_reject(bearer_resource_allocation_reject_msg *bearer_resource_allocation_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, BEARER_RESOURCE_ALLOCATION_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&bearer_resource_allocation_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&bearer_resource_allocation_reject->protocolconfigurationoptions, + BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_allocation_reject->presencemask |= BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_bearer_resource_allocation_reject(bearer_resource_allocation_reject_msg *bearer_resource_allocation_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, BEARER_RESOURCE_ALLOCATION_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&bearer_resource_allocation_reject->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((bearer_resource_allocation_reject->presencemask & BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&bearer_resource_allocation_reject->protocolconfigurationoptions, + BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h new file mode 100644 index 0000000000..8f2a0e471a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef BEARER_RESOURCE_ALLOCATION_REJECT_H_ +#define BEARER_RESOURCE_ALLOCATION_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define BEARER_RESOURCE_ALLOCATION_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define BEARER_RESOURCE_ALLOCATION_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum bearer_resource_allocation_reject_iei_tag { + BEARER_RESOURCE_ALLOCATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} bearer_resource_allocation_reject_iei; + +/* + * Message name: Bearer resource allocation reject + * Description: This message is sent by the network to the UE to reject the allocation of a dedicated bearer resource. See table 8.3.7.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct bearer_resource_allocation_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} bearer_resource_allocation_reject_msg; + +int decode_bearer_resource_allocation_reject(bearer_resource_allocation_reject_msg *bearerresourceallocationreject, uint8_t *buffer, uint32_t len); + +int encode_bearer_resource_allocation_reject(bearer_resource_allocation_reject_msg *bearerresourceallocationreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(BEARER_RESOURCE_ALLOCATION_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.c new file mode 100644 index 0000000000..e7f3ee7048 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.c @@ -0,0 +1,100 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "BearerResourceAllocationRequest.h" + +int decode_bearer_resource_allocation_request(bearer_resource_allocation_request_msg *bearer_resource_allocation_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, BEARER_RESOURCE_ALLOCATION_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_linked_eps_bearer_identity(&bearer_resource_allocation_request->linkedepsbeareridentity, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_traffic_flow_aggregate_description(&bearer_resource_allocation_request->trafficflowaggregate, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + if ((decoded_result = decode_eps_quality_of_service(&bearer_resource_allocation_request->requiredtrafficflowqos, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&bearer_resource_allocation_request->protocolconfigurationoptions, + BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_allocation_request->presencemask |= BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_bearer_resource_allocation_request(bearer_resource_allocation_request_msg *bearer_resource_allocation_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, BEARER_RESOURCE_ALLOCATION_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_linked_eps_bearer_identity(&bearer_resource_allocation_request->linkedepsbeareridentity) & 0x0f) << 4) | 0x00; + encoded++; + if ((encode_result = + encode_traffic_flow_aggregate_description(&bearer_resource_allocation_request->trafficflowaggregate, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((encode_result = + encode_eps_quality_of_service(&bearer_resource_allocation_request->requiredtrafficflowqos, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((bearer_resource_allocation_request->presencemask & BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&bearer_resource_allocation_request->protocolconfigurationoptions, + BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h new file mode 100644 index 0000000000..58c1ba1d40 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "LinkedEpsBearerIdentity.h" +#include "TrafficFlowAggregateDescription.h" +#include "EpsQualityOfService.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef BEARER_RESOURCE_ALLOCATION_REQUEST_H_ +#define BEARER_RESOURCE_ALLOCATION_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define BEARER_RESOURCE_ALLOCATION_REQUEST_MINIMUM_LENGTH ( \ + TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MINIMUM_LENGTH + \ + EPS_QUALITY_OF_SERVICE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define BEARER_RESOURCE_ALLOCATION_REQUEST_MAXIMUM_LENGTH ( \ + TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MAXIMUM_LENGTH + \ + EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum bearer_resource_allocation_request_iei_tag { + BEARER_RESOURCE_ALLOCATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} bearer_resource_allocation_request_iei; + +/* + * Message name: Bearer resource allocation request + * Description: This message is sent by the UE to the network to request the allocation of a dedicated bearer resource. See table 8.3.8.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct bearer_resource_allocation_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + LinkedEpsBearerIdentity linkedepsbeareridentity; + TrafficFlowAggregateDescription trafficflowaggregate; + EpsQualityOfService requiredtrafficflowqos; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} bearer_resource_allocation_request_msg; + +int decode_bearer_resource_allocation_request(bearer_resource_allocation_request_msg *bearerresourceallocationrequest, uint8_t *buffer, uint32_t len); + +int encode_bearer_resource_allocation_request(bearer_resource_allocation_request_msg *bearerresourceallocationrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(BEARER_RESOURCE_ALLOCATION_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.c new file mode 100644 index 0000000000..00c4107bf1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "BearerResourceModificationReject.h" + +int decode_bearer_resource_modification_reject(bearer_resource_modification_reject_msg *bearer_resource_modification_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, BEARER_RESOURCE_MODIFICATION_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&bearer_resource_modification_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&bearer_resource_modification_reject->protocolconfigurationoptions, + BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_modification_reject->presencemask |= BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_bearer_resource_modification_reject(bearer_resource_modification_reject_msg *bearer_resource_modification_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, BEARER_RESOURCE_MODIFICATION_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&bearer_resource_modification_reject->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((bearer_resource_modification_reject->presencemask & BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&bearer_resource_modification_reject->protocolconfigurationoptions, + BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h new file mode 100644 index 0000000000..ddb2971499 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef BEARER_RESOURCE_MODIFICATION_REJECT_H_ +#define BEARER_RESOURCE_MODIFICATION_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define BEARER_RESOURCE_MODIFICATION_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define BEARER_RESOURCE_MODIFICATION_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum bearer_resource_modification_reject_iei_tag { + BEARER_RESOURCE_MODIFICATION_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} bearer_resource_modification_reject_iei; + +/* + * Message name: Bearer resource modification reject + * Description: This message is sent by the network to the UE to reject the modification of a dedicated bearer resource. See table 8.3.9.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct bearer_resource_modification_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} bearer_resource_modification_reject_msg; + +int decode_bearer_resource_modification_reject(bearer_resource_modification_reject_msg *bearerresourcemodificationreject, uint8_t *buffer, uint32_t len); + +int encode_bearer_resource_modification_reject(bearer_resource_modification_reject_msg *bearerresourcemodificationreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(BEARER_RESOURCE_MODIFICATION_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.c new file mode 100644 index 0000000000..006ce9430c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.c @@ -0,0 +1,134 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "BearerResourceModificationRequest.h" + +int decode_bearer_resource_modification_request(bearer_resource_modification_request_msg *bearer_resource_modification_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, BEARER_RESOURCE_MODIFICATION_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_linked_eps_bearer_identity(&bearer_resource_modification_request->epsbeareridentityforpacketfilter, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + decoded++; + if ((decoded_result = decode_traffic_flow_aggregate_description(&bearer_resource_modification_request->trafficflowaggregate, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_IEI: + if ((decoded_result = + decode_eps_quality_of_service(&bearer_resource_modification_request->requiredtrafficflowqos, + BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_modification_request->presencemask |= BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_PRESENT; + break; + case BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_IEI: + if ((decoded_result = + decode_esm_cause(&bearer_resource_modification_request->esmcause, + BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_modification_request->presencemask |= BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_PRESENT; + break; + case BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&bearer_resource_modification_request->protocolconfigurationoptions, + BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + bearer_resource_modification_request->presencemask |= BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_bearer_resource_modification_request(bearer_resource_modification_request_msg *bearer_resource_modification_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, BEARER_RESOURCE_MODIFICATION_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_linked_eps_bearer_identity(&bearer_resource_modification_request->epsbeareridentityforpacketfilter) & 0x0f) << 4) | 0x00; + encoded++; + if ((encode_result = + encode_traffic_flow_aggregate_description(&bearer_resource_modification_request->trafficflowaggregate, + 0, buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((bearer_resource_modification_request->presencemask & BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_PRESENT) + == BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_PRESENT) + { + if ((encode_result = + encode_eps_quality_of_service(&bearer_resource_modification_request->requiredtrafficflowqos, + BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((bearer_resource_modification_request->presencemask & BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_PRESENT) + == BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_PRESENT) + { + if ((encode_result = + encode_esm_cause(&bearer_resource_modification_request->esmcause, + BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((bearer_resource_modification_request->presencemask & BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&bearer_resource_modification_request->protocolconfigurationoptions, + BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h new file mode 100644 index 0000000000..b731e254d1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "LinkedEpsBearerIdentity.h" +#include "TrafficFlowAggregateDescription.h" +#include "EpsQualityOfService.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef BEARER_RESOURCE_MODIFICATION_REQUEST_H_ +#define BEARER_RESOURCE_MODIFICATION_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define BEARER_RESOURCE_MODIFICATION_REQUEST_MINIMUM_LENGTH ( \ + TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define BEARER_RESOURCE_MODIFICATION_REQUEST_MAXIMUM_LENGTH ( \ + TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MAXIMUM_LENGTH + \ + EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_PRESENT (1<<0) +# define BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_PRESENT (1<<1) +# define BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<2) + +typedef enum bearer_resource_modification_request_iei_tag { + BEARER_RESOURCE_MODIFICATION_REQUEST_REQUIRED_TRAFFIC_FLOW_QOS_IEI = 0x5B, /* 0x5B = 91 */ + BEARER_RESOURCE_MODIFICATION_REQUEST_ESM_CAUSE_IEI = 0x58, /* 0x58 = 88 */ + BEARER_RESOURCE_MODIFICATION_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} bearer_resource_modification_request_iei; + +/* + * Message name: Bearer resource modification request + * Description: This message is sent by the UE to the network to request the modification of a dedicated bearer resource. See table 8.3.10.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct bearer_resource_modification_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + LinkedEpsBearerIdentity epsbeareridentityforpacketfilter; + TrafficFlowAggregateDescription trafficflowaggregate; + /* Optional fields */ + uint32_t presencemask; + EpsQualityOfService requiredtrafficflowqos; + EsmCause esmcause; + ProtocolConfigurationOptions protocolconfigurationoptions; +} bearer_resource_modification_request_msg; + +int decode_bearer_resource_modification_request(bearer_resource_modification_request_msg *bearerresourcemodificationrequest, uint8_t *buffer, uint32_t len); + +int encode_bearer_resource_modification_request(bearer_resource_modification_request_msg *bearerresourcemodificationrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(BEARER_RESOURCE_MODIFICATION_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.c new file mode 100644 index 0000000000..108c10e106 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DeactivateEpsBearerContextAccept.h" + +int decode_deactivate_eps_bearer_context_accept(deactivate_eps_bearer_context_accept_msg *deactivate_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&deactivate_eps_bearer_context_accept->protocolconfigurationoptions, + DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + deactivate_eps_bearer_context_accept->presencemask |= DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_deactivate_eps_bearer_context_accept(deactivate_eps_bearer_context_accept_msg *deactivate_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + if ((deactivate_eps_bearer_context_accept->presencemask & DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&deactivate_eps_bearer_context_accept->protocolconfigurationoptions, + DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h new file mode 100644 index 0000000000..6afad5c1f5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_H_ +#define DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_MAXIMUM_LENGTH ( \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum deactivate_eps_bearer_context_accept_iei_tag { + DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} deactivate_eps_bearer_context_accept_iei; + +/* + * Message name: Deactivate EPS bearer context accept + * Description: This message is sent by the UE to acknowledge deactivation of the EPS bearer context requested in the corresponding Deactivate EPS bearer context request message. See table 8.3.11.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct deactivate_eps_bearer_context_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} deactivate_eps_bearer_context_accept_msg; + +int decode_deactivate_eps_bearer_context_accept(deactivate_eps_bearer_context_accept_msg *deactivateepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +int encode_deactivate_eps_bearer_context_accept(deactivate_eps_bearer_context_accept_msg *deactivateepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.c new file mode 100644 index 0000000000..6e29e603e4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DeactivateEpsBearerContextRequest.h" + +int decode_deactivate_eps_bearer_context_request(deactivate_eps_bearer_context_request_msg *deactivate_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&deactivate_eps_bearer_context_request->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&deactivate_eps_bearer_context_request->protocolconfigurationoptions, + DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + deactivate_eps_bearer_context_request->presencemask |= DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_deactivate_eps_bearer_context_request(deactivate_eps_bearer_context_request_msg *deactivate_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&deactivate_eps_bearer_context_request->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((deactivate_eps_bearer_context_request->presencemask & DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&deactivate_eps_bearer_context_request->protocolconfigurationoptions, + DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h new file mode 100644 index 0000000000..ea5a8ca2ea --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_H_ +#define DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum deactivate_eps_bearer_context_request_iei_tag { + DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} deactivate_eps_bearer_context_request_iei; + +/* + * Message name: Deactivate EPS bearer context request + * Description: This message is sent by the network to request deactivation of an active EPS bearer context. See table 8.3.12.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct deactivate_eps_bearer_context_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} deactivate_eps_bearer_context_request_msg; + +int decode_deactivate_eps_bearer_context_request(deactivate_eps_bearer_context_request_msg *deactivateepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +int encode_deactivate_eps_bearer_context_request(deactivate_eps_bearer_context_request_msg *deactivateepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.c new file mode 100644 index 0000000000..643e1a4ed6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.c @@ -0,0 +1,31 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmInformationRequest.h" + +int decode_esm_information_request(esm_information_request_msg *esm_information_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ESM_INFORMATION_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + return decoded; +} + +int encode_esm_information_request(esm_information_request_msg *esm_information_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_INFORMATION_REQUEST_MINIMUM_LENGTH, len); + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h new file mode 100644 index 0000000000..5b9d070e42 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h @@ -0,0 +1,39 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" + +#ifndef ESM_INFORMATION_REQUEST_H_ +#define ESM_INFORMATION_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ESM_INFORMATION_REQUEST_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ESM_INFORMATION_REQUEST_MAXIMUM_LENGTH (0) + +/* + * Message name: ESM information request + * Description: This message is sent by the network to the UE to request the UE to provide ESM information, i.e. protocol configuration options or APN or both. See table 8.3.13.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct esm_information_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; +} esm_information_request_msg; + +int decode_esm_information_request(esm_information_request_msg *esminformationrequest, uint8_t *buffer, uint32_t len); + +int encode_esm_information_request(esm_information_request_msg *esminformationrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ESM_INFORMATION_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.c new file mode 100644 index 0000000000..a213f9e1a6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.c @@ -0,0 +1,93 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmInformationResponse.h" + +int decode_esm_information_response(esm_information_response_msg *esm_information_response, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ESM_INFORMATION_RESPONSE_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_IEI: + if ((decoded_result = + decode_access_point_name(&esm_information_response->accesspointname, + ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + esm_information_response->presencemask |= ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_PRESENT; + break; + case ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&esm_information_response->protocolconfigurationoptions, + ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + esm_information_response->presencemask |= ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_esm_information_response(esm_information_response_msg *esm_information_response, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_INFORMATION_RESPONSE_MINIMUM_LENGTH, len); + + if ((esm_information_response->presencemask & ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_PRESENT) + == ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_PRESENT) + { + if ((encode_result = + encode_access_point_name(&esm_information_response->accesspointname, + ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((esm_information_response->presencemask & ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&esm_information_response->protocolconfigurationoptions, + ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h new file mode 100644 index 0000000000..00d0020e12 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h @@ -0,0 +1,58 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "AccessPointName.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef ESM_INFORMATION_RESPONSE_H_ +#define ESM_INFORMATION_RESPONSE_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ESM_INFORMATION_RESPONSE_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ESM_INFORMATION_RESPONSE_MAXIMUM_LENGTH ( \ + ACCESS_POINT_NAME_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_PRESENT (1<<0) +# define ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<1) + +typedef enum esm_information_response_iei_tag { + ESM_INFORMATION_RESPONSE_ACCESS_POINT_NAME_IEI = 0x28, /* 0x28 = 40 */ + ESM_INFORMATION_RESPONSE_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} esm_information_response_iei; + +/* + * Message name: ESM information response + * Description: This message is sent by the UE to the network in response to an ESM INFORMATION REQUEST message and provides the requested ESM information. See table 8.3.14.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct esm_information_response_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + AccessPointName accesspointname; + ProtocolConfigurationOptions protocolconfigurationoptions; +} esm_information_response_msg; + +int decode_esm_information_response(esm_information_response_msg *esminformationresponse, uint8_t *buffer, uint32_t len); + +int encode_esm_information_response(esm_information_response_msg *esminformationresponse, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ESM_INFORMATION_RESPONSE_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.c new file mode 100644 index 0000000000..c202c0b3bb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.c @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmStatus.h" + +int decode_esm_status(esm_status_msg *esm_status, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ESM_STATUS_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&esm_status->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + return decoded; +} + +int encode_esm_status(esm_status_msg *esm_status, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_STATUS_MINIMUM_LENGTH, len); + + if ((encode_result = encode_esm_cause(&esm_status->esmcause, 0, buffer + + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h new file mode 100644 index 0000000000..80941a52a2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h @@ -0,0 +1,44 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" + +#ifndef ESM_STATUS_H_ +#define ESM_STATUS_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define ESM_STATUS_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define ESM_STATUS_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH ) + + +/* + * Message name: ESM status + * Description: This message is sent by the network or the UE to pass information on the status of the indicated EPS bearer context and report certain error conditions (e.g. as listed in clause 7). See table 8.3.15.1. + * Significance: dual + * Direction: both + */ + +typedef struct esm_status_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; +} esm_status_msg; + +int decode_esm_status(esm_status_msg *esmstatus, uint8_t *buffer, uint32_t len); + +int encode_esm_status(esm_status_msg *esmstatus, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(ESM_STATUS_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/Makefile b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/Makefile new file mode 100644 index 0000000000..833fecc901 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/Makefile @@ -0,0 +1,41 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(IESDIR) + +TARGET = $(LIBESMMSG) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c %.h Makefile $(LIBDIR)/$(LIBIES).a $(UTILDIR)/TLVEncoder.h $(UTILDIR)/TLVDecoder.h + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.c new file mode 100644 index 0000000000..4cb2ff209b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ModifyEpsBearerContextAccept.h" + +int decode_modify_eps_bearer_context_accept(modify_eps_bearer_context_accept_msg *modify_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&modify_eps_bearer_context_accept->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_accept->presencemask |= MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_modify_eps_bearer_context_accept(modify_eps_bearer_context_accept_msg *modify_eps_bearer_context_accept, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH, len); + + if ((modify_eps_bearer_context_accept->presencemask & MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&modify_eps_bearer_context_accept->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h new file mode 100644 index 0000000000..2dcfac1476 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef MODIFY_EPS_BEARER_CONTEXT_ACCEPT_H_ +#define MODIFY_EPS_BEARER_CONTEXT_ACCEPT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define MODIFY_EPS_BEARER_CONTEXT_ACCEPT_MAXIMUM_LENGTH ( \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum modify_eps_bearer_context_accept_iei_tag { + MODIFY_EPS_BEARER_CONTEXT_ACCEPT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} modify_eps_bearer_context_accept_iei; + +/* + * Message name: Modify EPS bearer context accept + * Description: This message is sent by the UE to the network to acknowledge the modification of an active EPS bearer context. See table 8.3.16.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct modify_eps_bearer_context_accept_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} modify_eps_bearer_context_accept_msg; + +int decode_modify_eps_bearer_context_accept(modify_eps_bearer_context_accept_msg *modifyepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +int encode_modify_eps_bearer_context_accept(modify_eps_bearer_context_accept_msg *modifyepsbearercontextaccept, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(MODIFY_EPS_BEARER_CONTEXT_ACCEPT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.c new file mode 100644 index 0000000000..05f9c386f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ModifyEpsBearerContextReject.h" + +int decode_modify_eps_bearer_context_reject(modify_eps_bearer_context_reject_msg *modify_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, MODIFY_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&modify_eps_bearer_context_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&modify_eps_bearer_context_reject->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_reject->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_modify_eps_bearer_context_reject(modify_eps_bearer_context_reject_msg *modify_eps_bearer_context_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MODIFY_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = + encode_esm_cause(&modify_eps_bearer_context_reject->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((modify_eps_bearer_context_reject->presencemask & MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&modify_eps_bearer_context_reject->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h new file mode 100644 index 0000000000..e23c59d483 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef MODIFY_EPS_BEARER_CONTEXT_REJECT_H_ +#define MODIFY_EPS_BEARER_CONTEXT_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define MODIFY_EPS_BEARER_CONTEXT_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define MODIFY_EPS_BEARER_CONTEXT_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum modify_eps_bearer_context_reject_iei_tag { + MODIFY_EPS_BEARER_CONTEXT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} modify_eps_bearer_context_reject_iei; + +/* + * Message name: Modify EPS bearer context reject + * Description: This message is sent by the UE or the network to reject a modification of an active EPS bearer context. See table 8.3.17.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct modify_eps_bearer_context_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} modify_eps_bearer_context_reject_msg; + +int decode_modify_eps_bearer_context_reject(modify_eps_bearer_context_reject_msg *modifyepsbearercontextreject, uint8_t *buffer, uint32_t len); + +int encode_modify_eps_bearer_context_reject(modify_eps_bearer_context_reject_msg *modifyepsbearercontextreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(MODIFY_EPS_BEARER_CONTEXT_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.c new file mode 100644 index 0000000000..3ff75b171d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.c @@ -0,0 +1,231 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ModifyEpsBearerContextRequest.h" + +int decode_modify_eps_bearer_context_request(modify_eps_bearer_context_request_msg *modify_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, MODIFY_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_IEI: + if ((decoded_result = + decode_eps_quality_of_service(&modify_eps_bearer_context_request->newepsqos, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_IEI: + if ((decoded_result = + decode_traffic_flow_template(&modify_eps_bearer_context_request->tft, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_IEI: + if ((decoded_result = + decode_quality_of_service(&modify_eps_bearer_context_request->newqos, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI: + if ((decoded_result = + decode_llc_service_access_point_identifier(&modify_eps_bearer_context_request->negotiatedllcsapi, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI: + if ((decoded_result = + decode_radio_priority(&modify_eps_bearer_context_request->radiopriority, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI: + if ((decoded_result = + decode_packet_flow_identifier(&modify_eps_bearer_context_request->packetflowidentifier, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI: + if ((decoded_result = + decode_apn_aggregate_maximum_bit_rate(&modify_eps_bearer_context_request->apnambr, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT; + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&modify_eps_bearer_context_request->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + modify_eps_bearer_context_request->presencemask |= MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_modify_eps_bearer_context_request(modify_eps_bearer_context_request_msg *modify_eps_bearer_context_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MODIFY_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH, len); + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_PRESENT) + { + if ((encode_result = + encode_eps_quality_of_service(&modify_eps_bearer_context_request->newepsqos, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_PRESENT) + { + if ((encode_result = + encode_traffic_flow_template(&modify_eps_bearer_context_request->tft, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_IEI, buffer + encoded, len - + encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_PRESENT) + { + if ((encode_result = + encode_quality_of_service(&modify_eps_bearer_context_request->newqos, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT) + { + if ((encode_result = + encode_llc_service_access_point_identifier(&modify_eps_bearer_context_request->negotiatedllcsapi, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT) + { + if ((encode_result = + encode_radio_priority(&modify_eps_bearer_context_request->radiopriority, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT) + { + if ((encode_result = + encode_packet_flow_identifier(&modify_eps_bearer_context_request->packetflowidentifier, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT) + { + if ((encode_result = + encode_apn_aggregate_maximum_bit_rate(&modify_eps_bearer_context_request->apnambr, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((modify_eps_bearer_context_request->presencemask & MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&modify_eps_bearer_context_request->protocolconfigurationoptions, + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h new file mode 100644 index 0000000000..a65c2c2aa0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h @@ -0,0 +1,88 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EpsQualityOfService.h" +#include "TrafficFlowTemplate.h" +#include "QualityOfService.h" +#include "LlcServiceAccessPointIdentifier.h" +#include "RadioPriority.h" +#include "PacketFlowIdentifier.h" +#include "ApnAggregateMaximumBitRate.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef MODIFY_EPS_BEARER_CONTEXT_REQUEST_H_ +#define MODIFY_EPS_BEARER_CONTEXT_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define MODIFY_EPS_BEARER_CONTEXT_REQUEST_MINIMUM_LENGTH (0) + +/* Maximum length macro. Formed by maximum length of each field */ +#define MODIFY_EPS_BEARER_CONTEXT_REQUEST_MAXIMUM_LENGTH ( \ + EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + TRAFFIC_FLOW_TEMPLATE_MAXIMUM_LENGTH + \ + QUALITY_OF_SERVICE_MAXIMUM_LENGTH + \ + LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MAXIMUM_LENGTH + \ + RADIO_PRIORITY_MAXIMUM_LENGTH + \ + PACKET_FLOW_IDENTIFIER_MAXIMUM_LENGTH + \ + APN_AGGREGATE_MAXIMUM_BIT_RATE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_PRESENT (1<<0) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_PRESENT (1<<1) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_PRESENT (1<<2) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_PRESENT (1<<3) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_PRESENT (1<<4) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_PRESENT (1<<5) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_PRESENT (1<<6) +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<7) + +typedef enum modify_eps_bearer_context_request_iei_tag { + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_EPS_QOS_IEI = 0x5B, /* 0x5B = 91 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_TFT_IEI = 0x36, /* 0x36 = 54 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEW_QOS_IEI = 0x30, /* 0x30 = 48 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_NEGOTIATED_LLC_SAPI_IEI = 0x32, /* 0x32 = 50 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_RADIO_PRIORITY_IEI = 0x80, /* 0x80 = 128 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PACKET_FLOW_IDENTIFIER_IEI = 0x34, /* 0x34 = 52 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_APNAMBR_IEI = 0x5E, /* 0x5E = 94 */ + MODIFY_EPS_BEARER_CONTEXT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} modify_eps_bearer_context_request_iei; + +/* + * Message name: Modify EPS bearer context request + * Description: This message is sent by the network to the UE to request modification of an active EPS bearer context. See table 8.3.18.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct modify_eps_bearer_context_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + /* Optional fields */ + uint32_t presencemask; + EpsQualityOfService newepsqos; + TrafficFlowTemplate tft; + QualityOfService newqos; + LlcServiceAccessPointIdentifier negotiatedllcsapi; + RadioPriority radiopriority; + PacketFlowIdentifier packetflowidentifier; + ApnAggregateMaximumBitRate apnambr; + ProtocolConfigurationOptions protocolconfigurationoptions; +} modify_eps_bearer_context_request_msg; + +int decode_modify_eps_bearer_context_request(modify_eps_bearer_context_request_msg *modifyepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +int encode_modify_eps_bearer_context_request(modify_eps_bearer_context_request_msg *modifyepsbearercontextrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(MODIFY_EPS_BEARER_CONTEXT_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.c new file mode 100644 index 0000000000..9e31650011 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.c @@ -0,0 +1,81 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnConnectivityReject.h" + +int decode_pdn_connectivity_reject(pdn_connectivity_reject_msg *pdn_connectivity_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, PDN_CONNECTIVITY_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&pdn_connectivity_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&pdn_connectivity_reject->protocolconfigurationoptions, + PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_connectivity_reject->presencemask |= PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_pdn_connectivity_reject(pdn_connectivity_reject_msg *pdn_connectivity_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_CONNECTIVITY_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = encode_esm_cause(&pdn_connectivity_reject->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((pdn_connectivity_reject->presencemask & PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&pdn_connectivity_reject->protocolconfigurationoptions, + PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h new file mode 100644 index 0000000000..b3a131f703 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef PDN_CONNECTIVITY_REJECT_H_ +#define PDN_CONNECTIVITY_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define PDN_CONNECTIVITY_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define PDN_CONNECTIVITY_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum pdn_connectivity_reject_iei_tag { + PDN_CONNECTIVITY_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} pdn_connectivity_reject_iei; + +/* + * Message name: PDN connectivity reject + * Description: This message is sent by the network to the UE to reject establishment of a PDN connection. See table 8.3.19.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct pdn_connectivity_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} pdn_connectivity_reject_msg; + +int decode_pdn_connectivity_reject(pdn_connectivity_reject_msg *pdnconnectivityreject, uint8_t *buffer, uint32_t len); + +int encode_pdn_connectivity_reject(pdn_connectivity_reject_msg *pdnconnectivityreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(PDN_CONNECTIVITY_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.c new file mode 100644 index 0000000000..9206f0d2cd --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.c @@ -0,0 +1,126 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnConnectivityRequest.h" + +int decode_pdn_connectivity_request(pdn_connectivity_request_msg *pdn_connectivity_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, PDN_CONNECTIVITY_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_request_type(&pdn_connectivity_request->pdntype, 0, *(buffer + decoded) >> 4, len - decoded)) < 0) + return decoded_result; + + if ((decoded_result = decode_u8_pdn_type(&pdn_connectivity_request->requesttype, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + decoded++; + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_IEI: + if ((decoded_result = + decode_esm_information_transfer_flag(&pdn_connectivity_request->esminformationtransferflag, + PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_connectivity_request->presencemask |= PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT; + break; + case PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_IEI: + if ((decoded_result = + decode_access_point_name(&pdn_connectivity_request->accesspointname, + PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_IEI, buffer + + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_connectivity_request->presencemask |= PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT; + break; + case PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&pdn_connectivity_request->protocolconfigurationoptions, + PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_connectivity_request->presencemask |= PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_pdn_connectivity_request(pdn_connectivity_request_msg *pdn_connectivity_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_CONNECTIVITY_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = ((encode_u8_pdn_type(&pdn_connectivity_request->pdntype) & 0x0f) << 4) | (encode_u8_request_type(&pdn_connectivity_request->requesttype) & 0x0f); + encoded++; + + if ((pdn_connectivity_request->presencemask & PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT) + == PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT) + { + if ((encode_result = + encode_esm_information_transfer_flag(&pdn_connectivity_request->esminformationtransferflag, + PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((pdn_connectivity_request->presencemask & PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) + == PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) + { + if ((encode_result = + encode_access_point_name(&pdn_connectivity_request->accesspointname, + PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_IEI, buffer + encoded, + len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + if ((pdn_connectivity_request->presencemask & PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&pdn_connectivity_request->protocolconfigurationoptions, + PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h new file mode 100644 index 0000000000..e6f53da4eb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "RequestType.h" +#include "PdnType.h" +#include "EsmInformationTransferFlag.h" +#include "AccessPointName.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef PDN_CONNECTIVITY_REQUEST_H_ +#define PDN_CONNECTIVITY_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define PDN_CONNECTIVITY_REQUEST_MINIMUM_LENGTH ( \ + PDN_TYPE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define PDN_CONNECTIVITY_REQUEST_MAXIMUM_LENGTH ( \ + PDN_TYPE_MAXIMUM_LENGTH + \ + ESM_INFORMATION_TRANSFER_FLAG_MAXIMUM_LENGTH + \ + ACCESS_POINT_NAME_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT (1<<0) +# define PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT (1<<1) +# define PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<2) + +typedef enum pdn_connectivity_request_iei_tag { + PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_IEI = 0xD0, /* 0xD0 = 208 */ + PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_IEI = 0x28, /* 0x28 = 40 */ + PDN_CONNECTIVITY_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} pdn_connectivity_request_iei; + +/* + * Message name: PDN connectivity request + * Description: This message is sent by the UE to the network to initiate establishment of a PDN connection. See table 8.3.20.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct pdn_connectivity_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + RequestType requesttype; + PdnType pdntype; + /* Optional fields */ + uint32_t presencemask; + EsmInformationTransferFlag esminformationtransferflag; + AccessPointName accesspointname; + ProtocolConfigurationOptions protocolconfigurationoptions; +} pdn_connectivity_request_msg; + +int decode_pdn_connectivity_request(pdn_connectivity_request_msg *pdnconnectivityrequest, uint8_t *buffer, uint32_t len); + +int encode_pdn_connectivity_request(pdn_connectivity_request_msg *pdnconnectivityrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(PDN_CONNECTIVITY_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.c new file mode 100644 index 0000000000..6f5372e6e8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.c @@ -0,0 +1,81 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnDisconnectReject.h" + +int decode_pdn_disconnect_reject(pdn_disconnect_reject_msg *pdn_disconnect_reject, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, PDN_DISCONNECT_REJECT_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_esm_cause(&pdn_disconnect_reject->esmcause, 0, buffer + decoded, len - decoded)) < 0) + return decoded_result; + else + decoded += decoded_result; + + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&pdn_disconnect_reject->protocolconfigurationoptions, + PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_disconnect_reject->presencemask |= PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_pdn_disconnect_reject(pdn_disconnect_reject_msg *pdn_disconnect_reject, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_DISCONNECT_REJECT_MINIMUM_LENGTH, len); + + if ((encode_result = encode_esm_cause(&pdn_disconnect_reject->esmcause, 0, + buffer + encoded, len - encoded)) < 0) //Return in case of error + return encode_result; + else + encoded += encode_result; + + if ((pdn_disconnect_reject->presencemask & PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&pdn_disconnect_reject->protocolconfigurationoptions, + PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h new file mode 100644 index 0000000000..5053c0554c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "EsmCause.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef PDN_DISCONNECT_REJECT_H_ +#define PDN_DISCONNECT_REJECT_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define PDN_DISCONNECT_REJECT_MINIMUM_LENGTH ( \ + ESM_CAUSE_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define PDN_DISCONNECT_REJECT_MAXIMUM_LENGTH ( \ + ESM_CAUSE_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum pdn_disconnect_reject_iei_tag { + PDN_DISCONNECT_REJECT_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} pdn_disconnect_reject_iei; + +/* + * Message name: PDN disconnect reject + * Description: This message is sent by the network to the UE to reject release of a PDN connection. See table 8.3.21.1. + * Significance: dual + * Direction: network to UE + */ + +typedef struct pdn_disconnect_reject_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + EsmCause esmcause; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} pdn_disconnect_reject_msg; + +int decode_pdn_disconnect_reject(pdn_disconnect_reject_msg *pdndisconnectreject, uint8_t *buffer, uint32_t len); + +int encode_pdn_disconnect_reject(pdn_disconnect_reject_msg *pdndisconnectreject, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(PDN_DISCONNECT_REJECT_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.c new file mode 100644 index 0000000000..0c690a4cd3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnDisconnectRequest.h" + +int decode_pdn_disconnect_request(pdn_disconnect_request_msg *pdn_disconnect_request, uint8_t *buffer, uint32_t len) +{ + uint32_t decoded = 0; + int decoded_result = 0; + + // Check if we got a NULL pointer and if buffer length is >= minimum length expected for the message. + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, PDN_DISCONNECT_REQUEST_MINIMUM_LENGTH, len); + + /* Decoding mandatory fields */ + if ((decoded_result = decode_u8_linked_eps_bearer_identity(&pdn_disconnect_request->linkedepsbeareridentity, 0, *(buffer + decoded) & 0x0f, len - decoded)) < 0) + return decoded_result; + + decoded++; + /* Decoding optional fields */ + while(len - decoded > 0) + { + uint8_t ieiDecoded = *(buffer + decoded); + /* Type | value iei are below 0x80 so just return the first 4 bits */ + if (ieiDecoded >= 0x80) + ieiDecoded = ieiDecoded & 0xf0; + switch(ieiDecoded) + { + case PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI: + if ((decoded_result = + decode_protocol_configuration_options(&pdn_disconnect_request->protocolconfigurationoptions, + PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, + buffer + decoded, len - decoded)) <= 0) + return decoded_result; + decoded += decoded_result; + /* Set corresponding mask to 1 in presencemask */ + pdn_disconnect_request->presencemask |= PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT; + break; + default: + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; + return TLV_DECODE_UNEXPECTED_IEI; + } + } + return decoded; +} + +int encode_pdn_disconnect_request(pdn_disconnect_request_msg *pdn_disconnect_request, uint8_t *buffer, uint32_t len) +{ + int encoded = 0; + int encode_result = 0; + + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_DISCONNECT_REQUEST_MINIMUM_LENGTH, len); + + *(buffer + encoded) = (encode_u8_linked_eps_bearer_identity(&pdn_disconnect_request->linkedepsbeareridentity) & 0x0f); + encoded++; + + if ((pdn_disconnect_request->presencemask & PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + == PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT) + { + if ((encode_result = + encode_protocol_configuration_options(&pdn_disconnect_request->protocolconfigurationoptions, + PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI, buffer + + encoded, len - encoded)) < 0) + // Return in case of error + return encode_result; + else + encoded += encode_result; + } + + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h new file mode 100644 index 0000000000..f16a8ffee7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "ProtocolDiscriminator.h" +#include "EpsBearerIdentity.h" +#include "ProcedureTransactionIdentity.h" +#include "MessageType.h" +#include "LinkedEpsBearerIdentity.h" +#include "ProtocolConfigurationOptions.h" + +#ifndef PDN_DISCONNECT_REQUEST_H_ +#define PDN_DISCONNECT_REQUEST_H_ + +/* Minimum length macro. Formed by minimum length of each mandatory field */ +#define PDN_DISCONNECT_REQUEST_MINIMUM_LENGTH ( \ + LINKED_EPS_BEARER_IDENTITY_MINIMUM_LENGTH ) + +/* Maximum length macro. Formed by maximum length of each field */ +#define PDN_DISCONNECT_REQUEST_MAXIMUM_LENGTH ( \ + LINKED_EPS_BEARER_IDENTITY_MAXIMUM_LENGTH + \ + PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH ) + +/* If an optional value is present and should be encoded, the corresponding + * Bit mask should be set to 1. + */ +# define PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_PRESENT (1<<0) + +typedef enum pdn_disconnect_request_iei_tag { + PDN_DISCONNECT_REQUEST_PROTOCOL_CONFIGURATION_OPTIONS_IEI = 0x27, /* 0x27 = 39 */ +} pdn_disconnect_request_iei; + +/* + * Message name: PDN disconnect request + * Description: This message is sent by the UE to the network to initiate release of a PDN connection. See table 8.3.22.1. + * Significance: dual + * Direction: UE to network + */ + +typedef struct pdn_disconnect_request_msg_tag { + /* Mandatory fields */ + ProtocolDiscriminator protocoldiscriminator:4; + EpsBearerIdentity epsbeareridentity:4; + ProcedureTransactionIdentity proceduretransactionidentity; + MessageType messagetype; + LinkedEpsBearerIdentity linkedepsbeareridentity; + /* Optional fields */ + uint32_t presencemask; + ProtocolConfigurationOptions protocolconfigurationoptions; +} pdn_disconnect_request_msg; + +int decode_pdn_disconnect_request(pdn_disconnect_request_msg *pdndisconnectrequest, uint8_t *buffer, uint32_t len); + +int encode_pdn_disconnect_request(pdn_disconnect_request_msg *pdndisconnectrequest, uint8_t *buffer, uint32_t len); + +#endif /* ! defined(PDN_DISCONNECT_REQUEST_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h new file mode 100644 index 0000000000..92823e25d0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h @@ -0,0 +1,104 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_cause.h + +Version 0.1 + +Date 2013/02/06 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines error cause code returned upon receiving unknown, + unforeseen, and erroneous EPS session management protocol + data. + +*****************************************************************************/ +#ifndef __ESM_CAUSE_H__ +#define __ESM_CAUSE_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Cause code used to notify that the EPS session management procedure + * has been successfully processed + */ +#define ESM_CAUSE_SUCCESS (-1) + +/* + * Causes related to nature of request (TS 24.301 - Annex B1) + */ +#define ESM_CAUSE_OPERATOR_DETERMINED_BARRING 8 +#define ESM_CAUSE_INSUFFICIENT_RESOURCES 26 +#define ESM_CAUSE_UNKNOWN_ACCESS_POINT_NAME 27 +#define ESM_CAUSE_UNKNOWN_PDN_TYPE 28 +#define ESM_CAUSE_USER_AUTHENTICATION_FAILED 29 +#define ESM_CAUSE_REQUEST_REJECTED_BY_GW 30 +#define ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED 31 +#define ESM_CAUSE_SERVICE_OPTION_NOT_SUPPORTED 32 +#define ESM_CAUSE_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED 33 +#define ESM_CAUSE_SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER 34 +#define ESM_CAUSE_PTI_ALREADY_IN_USE 35 +#define ESM_CAUSE_REGULAR_DEACTIVATION 36 +#define ESM_CAUSE_EPS_QOS_NOT_ACCEPTED 37 +#define ESM_CAUSE_NETWORK_FAILURE 38 +#define ESM_CAUSE_REACTIVATION_REQUESTED 39 +#define ESM_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION 41 +#define ESM_CAUSE_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION 42 +#define ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY 43 +#define ESM_CAUSE_SEMANTIC_ERRORS_IN_PACKET_FILTER 44 +#define ESM_CAUSE_SYNTACTICAL_ERROR_IN_PACKET_FILTER 45 +#define ESM_CAUSE_PTI_MISMATCH 47 +#define ESM_CAUSE_LAST_PDN_DISCONNECTION_NOT_ALLOWED 49 +#define ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED 50 +#define ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED 51 +#define ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED 52 +#define ESM_CAUSE_ESM_INFORMATION_NOT_RECEIVED 53 +#define ESM_CAUSE_PDN_CONNECTION_DOES_NOT_EXIST 54 +#define ESM_CAUSE_MULTIPLE_PDN_CONNECTIONS_NOT_ALLOWED 55 +#define ESM_CAUSE_COLLISION_WITH_NETWORK_INITIATED_REQUEST 56 +#define ESM_CAUSE_UNSUPPORTED_QCI_VALUE 59 +#define ESM_CAUSE_BEARER_HANDLING_NOT_SUPPORTED 60 +#define ESM_CAUSE_INVALID_PTI_VALUE 81 +#define ESM_CAUSE_APN_RESTRICTION_VALUE_NOT_COMPATIBLE 112 + +/* + * Protocol errors (e.g., unknown message) class (TS 24.301 - Annex B2) + */ +#define ESM_CAUSE_SEMANTICALLY_INCORRECT 95 +#define ESM_CAUSE_INVALID_MANDATORY_INFO 96 +#define ESM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED 97 +#define ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE 98 +#define ESM_CAUSE_IE_NOT_IMPLEMENTED 99 +#define ESM_CAUSE_CONDITIONAL_IE_ERROR 100 +#define ESM_CAUSE_MESSAGE_NOT_COMPATIBLE 101 +#define ESM_CAUSE_PROTOCOL_ERROR 111 + +/* + * TS 24.301 - Table 9.9.4.4.1 + * Any other value received by the UE shall be treated as cause code #34, + * "service option temporarily out of order". + * Any other value received by the network shall be treated as cause code #111 + * "protocol error, unspecified". + */ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __ESM_CAUSE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.c b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.c new file mode 100644 index 0000000000..5ceb8aa661 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.c @@ -0,0 +1,372 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_msg.c + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel, Sebastien Roux + +Description Defines EPS Session Management messages + +*****************************************************************************/ + +#include "esm_msg.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "TLVDecoder.h" +#include "TLVEncoder.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static int _esm_msg_decode_header(esm_msg_header_t *header, const uint8_t *buffer, uint32_t len); +static int _esm_msg_encode_header(const esm_msg_header_t *header, uint8_t *buffer, uint32_t len); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: esm_msg_decode() ** + ** ** + ** Description: Decode EPS Session Management messages ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the ESM ** + ** message ** + ** len: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message structure to be filled ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_msg_decode(ESM_msg *msg, uint8_t *buffer, uint32_t len) +{ + LOG_FUNC_IN; + + int header_result; + int decode_result; + + /* First decode the ESM message header */ + header_result = _esm_msg_decode_header(&msg->header, buffer, len); + if (header_result < 0) { + LOG_TRACE(ERROR, "ESM-MSG - Failed to decode ESM message header " + "(%d)", header_result); + LOG_FUNC_RETURN(header_result); + } + + buffer += header_result; + len -= header_result; + + switch(msg->header.message_type) + { + case PDN_DISCONNECT_REQUEST: + decode_result = decode_pdn_disconnect_request(&msg->pdn_disconnect_request, buffer, len); + break; + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + decode_result = decode_deactivate_eps_bearer_context_accept(&msg->deactivate_eps_bearer_context_accept, buffer, len); + break; + case BEARER_RESOURCE_ALLOCATION_REQUEST: + decode_result = decode_bearer_resource_allocation_request(&msg->bearer_resource_allocation_request, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + decode_result = decode_activate_default_eps_bearer_context_accept(&msg->activate_default_eps_bearer_context_accept, buffer, len); + break; + case PDN_CONNECTIVITY_REJECT: + decode_result = decode_pdn_connectivity_reject(&msg->pdn_connectivity_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_REJECT: + decode_result = decode_modify_eps_bearer_context_reject(&msg->modify_eps_bearer_context_reject, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT: + decode_result = decode_activate_dedicated_eps_bearer_context_reject(&msg->activate_dedicated_eps_bearer_context_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_ACCEPT: + decode_result = decode_modify_eps_bearer_context_accept(&msg->modify_eps_bearer_context_accept, buffer, len); + break; + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST: + decode_result = decode_deactivate_eps_bearer_context_request(&msg->deactivate_eps_bearer_context_request, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT: + decode_result = decode_activate_dedicated_eps_bearer_context_accept(&msg->activate_dedicated_eps_bearer_context_accept, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + decode_result = decode_activate_default_eps_bearer_context_reject(&msg->activate_default_eps_bearer_context_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST: + decode_result = decode_modify_eps_bearer_context_request(&msg->modify_eps_bearer_context_request, buffer, len); + break; + case PDN_DISCONNECT_REJECT: + decode_result = decode_pdn_disconnect_reject(&msg->pdn_disconnect_reject, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST: + decode_result = decode_activate_dedicated_eps_bearer_context_request(&msg->activate_dedicated_eps_bearer_context_request, buffer, len); + break; + case BEARER_RESOURCE_MODIFICATION_REJECT: + decode_result = decode_bearer_resource_modification_reject(&msg->bearer_resource_modification_reject, buffer, len); + break; + case BEARER_RESOURCE_ALLOCATION_REJECT: + decode_result = decode_bearer_resource_allocation_reject(&msg->bearer_resource_allocation_reject, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + decode_result = decode_activate_default_eps_bearer_context_request(&msg->activate_default_eps_bearer_context_request, buffer, len); + break; + case PDN_CONNECTIVITY_REQUEST: + decode_result = decode_pdn_connectivity_request(&msg->pdn_connectivity_request, buffer, len); + break; + case ESM_INFORMATION_RESPONSE: + decode_result = decode_esm_information_response(&msg->esm_information_response, buffer, len); + break; + case BEARER_RESOURCE_MODIFICATION_REQUEST: + decode_result = decode_bearer_resource_modification_request(&msg->bearer_resource_modification_request, buffer, len); + break; + case ESM_INFORMATION_REQUEST: + decode_result = decode_esm_information_request(&msg->esm_information_request, buffer, len); + break; + case ESM_STATUS: + decode_result = decode_esm_status(&msg->esm_status, buffer, len); + break; + default: + LOG_TRACE(ERROR, "ESM-MSG - Unexpected message type: 0x%x", + msg->header.message_type); + decode_result = TLV_DECODE_WRONG_MESSAGE_TYPE; + } + + if (decode_result < 0) { + LOG_TRACE(ERROR, "ESM-MSG - Failed to decode L3 ESM message 0x%x " + "(%d)", msg->header.message_type, decode_result); + LOG_FUNC_RETURN (decode_result); + } + LOG_FUNC_RETURN (header_result + decode_result); +} + +/**************************************************************************** + ** ** + ** Name: esm_msg_encode() ** + ** ** + ** Description: Encode EPS Session Management messages ** + ** ** + ** Inputs: msg: The ESM message structure to encode ** + ** length: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_msg_encode(ESM_msg *msg, uint8_t *buffer, uint32_t len) +{ + LOG_FUNC_IN; + + int header_result; + int encode_result; + + /* First encode the ESM message header */ + header_result = _esm_msg_encode_header(&msg->header, buffer, len); + if (header_result < 0) { + LOG_TRACE(ERROR, "ESM-MSG - Failed to encode ESM message header " + "(%d)", header_result); + LOG_FUNC_RETURN(header_result); + } + + buffer += header_result; + len -= header_result; + + switch(msg->header.message_type) + { + case PDN_DISCONNECT_REQUEST: + encode_result = encode_pdn_disconnect_request(&msg->pdn_disconnect_request, buffer, len); + break; + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + encode_result = encode_deactivate_eps_bearer_context_accept(&msg->deactivate_eps_bearer_context_accept, buffer, len); + break; + case BEARER_RESOURCE_ALLOCATION_REQUEST: + encode_result = encode_bearer_resource_allocation_request(&msg->bearer_resource_allocation_request, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + encode_result = encode_activate_default_eps_bearer_context_accept(&msg->activate_default_eps_bearer_context_accept, buffer, len); + break; + case PDN_CONNECTIVITY_REJECT: + encode_result = encode_pdn_connectivity_reject(&msg->pdn_connectivity_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_REJECT: + encode_result = encode_modify_eps_bearer_context_reject(&msg->modify_eps_bearer_context_reject, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT: + encode_result = encode_activate_dedicated_eps_bearer_context_reject(&msg->activate_dedicated_eps_bearer_context_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_ACCEPT: + encode_result = encode_modify_eps_bearer_context_accept(&msg->modify_eps_bearer_context_accept, buffer, len); + break; + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST: + encode_result = encode_deactivate_eps_bearer_context_request(&msg->deactivate_eps_bearer_context_request, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT: + encode_result = encode_activate_dedicated_eps_bearer_context_accept(&msg->activate_dedicated_eps_bearer_context_accept, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + encode_result = encode_activate_default_eps_bearer_context_reject(&msg->activate_default_eps_bearer_context_reject, buffer, len); + break; + case MODIFY_EPS_BEARER_CONTEXT_REQUEST: + encode_result = encode_modify_eps_bearer_context_request(&msg->modify_eps_bearer_context_request, buffer, len); + break; + case PDN_DISCONNECT_REJECT: + encode_result = encode_pdn_disconnect_reject(&msg->pdn_disconnect_reject, buffer, len); + break; + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST: + encode_result = encode_activate_dedicated_eps_bearer_context_request(&msg->activate_dedicated_eps_bearer_context_request, buffer, len); + break; + case BEARER_RESOURCE_MODIFICATION_REJECT: + encode_result = encode_bearer_resource_modification_reject(&msg->bearer_resource_modification_reject, buffer, len); + break; + case BEARER_RESOURCE_ALLOCATION_REJECT: + encode_result = encode_bearer_resource_allocation_reject(&msg->bearer_resource_allocation_reject, buffer, len); + break; + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + encode_result = encode_activate_default_eps_bearer_context_request(&msg->activate_default_eps_bearer_context_request, buffer, len); + break; + case PDN_CONNECTIVITY_REQUEST: + encode_result = encode_pdn_connectivity_request(&msg->pdn_connectivity_request, buffer, len); + break; + case ESM_INFORMATION_RESPONSE: + encode_result = encode_esm_information_response(&msg->esm_information_response, buffer, len); + break; + case BEARER_RESOURCE_MODIFICATION_REQUEST: + encode_result = encode_bearer_resource_modification_request(&msg->bearer_resource_modification_request, buffer, len); + break; + case ESM_INFORMATION_REQUEST: + encode_result = encode_esm_information_request(&msg->esm_information_request, buffer, len); + break; + case ESM_STATUS: + encode_result = encode_esm_status(&msg->esm_status, buffer, len); + break; + default: + LOG_TRACE(ERROR, "ESM-MSG - Unexpected message type: 0x%x", + msg->header.message_type); + encode_result = TLV_ENCODE_WRONG_MESSAGE_TYPE; + } + + if (encode_result < 0) { + LOG_TRACE(ERROR, "ESM-MSG - Failed to encode L3 ESM message 0x%x " + "(%d)", msg->header.message_type, encode_result); + } + LOG_FUNC_RETURN (header_result + encode_result); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _esm_msg_decode_header() ** + ** ** + ** Description: Decode header of EPS Mobility Management message. ** + ** The protocol discriminator and the security header type ** + ** have already been decoded. ** + ** ** + ** Inputs: buffer: Pointer to the buffer containing the ESM ** + ** message ** + ** len: Number of bytes that should be decoded ** + ** Others: None ** + ** ** + ** Outputs: header: The ESM message header to be filled ** + ** Return: The size of the header if data have been ** + ** successfully decoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_msg_decode_header(esm_msg_header_t *header, + const uint8_t *buffer, uint32_t len) +{ + int size = 0; + + /* Check the buffer length */ + if (len < sizeof(esm_msg_header_t)) { + return (TLV_DECODE_BUFFER_TOO_SHORT); + } + + /* Decode the EPS bearer identity and the protocol discriminator */ + DECODE_U8(buffer + size, *(uint8_t*)(header), size); + /* Decode the procedure transaction identity */ + DECODE_U8(buffer + size, header->procedure_transaction_identity, size); + /* Decode the message type */ + DECODE_U8(buffer + size, header->message_type, size); + + /* Check the protocol discriminator */ + if (header->protocol_discriminator != EPS_SESSION_MANAGEMENT_MESSAGE) + { + LOG_TRACE(ERROR, "ESM-MSG - Unexpected protocol discriminator: 0x%x", + header->protocol_discriminator); + return (TLV_DECODE_PROTOCOL_NOT_SUPPORTED); + } + + return (size); +} + +/**************************************************************************** + ** ** + ** Name: _esm_msg_encode_header() ** + ** ** + ** The protocol discriminator and the security header type ** + ** have already been encoded. ** + ** ** + ** Inputs: header: The ESM message header to encode ** + ** len: Maximal capacity of the output buffer ** + ** Others: None ** + ** ** + ** Outputs: buffer: Pointer to the encoded data buffer ** + ** Return: The number of bytes in the buffer if data ** + ** have been successfully encoded; ** + ** A negative error code otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _esm_msg_encode_header(const esm_msg_header_t *header, + uint8_t *buffer, uint32_t len) +{ + int size = 0; + + /* Check the buffer length */ + if (len < sizeof(esm_msg_header_t)) { + return (TLV_ENCODE_BUFFER_TOO_SHORT); + } + /* Check the protocol discriminator */ + else if (header->protocol_discriminator != EPS_SESSION_MANAGEMENT_MESSAGE) { + LOG_TRACE(ERROR, "ESM-MSG - Unexpected protocol discriminator: 0x%x", + header->protocol_discriminator); + return (TLV_ENCODE_PROTOCOL_NOT_SUPPORTED); + } + + /* Encode the EPS bearer identity and the protocol discriminator */ + ENCODE_U8(buffer + size, *(uint8_t*)(header), size); + /* Encode the procedure transaction identity */ + ENCODE_U8(buffer + size, header->procedure_transaction_identity, size); + /* Encode the message type */ + ENCODE_U8(buffer + size, header->message_type, size); + + return (size); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h new file mode 100644 index 0000000000..2ae252e884 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h @@ -0,0 +1,102 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_msg.h + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines EPS Session Management messages and functions used + to encode and decode + +*****************************************************************************/ +#ifndef __ESM_MSG_H__ +#define __ESM_MSG_H__ + +#include "esm_msgDef.h" + +#include "ActivateDedicatedEpsBearerContextRequest.h" +#include "ActivateDedicatedEpsBearerContextAccept.h" +#include "ActivateDedicatedEpsBearerContextReject.h" +#include "ActivateDefaultEpsBearerContextRequest.h" +#include "ActivateDefaultEpsBearerContextAccept.h" +#include "ActivateDefaultEpsBearerContextReject.h" +#include "ModifyEpsBearerContextRequest.h" +#include "ModifyEpsBearerContextAccept.h" +#include "ModifyEpsBearerContextReject.h" +#include "DeactivateEpsBearerContextRequest.h" +#include "DeactivateEpsBearerContextAccept.h" +#include "PdnDisconnectRequest.h" +#include "PdnDisconnectReject.h" +#include "PdnConnectivityRequest.h" +#include "PdnConnectivityReject.h" +#include "BearerResourceAllocationRequest.h" +#include "BearerResourceAllocationReject.h" +#include "BearerResourceModificationRequest.h" +#include "BearerResourceModificationReject.h" +#include "EsmInformationRequest.h" +#include "EsmInformationResponse.h" +#include "EsmStatus.h" + +#include <stdint.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Structure of ESM plain NAS message + * ---------------------------------- + */ +typedef union { + esm_msg_header_t header; + activate_default_eps_bearer_context_request_msg activate_default_eps_bearer_context_request; + activate_default_eps_bearer_context_accept_msg activate_default_eps_bearer_context_accept; + activate_default_eps_bearer_context_reject_msg activate_default_eps_bearer_context_reject; + activate_dedicated_eps_bearer_context_request_msg activate_dedicated_eps_bearer_context_request; + activate_dedicated_eps_bearer_context_accept_msg activate_dedicated_eps_bearer_context_accept; + activate_dedicated_eps_bearer_context_reject_msg activate_dedicated_eps_bearer_context_reject; + modify_eps_bearer_context_request_msg modify_eps_bearer_context_request; + modify_eps_bearer_context_accept_msg modify_eps_bearer_context_accept; + modify_eps_bearer_context_reject_msg modify_eps_bearer_context_reject; + deactivate_eps_bearer_context_request_msg deactivate_eps_bearer_context_request; + deactivate_eps_bearer_context_accept_msg deactivate_eps_bearer_context_accept; + pdn_connectivity_request_msg pdn_connectivity_request; + pdn_connectivity_reject_msg pdn_connectivity_reject; + pdn_disconnect_request_msg pdn_disconnect_request; + pdn_disconnect_reject_msg pdn_disconnect_reject; + bearer_resource_allocation_request_msg bearer_resource_allocation_request; + bearer_resource_allocation_reject_msg bearer_resource_allocation_reject; + bearer_resource_modification_request_msg bearer_resource_modification_request; + bearer_resource_modification_reject_msg bearer_resource_modification_reject; + esm_information_request_msg esm_information_request; + esm_information_response_msg esm_information_response; + esm_status_msg esm_status; +} ESM_msg; + + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int esm_msg_decode(ESM_msg *msg, uint8_t *buffer, uint32_t len); + +int esm_msg_encode(ESM_msg *msg, uint8_t *buffer, uint32_t len); + +#endif /* __ESM_MSG_H__ */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h new file mode 100644 index 0000000000..7a2d7a73be --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h @@ -0,0 +1,99 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + + +Version 0.1 + +Date 2012/09/27 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel, Sebastien Roux + +Description Defines identifiers of the EPS Session Management messages + +*****************************************************************************/ +#ifndef __ESM_MSGDEF_H__ +#define __ESM_MSGDEF_H__ + +#include <stdint.h> +#include <asm/byteorder.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Header length boundaries of EPS Session Management messages */ +#define ESM_HEADER_LENGTH sizeof(esm_msg_header_t) +#define ESM_HEADER_MINIMUM_LENGTH ESM_HEADER_LENGTH +#define ESM_HEADER_MAXIMUM_LENGTH ESM_HEADER_LENGTH + +/* Protocol discriminator identifier for EPS Session Management */ +#define EPS_SESSION_MANAGEMENT_MESSAGE 0x2 + +/* Message identifiers for EPS Session Management */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST 0b11000001 /* 193 = 0xc1 */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT 0b11000010 /* 194 = 0xc2 */ +# define ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT 0b11000011 /* 195 = 0xc3 */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST 0b11000101 /* 197 = 0xc5 */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT 0b11000110 /* 198 = 0xc6 */ +# define ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT 0b11000111 /* 199 = 0xc7 */ +# define MODIFY_EPS_BEARER_CONTEXT_REQUEST 0b11001001 /* 201 = 0xc9 */ +# define MODIFY_EPS_BEARER_CONTEXT_ACCEPT 0b11001010 /* 202 = 0xca */ +# define MODIFY_EPS_BEARER_CONTEXT_REJECT 0b11001011 /* 203 = 0xcb */ +# define DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST 0b11001101 /* 205 = 0xcd */ +# define DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT 0b11001110 /* 206 = 0xce */ +# define PDN_CONNECTIVITY_REQUEST 0b11010000 /* 208 = 0xd0 */ +# define PDN_CONNECTIVITY_REJECT 0b11010001 /* 209 = 0xd1 */ +# define PDN_DISCONNECT_REQUEST 0b11010010 /* 210 = 0xd2 */ +# define PDN_DISCONNECT_REJECT 0b11010011 /* 211 = 0xd3 */ +# define BEARER_RESOURCE_ALLOCATION_REQUEST 0b11010100 /* 212 = 0xd4 */ +# define BEARER_RESOURCE_ALLOCATION_REJECT 0b11010101 /* 213 = 0xd5 */ +# define BEARER_RESOURCE_MODIFICATION_REQUEST 0b11010110 /* 214 = 0xd6 */ +# define BEARER_RESOURCE_MODIFICATION_REJECT 0b11010111 /* 215 = 0xd7 */ +# define ESM_INFORMATION_REQUEST 0b11011001 /* 217 = 0xd9 */ +# define ESM_INFORMATION_RESPONSE 0b11011010 /* 218 = 0xda */ +# define ESM_STATUS 0b11101000 /* 232 = 0xe8 */ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Header of EPS Session Management plain NAS message + * -------------------------------------------------- + * 8 7 6 5 4 3 2 1 + * +-----------------------+------------------------+ + * | EPS bearer identity | Protocol discriminator | + * +-----------------------+------------------------+ + * | Procedure transaction identity | + * +-----------------------+------------------------+ + * | Message type | + * +-----------------------+------------------------+ + */ +typedef struct { +#ifdef __LITTLE_ENDIAN_BITFIELD + uint8_t protocol_discriminator:4; + uint8_t eps_bearer_identity:4; +#endif +#ifdef __BIG_ENDIAN_BITFIELD + uint8_t eps_bearer_identity:4; + uint8_t protocol_discriminator:4; +#endif + uint8_t procedure_transaction_identity; + uint8_t message_type; +}__attribute__((__packed__)) esm_msg_header_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __ESM_MSGDEF_H__ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/Makefile b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/Makefile new file mode 100644 index 0000000000..425e465f36 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/Makefile @@ -0,0 +1,42 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(ESMDIR) \ + -I$(IESDIR) -I$(ESMMSGDIR) + +TARGET = $(LIBESMSAP) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c Makefile $(PROJDIR)/Makerules $(PROJDIR)/Makefile.inc + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBPROCESS) + @$(RM) $(LIBPROCESS)/$@ + @$(CP) $@ $(LIBPROCESS) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.c b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.c new file mode 100644 index 0000000000..af3d072d65 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.c @@ -0,0 +1,1219 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_recv.c + +Version 0.1 + +Date 2013/02/06 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions executed at the ESM Service Access + Point upon receiving EPS Session Management messages + from the EPS Mobility Management sublayer. + +*****************************************************************************/ + +#include "esm_recv.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "esm_pt.h" +#include "esm_ebr.h" +#include "esm_proc.h" + +#include "esm_cause.h" + +#ifdef NAS_UE +#include <stdlib.h> // malloc, free +#include <string.h> // memset +#endif + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME upon receiving ESM messages + * -------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: esm_recv_status() ** + ** ** + ** Description: Processes ESM status message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +#ifdef NAS_UE +int esm_recv_status(int pti, int ebi, const esm_status_msg* msg) +#endif +#ifdef NAS_MME +int esm_recv_status(unsigned int ueid, int pti, int ebi, + const esm_status_msg* msg) +#endif +{ + LOG_FUNC_IN; + + int esm_cause; + int rc; + + LOG_TRACE(INFO, "ESM-SAP - Received ESM status message (pti=%d, ebi=%d)", + pti, ebi); + + /* + * Message processing + */ + /* Get the ESM cause */ + esm_cause = msg->esmcause; + + /* Execute the ESM status procedure */ +#ifdef NAS_UE + rc = esm_proc_status_ind(pti, ebi, &esm_cause); +#endif +#ifdef NAS_MME + rc = esm_proc_status_ind(ueid, pti, ebi, &esm_cause); +#endif + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE upon receiving ESM message from the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_recv_pdn_connectivity_reject() ** + ** ** + ** Description: Processes PDN Connectivity Reject message ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_pdn_connectivity_reject(int pti, int ebi, + const pdn_connectivity_reject_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause; + + LOG_TRACE(INFO, "ESM-SAP - Received PDN Connectivity Reject message " + "(pti=%d, ebi=%d, cause=%d)", pti, ebi, msg->esmcause); + + /* + * Procedure transaction identity checking + */ + if ( (pti == ESM_PT_UNASSIGNED) || esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case a + * Reserved or unassigned PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + else if ( esm_pt_is_not_in_use(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case a + * Assigned value that does not match any PTI in use + */ + LOG_TRACE(WARNING, "ESM-SAP - PTI mismatch (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_PTI_MISMATCH); + } + /* + * EPS bearer identity checking + */ + else if ( (ebi != ESM_EBI_UNASSIGNED) || esm_ebr_is_reserved(ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case a + * Assigned or reserved EPS bearer identity value */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + /* Get the ESM cause */ + esm_cause = msg->esmcause; + + /* Execute the PDN connectivity procedure not accepted by the network */ + int rc = esm_proc_pdn_connectivity_reject(pti, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_pdn_disconnect_reject() ** + ** ** + ** Description: Processes PDN Disconnect Reject message ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_pdn_disconnect_reject(int pti, int ebi, + const pdn_disconnect_reject_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause; + + LOG_TRACE(INFO, "ESM-SAP - Received PDN Disconnect Reject message " + "(pti=%d, ebi=%d, cause=%d)", pti, ebi, msg->esmcause); + + /* + * Procedure transaction identity checking + */ + if ( (pti == ESM_PT_UNASSIGNED) || esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case b + * Reserved or unassigned PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + else if ( esm_pt_is_not_in_use(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case b + * Assigned value that does not match any PTI in use + */ + LOG_TRACE(WARNING, "ESM-SAP - PTI mismatch (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_PTI_MISMATCH); + } + /* + * EPS bearer identity checking + */ + else if ( (ebi != ESM_EBI_UNASSIGNED) || esm_ebr_is_reserved(ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case b + * Assigned or reserved EPS bearer identity value */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + /* Get the ESM cause */ + esm_cause = msg->esmcause; + + /* Execute the PDN disconnect procedure not accepted by the network */ + int rc = esm_proc_pdn_disconnect_reject(pti, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_default_eps_bearer_context_request() ** + ** ** + ** Description: Processes Activate Default EPS Bearer Context Request ** + ** message ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_default_eps_bearer_context_request(int pti, int ebi, + const activate_default_eps_bearer_context_request_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Default EPS Bearer Context " + "Request message (pti=%d, ebi=%d)", pti, ebi); + + /* + * Procedure transaction identity checking + */ + if ( (pti == ESM_PT_UNASSIGNED) || esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case h + * Reserved or unassigned PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + else if ( esm_pt_is_not_in_use(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case g + * Assigned value that does not match any PTI in use + */ + LOG_TRACE(WARNING, "ESM-SAP - PTI mismatch (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_PTI_MISMATCH); + } + /* + * EPS bearer identity checking + */ + else if ( (ebi == ESM_EBI_UNASSIGNED) || esm_ebr_is_reserved(ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case g + * Reserved or unassigned EPS bearer identity value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + esm_proc_qos_t qos = {-1, -1, -1, -1, -1}; + /* Get the maximum bit rate for uplink and downlink */ + if (msg->epsqos.bitRatesExtPresent) { + qos.mbrUL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.maxBitRateForUL); + qos.mbrDL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.maxBitRateForDL); + } + else if (msg->epsqos.bitRatesPresent) { + qos.mbrUL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.maxBitRateForUL); + qos.mbrDL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.maxBitRateForDL); + } + /* Get the guaranteed bit rate for uplink and downlink */ + if (msg->epsqos.bitRatesExtPresent) { + qos.gbrUL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.guarBitRateForUL); + qos.gbrDL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.guarBitRateForDL); + } + else if (msg->epsqos.bitRatesPresent) { + qos.gbrUL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.guarBitRateForUL); + qos.gbrDL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.guarBitRateForDL); + } + /* Get the QoS Class Identifier */ + qos.qci = msg->epsqos.qci; + /* Get the value of the PDN type indicator */ + int pdn_type = -1; + if (msg->pdnaddress.pdntypevalue == PDN_VALUE_TYPE_IPV4) { + pdn_type = ESM_PDN_TYPE_IPV4; + } else if (msg->pdnaddress.pdntypevalue == PDN_VALUE_TYPE_IPV6) { + pdn_type = ESM_PDN_TYPE_IPV6; + } else if (msg->pdnaddress.pdntypevalue == PDN_VALUE_TYPE_IPV4V6) { + pdn_type = ESM_PDN_TYPE_IPV4V6; + } + /* Get the ESM cause */ + if (msg->presencemask & ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT) { + /* The network allocated a PDN address of a PDN type which is different + * from the requested PDN type */ + esm_cause = msg->esmcause; + } + + /* Execute the PDN connectivity procedure accepted by the network */ + int pid = esm_proc_pdn_connectivity_accept(pti, pdn_type, + &msg->pdnaddress.pdnaddressinformation, + &msg->accesspointname.accesspointnamevalue, + &esm_cause); + + if (pid != RETURNerror) { + /* Create local default EPS bearer context */ + int rc = esm_proc_default_eps_bearer_context_request(pid, ebi, &qos, + &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_dedicated_eps_bearer_context_request() ** + ** ** + ** Description: Processes Activate Dedicated EPS Bearer Context Request ** + ** message ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_dedicated_eps_bearer_context_request(int pti, int ebi, + const activate_dedicated_eps_bearer_context_request_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Dedicated EPS Bearer " + "Context Request message (pti=%d, ebi=%d)", pti, ebi); + + /* + * Procedure transaction identity checking + */ + if ( esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case j + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + else if ( (pti != ESM_PT_UNASSIGNED) && esm_pt_is_not_in_use(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case i + * Assigned value that does not match any PTI in use + */ + LOG_TRACE(WARNING, "ESM-SAP - PTI mismatch (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_PTI_MISMATCH); + } + /* + * EPS bearer identity checking + */ + else if ( (ebi == ESM_EBI_UNASSIGNED) || esm_ebr_is_reserved(ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case h + * Reserved or unassigned EPS bearer identity value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * TFT checking + */ + else if (msg->tft.tftoperationcode != TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE) { + /* 3GPP TS 24.301, section 6.4.2.4, case a1 + * Semantic errors in TFT operations + */ + LOG_FUNC_RETURN (ESM_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION); + } + else if (msg->tft.numberofpacketfilters == 0) { + /* 3GPP TS 24.301, section 6.4.2.4, case b1 + * Syntactical errors in TFT operations + */ + LOG_FUNC_RETURN (ESM_CAUSE_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION); + } + + /* + * Message processing + */ + /* Processing of the EPS bearer level QoS parameters */ + esm_proc_qos_t qos = {-1, -1, -1, -1, -1}; + /* Get the maximum bit rate for uplink and downlink */ + if (msg->epsqos.bitRatesExtPresent) { + qos.mbrUL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.maxBitRateForUL); + qos.mbrDL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.maxBitRateForDL); + } + else if (msg->epsqos.bitRatesPresent) { + qos.mbrUL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.maxBitRateForUL); + qos.mbrDL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.maxBitRateForDL); + } + /* Get the guaranteed bit rate for uplink and downlink */ + if (msg->epsqos.bitRatesExtPresent) { + qos.gbrUL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.guarBitRateForUL); + qos.gbrDL = + eps_qos_bit_rate_ext_value(msg->epsqos.bitRatesExt.guarBitRateForDL); + } + else if (msg->epsqos.bitRatesPresent) { + qos.gbrUL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.guarBitRateForUL); + qos.gbrDL = + eps_qos_bit_rate_value(msg->epsqos.bitRates.guarBitRateForDL); + } + /* Get the QoS Class Identifier */ + qos.qci = msg->epsqos.qci; + + /* Processing of the traffic flow template parameters */ + esm_proc_tft_t tft = {0, {NULL}}; + /* Get the list of packet filters */ + const PacketFilters* pkfs = &(msg->tft.packetfilterlist.createtft); + for (int i = 0; i < msg->tft.numberofpacketfilters; i++) + { + /* Create new temporary packet filter */ + tft.pkf[i] = (network_pkf_t*)malloc(sizeof(network_pkf_t)); + if (tft.pkf[i] != NULL) + { + /* Initialize the temporary packet filter */ + memset(tft.pkf[i], 0, sizeof(network_pkf_t)); + /* Increment the number of packet filters contained in the TFT */ + tft.n_pkfs += 1; + /* Packet filter identifier */ + tft.pkf[i]->id = pkfs[i]->identifier; + /* Packet filter direction */ + tft.pkf[i]->dir = pkfs[i]->direction; + /* Evaluation precedence */ + tft.pkf[i]->precedence = pkfs[i]->eval_precedence; + + /* Get the packet filter components */ + const PacketFilter* pkf = &(pkfs[i]->packetfilter); + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG) { + /* IPv4 remote address component */ + for (int j = 0; (j < TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE) && (j < NET_PACKET_FILTER_IPV4_ADDR_SIZE); j++) + { + tft.pkf[i]->data.ipv4.addr[j] = pkf->ipv4remoteaddr[j].addr; + tft.pkf[i]->data.ipv4.mask[j] = pkf->ipv4remoteaddr[j].mask; + } + } + else if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR_FLAG) { + /* IPv6 remote address component */ + for (int j = 0; (j < TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE) && (j < NET_PACKET_FILTER_IPV6_ADDR_SIZE); j++) + { + tft.pkf[i]->data.ipv6.addr[j] = pkf->ipv6remoteaddr[j].addr; + tft.pkf[i]->data.ipv6.mask[j] = pkf->ipv6remoteaddr[j].mask; + } + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG) { + /* Protocol identifier/Next header component */ + tft.pkf[i]->data.ipv4.protocol = + pkf->protocolidentifier_nextheader; + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG) { + /* Single local port component */ + tft.pkf[i]->lport = pkf->singlelocalport; + } + else if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE_FLAG) { + /* Local port range component */ + /* TODO: Add port range type to network_pkf_t in networkDef.h */ + tft.pkf[i]->lport = pkf->localportrange.lowlimit; + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG) { + /* Single remote port component */ + tft.pkf[i]->rport = pkf->singleremoteport; + } + else if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE_FLAG) + { + /* Remote port range component */ + /* TODO: Add port range type to network_pkf_t in networkDef.h */ + tft.pkf[i]->rport = pkf->remoteportrange.lowlimit; + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX) { + /* Security parameter index component */ + tft.pkf[i]->data.ipv6.ipsec = pkf->securityparameterindex; + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS) { + /* Type of service/Traffic class component */ + tft.pkf[i]->data.ipv4.tos = + pkf->typdeofservice_trafficclass.value; + } + if (pkf->flags & TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL) { + /* Flow label component */ + tft.pkf[i]->data.ipv6.fl = pkf->flowlabel; + } + } + } + + /* Execute the dedicated EPS bearer context activation procedure */ + int rc = esm_proc_dedicated_eps_bearer_context_request(ebi, + msg->linkedepsbeareridentity, + &qos, &tft, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + /* Release temporary traffic flow template data */ + for (int i = 0; i < tft.n_pkfs; i++) { + free(tft.pkf[i]); + } + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_deactivate_eps_bearer_context_request() ** + ** ** + ** Description: Processes Deactivate EPS Bearer Context Request message ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_deactivate_eps_bearer_context_request(int pti, int ebi, + const deactivate_eps_bearer_context_request_msg* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + int esm_cause; + + LOG_TRACE(INFO, "ESM-SAP - Received Deactivate EPS Bearer Context " + "Request message (pti=%d, ebi=%d)", pti, ebi); + + /* + * Procedure transaction identity checking + */ + if ( esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case m + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + else if ( esm_pt_is_not_in_use(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case m + * Assigned value does not match any PTI in use + */ + LOG_TRACE(WARNING, "ESM-SAP - PTI mismatch (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_PTI_MISMATCH); + } + /* + * EPS bearer identity checking + */ + else if ( (ebi == ESM_EBI_UNASSIGNED) || esm_ebr_is_reserved(ebi) || + esm_ebr_is_not_in_use(ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case j + * Reserved or unassigned EPS bearer identity value or, + * assigned value that does not match an existing EPS bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + /* Respond with a DEACTIVATE EPS BEARER CONTEXT ACCEPT message with + * the EPS bearer identity set to the received EPS bearer identity */ + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + /* Get the ESM cause */ + esm_cause = msg->esmcause; + + /* Execute the PDN disconnect procedure accepted by the network */ + if (pti != ESM_PT_UNASSIGNED) { + rc = esm_proc_pdn_disconnect_accept(pti, &esm_cause); + } + + if (rc != RETURNerror) { + /* Execute the EPS bearer context deactivation procedure */ + rc = esm_proc_eps_bearer_context_deactivate_request(ebi, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME upon receiving ESM message from the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_recv_pdn_connectivity_request() ** + ** ** + ** Description: Processes PDN connectivity request message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: new_ebi: New assigned EPS bearer identity ** + ** data: PDN connection and EPS bearer context data ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_pdn_connectivity_request(unsigned int ueid, int pti, int ebi, + const pdn_connectivity_request_msg* msg, + unsigned int* new_ebi, void* data) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received PDN Connectivity Request message " + "(ueid=%d, pti=%d, ebi=%d)", ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if ( (pti == ESM_PT_UNASSIGNED) || esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case a + * Reserved or unassigned PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( ebi != ESM_EBI_UNASSIGNED ) { + /* 3GPP TS 24.301, section 7.3.2, case a + * Reserved or assigned EPS bearer identity value */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + /* Get PDN connection and EPS bearer context data structure to setup */ + esm_proc_data_t* esm_data = (esm_proc_data_t*)(data); + if (data == NULL) { + LOG_TRACE(ERROR, "ESM-SAP - Invalid ESM data structure"); + LOG_FUNC_RETURN (ESM_CAUSE_PROTOCOL_ERROR); + } + /* Get the PDN connectivity request type */ + int request_type = -1; + if (msg->requesttype == REQUEST_TYPE_INITIAL_REQUEST) { + request_type = ESM_PDN_REQUEST_INITIAL; + } else if (msg->requesttype == REQUEST_TYPE_HANDOVER) { + request_type = ESM_PDN_REQUEST_HANDOVER; + } else if (msg->requesttype == REQUEST_TYPE_EMERGENCY) { + request_type = ESM_PDN_REQUEST_EMERGENCY; + } else { + /* Unkown PDN request type */ + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_MANDATORY_INFO); + } + /* Get the value of the PDN type indicator */ + if (msg->pdntype == PDN_TYPE_IPV4) { + esm_data->pdn_type = ESM_PDN_TYPE_IPV4; + } else if (msg->pdntype == PDN_TYPE_IPV6) { + esm_data->pdn_type = ESM_PDN_TYPE_IPV6; + } else if (msg->pdntype == PDN_TYPE_IPV4V6) { + esm_data->pdn_type = ESM_PDN_TYPE_IPV4V6; + } else { + /* Unkown PDN type */ + LOG_FUNC_RETURN (ESM_CAUSE_UNKNOWN_PDN_TYPE); + } + + /* Get the Access Point Name, if provided */ + if (msg->presencemask & PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) + { + esm_data->apn = msg->accesspointname.accesspointnamevalue; + } + + /* Get the ESM information transfer flag */ + if (msg->presencemask & PDN_CONNECTIVITY_REQUEST_ESM_INFORMATION_TRANSFER_FLAG_PRESENT) + { + /* 3GPP TS 24.301, sections 6.5.1.2, 6.5.1.3 + * ESM information, i.e. protocol configuration options, APN, or both, + * has to be sent after the NAS signalling security has been activated + * between the UE and the MME. + * + * The MME then at a later stage in the PDN connectivity procedure + * initiates the ESM information request procedure in which the UE + * can provide the MME with protocol configuration options or APN + * or both. + * The MME waits for completion of the ESM information request + * procedure before proceeding with the PDN connectivity procedure. + */ + //TODO: rc = esm_proc_information_request(); + } + + /* Execute the PDN connectivity procedure requested by the UE */ + int pid = esm_proc_pdn_connectivity_request(ueid, pti, request_type, + &esm_data->apn, + esm_data->pdn_type, + &esm_data->pdn_addr, + &esm_data->qos, + &esm_cause); + if (pid != RETURNerror) { + /* Create local default EPS bearer context */ + int rc = esm_proc_default_eps_bearer_context(ueid, pid, new_ebi, + &esm_data->qos, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_pdn_disconnect_request() ** + ** ** + ** Description: Processes PDN disconnect request message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: linked_ebi: Linked EPS bearer identity of the default ** + ** bearer associated with the PDN to discon- ** + ** nect from ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_pdn_disconnect_request(unsigned int ueid, int pti, int ebi, + const pdn_disconnect_request_msg* msg, + unsigned int* linked_ebi) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received PDN Disconnect Request message " + "(ueid=%d, pti=%d, ebi=%d)", ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if ( (pti == ESM_PT_UNASSIGNED) || esm_pt_is_reserved(pti) ) { + /* 3GPP TS 24.301, section 7.3.1, case b + * Reserved or unassigned PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( ebi != ESM_EBI_UNASSIGNED ) { + /* 3GPP TS 24.301, section 7.3.2, case b + * Reserved or assigned EPS bearer identity value */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + + /* + * Message processing + */ + /* Execute the PDN disconnect procedure requested by the UE */ + int pid = esm_proc_pdn_disconnect_request(ueid, pti, &esm_cause); + if (pid != RETURNerror) { + /* Get the identity of the default EPS bearer context assigned to + * the PDN connection to disconnect from */ + *linked_ebi = msg->linkedepsbeareridentity; + /* Release the associated default EPS bearer context */ + int bid = 0; + int rc = esm_proc_eps_bearer_context_deactivate(ueid, FALSE, + *linked_ebi, + &pid, &bid, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_default_eps_bearer_context_accept() ** + ** ** + ** Description: Processes Activate Default EPS Bearer Context Accept ** + ** message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_default_eps_bearer_context_accept(unsigned int ueid, + int pti, int ebi, + const activate_default_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Default EPS Bearer Context " + "Accept message (ueid=%d, pti=%d, ebi=%d)", ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if (esm_pt_is_reserved(pti)) { + /* 3GPP TS 24.301, section 7.3.1, case f + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( esm_ebr_is_reserved(ebi) || esm_ebr_is_not_in_use(ueid, ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case f + * Reserved or assigned value that does not match an existing EPS + * bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * Message processing + */ + /* Execute the default EPS bearer context activation procedure accepted + * by the UE */ + int rc = esm_proc_default_eps_bearer_context_accept(ueid, ebi, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_default_eps_bearer_context_reject() ** + ** ** + ** Description: Processes Activate Default EPS Bearer Context Reject ** + ** message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fail ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_default_eps_bearer_context_reject(unsigned int ueid, + int pti, int ebi, + const activate_default_eps_bearer_context_reject_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Default EPS Bearer Context " + "Reject message (ueid=%d, pti=%d, ebi=%d)", ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if (esm_pt_is_reserved(pti)) { + /* 3GPP TS 24.301, section 7.3.1, case f + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( esm_ebr_is_reserved(ebi) || esm_ebr_is_not_in_use(ueid, ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case f + * Reserved or assigned value that does not match an existing EPS + * bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * Message processing + */ + /* Execute the default EPS bearer context activation procedure not accepted + * by the UE */ + int rc = esm_proc_default_eps_bearer_context_reject(ueid, ebi, &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_dedicated_eps_bearer_context_accept() ** + ** ** + ** Description: Processes Activate Dedicated EPS Bearer Context Accept ** + ** message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_dedicated_eps_bearer_context_accept(unsigned int ueid, + int pti, int ebi, + const activate_dedicated_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Dedicated EPS Bearer " + "Context Accept message (ueid=%d, pti=%d, ebi=%d)", + ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if (esm_pt_is_reserved(pti)) { + /* 3GPP TS 24.301, section 7.3.1, case f + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( esm_ebr_is_reserved(ebi) || esm_ebr_is_not_in_use(ueid, ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case f + * Reserved or assigned value that does not match an existing EPS + * bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * Message processing + */ + /* Execute the dedicated EPS bearer context activation procedure accepted + * by the UE */ + int rc = esm_proc_dedicated_eps_bearer_context_accept(ueid, ebi, + &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_activate_dedicated_eps_bearer_context_reject() ** + ** ** + ** Description: Processes Activate Dedicated EPS Bearer Context Reject ** + ** message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fail ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_activate_dedicated_eps_bearer_context_reject(unsigned int ueid, + int pti, int ebi, + const activate_dedicated_eps_bearer_context_reject_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Activate Dedicated EPS Bearer " + "Context Reject message (ueid=%d, pti=%d, ebi=%d)", + ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if (esm_pt_is_reserved(pti)) { + /* 3GPP TS 24.301, section 7.3.1, case f + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( esm_ebr_is_reserved(ebi) || esm_ebr_is_not_in_use(ueid, ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case f + * Reserved or assigned value that does not match an existing EPS + * bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * Message processing + */ + /* Execute the dedicated EPS bearer context activation procedure not + * accepted by the UE */ + int rc = esm_proc_dedicated_eps_bearer_context_reject(ueid, ebi, + &esm_cause); + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +/**************************************************************************** + ** ** + ** Name: esm_recv_deactivate_eps_bearer_context_accept() ** + ** ** + ** Description: Processes Deactivate EPS Bearer Context Accept message ** + ** ** + ** Inputs: ueid: UE local identifier ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** msg: The received ESM message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: ESM cause code whenever the processing of ** + ** the ESM message fails ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_recv_deactivate_eps_bearer_context_accept(unsigned int ueid, + int pti, int ebi, + const deactivate_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + int esm_cause = ESM_CAUSE_SUCCESS; + + LOG_TRACE(INFO, "ESM-SAP - Received Deactivate EPS Bearer Context " + "Accept message (ueid=%d, pti=%d, ebi=%d)", ueid, pti, ebi); + + /* + * Procedure transaction identity checking + */ + if (esm_pt_is_reserved(pti)) { + /* 3GPP TS 24.301, section 7.3.1, case f + * Reserved PTI value + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid PTI value (pti=%d)", pti); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_PTI_VALUE); + } + /* + * EPS bearer identity checking + */ + else if ( esm_ebr_is_reserved(ebi) || esm_ebr_is_not_in_use(ueid, ebi) ) { + /* 3GPP TS 24.301, section 7.3.2, case f + * Reserved or assigned value that does not match an existing EPS + * bearer context + */ + LOG_TRACE(WARNING, "ESM-SAP - Invalid EPS bearer identity (ebi=%d)", + ebi); + LOG_FUNC_RETURN (ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY); + } + /* + * Message processing + */ + /* Execute the default EPS bearer context activation procedure accepted + * by the UE */ + int pid = esm_proc_eps_bearer_context_deactivate_accept(ueid, ebi, + &esm_cause); + if (pid != RETURNerror) { + /* Release all the resources reserved for the PDN */ + int rc = esm_proc_pdn_disconnect_accept(ueid, pid, &esm_cause); + + if (rc != RETURNerror) { + esm_cause = ESM_CAUSE_SUCCESS; + } + } + + /* Return the ESM cause value */ + LOG_FUNC_RETURN (esm_cause); +} + +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.h b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.h new file mode 100644 index 0000000000..b30d45bd21 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_recv.h @@ -0,0 +1,140 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_recv.h + +Version 0.1 + +Date 2013/02/06 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions executed at the ESM Service Access + Point upon receiving EPS Session Management messages + from the EPS Mobility Management sublayer. + +*****************************************************************************/ +#ifndef __ESM_RECV_H__ +#define __ESM_RECV_H__ + +#include "EsmStatus.h" + +#ifdef NAS_UE +#include "PdnConnectivityReject.h" +#include "PdnDisconnectReject.h" +#include "BearerResourceAllocationReject.h" +#include "BearerResourceModificationReject.h" + +#include "ActivateDefaultEpsBearerContextRequest.h" +#include "ActivateDedicatedEpsBearerContextRequest.h" +#include "ModifyEpsBearerContextRequest.h" +#include "DeactivateEpsBearerContextRequest.h" + +#include "EsmInformationRequest.h" +#endif + +#ifdef NAS_MME +#include "PdnConnectivityRequest.h" +#include "PdnDisconnectRequest.h" +#include "BearerResourceAllocationRequest.h" +#include "BearerResourceModificationRequest.h" + +#include "ActivateDefaultEpsBearerContextAccept.h" +#include "ActivateDefaultEpsBearerContextReject.h" +#include "ActivateDedicatedEpsBearerContextAccept.h" +#include "ActivateDedicatedEpsBearerContextReject.h" +#include "ModifyEpsBearerContextAccept.h" +#include "ModifyEpsBearerContextReject.h" +#include "DeactivateEpsBearerContextAccept.h" + +#include "EsmInformationResponse.h" +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME upon receiving ESM messages + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +int esm_recv_status(int pti, int ebi, const esm_status_msg* msg); +#endif +#ifdef NAS_MME +int esm_recv_status(unsigned int ueid, int pti, int ebi, const esm_status_msg* msg); +#endif + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE upon receiving ESM message from the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Transaction related messages + * ---------------------------- + */ +int esm_recv_pdn_connectivity_reject(int pti, int ebi, const pdn_connectivity_reject_msg* msg); + +int esm_recv_pdn_disconnect_reject(int pti, int ebi, const pdn_disconnect_reject_msg* msg); + +/* + * Messages related to EPS bearer contexts + * --------------------------------------- + */ +int esm_recv_activate_default_eps_bearer_context_request(int pti, int ebi, const activate_default_eps_bearer_context_request_msg* msg); + +int esm_recv_activate_dedicated_eps_bearer_context_request(int pti, int ebi, const activate_dedicated_eps_bearer_context_request_msg* msg); + +int esm_recv_deactivate_eps_bearer_context_request(int pti, int ebi, const deactivate_eps_bearer_context_request_msg* msg); +#endif + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME upon receiving ESM message from the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Transaction related messages + * ---------------------------- + */ +int esm_recv_pdn_connectivity_request(unsigned int ueid, int pti, int ebi, const pdn_connectivity_request_msg* msg, unsigned int* new_ebi, void* data); + +int esm_recv_pdn_disconnect_request(unsigned int ueid, int pti, int ebi, const pdn_disconnect_request_msg* msg, unsigned int* linked_ebi); + +/* + * Messages related to EPS bearer contexts + * --------------------------------------- + */ +int esm_recv_activate_default_eps_bearer_context_accept(unsigned int ueid, int pti, int ebi, const activate_default_eps_bearer_context_accept_msg* msg); + +int esm_recv_activate_default_eps_bearer_context_reject(unsigned int ueid, int pti, int ebi, const activate_default_eps_bearer_context_reject_msg* msg); + +int esm_recv_activate_dedicated_eps_bearer_context_accept(unsigned int ueid, int pti, int ebi, const activate_dedicated_eps_bearer_context_accept_msg* msg); + +int esm_recv_activate_dedicated_eps_bearer_context_reject(unsigned int ueid, int pti, int ebi, const activate_dedicated_eps_bearer_context_reject_msg* msg); + +int esm_recv_deactivate_eps_bearer_context_accept(unsigned int ueid, int pti, int ebi, const deactivate_eps_bearer_context_accept_msg* msg); +#endif + +#endif /* __ESM_RECV_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.c b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.c new file mode 100644 index 0000000000..76846a4e3d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.c @@ -0,0 +1,1138 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_sap.c + +Version 0.1 + +Date 2012/11/22 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the ESM Service Access Points at which the EPS + Session Management sublayer provides procedures for the + EPS bearer context handling and resources allocation. + +*****************************************************************************/ + +#include "esm_sap.h" +#include "esm_recv.h" +#include "esm_send.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "OctetString.h" +#include "TLVDecoder.h" +#include "esm_msgDef.h" +#include "esm_msg.h" + +#include "esm_cause.h" +#include "esm_proc.h" + +#include <string.h> // memset, strlen +#include <assert.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +static int _esm_sap_recv(int msg_type, int is_standalone, const OctetString* req, OctetString* rsp, esm_sap_error_t* err); +static int _esm_sap_send(int msg_type, int is_standalone, int pti, int ebi, const esm_sap_data_t* data, OctetString* rsp); +#endif + +#ifdef NAS_MME +static int _esm_sap_recv(int msg_type, int is_standalone, unsigned int ueid, const OctetString* req, OctetString* rsp, esm_sap_error_t* err); +static int _esm_sap_send(int msg_type, int is_standalone, unsigned int ueid, int pti, int ebi, const esm_sap_data_t* data, OctetString* rsp); +#endif + +/* + * String representation of ESM-SAP primitives + */ +static const char* _esm_sap_primitive_str[] = { + "ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REQ", + "ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF", + "ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ", + "ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REQ", + "ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_CNF", + "ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REJ", + "ESM_EPS_BEARER_CONTEXT_MODIFY_REQ", + "ESM_EPS_BEARER_CONTEXT_MODIFY_CNF", + "ESM_EPS_BEARER_CONTEXT_MODIFY_REJ", + "ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ", + "ESM_EPS_BEARER_CONTEXT_DEACTIVATE_CNF", + "ESM_PDN_CONNECTIVITY_REQ", + "ESM_PDN_CONNECTIVITY_REJ", + "ESM_PDN_DISCONNECT_REQ", + "ESM_PDN_DISCONNECT_REJ", + "ESM_BEARER_RESOURCE_ALLOCATE_REQ", + "ESM_BEARER_RESOURCE_ALLOCATE_REJ", + "ESM_BEARER_RESOURCE_MODIFY_REQ", + "ESM_BEARER_RESOURCE_MODIFY_REJ", + "ESM_UNITDATA_IND", +}; + +/* + * Buffer used to encode ESM messages before being returned to the EPS + * Mobility Management sublayer in order to be sent onto the network + */ +#define ESM_SAP_BUFFER_SIZE 4096 +static char _esm_sap_buffer[ESM_SAP_BUFFER_SIZE]; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: esm_sap_initialize() ** + ** ** + ** Description: Initializes the ESM Service Access Point state machine ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: NONE ** + ** ** + ***************************************************************************/ +void esm_sap_initialize(void) +{ + LOG_FUNC_IN; + + /* Initialize ESM state machine */ + //esm_fsm_initialize(); + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: esm_sap_send() ** + ** ** + ** Description: Processes the ESM Service Access Point primitive ** + ** ** + ** Inputs: msg: The ESM-SAP primitive to process ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_sap_send(esm_sap_t* msg) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + int pid; + + /* Check the ESM-SAP primitive */ + esm_primitive_t primitive = msg->primitive; + assert( (primitive > ESM_START) && (primitive < ESM_END)); + + LOG_TRACE(INFO, "ESM-SAP - Received primitive %s (%d)", + _esm_sap_primitive_str[primitive - ESM_START - 1], primitive); + + switch (primitive) + { + case ESM_PDN_CONNECTIVITY_REQ: +#ifdef NAS_UE + { + esm_pdn_connectivity_t* pdn_connect = &msg->data.pdn_connect; + if ( !msg->is_standalone || !pdn_connect->is_defined ) + { + OctetString apn = {0, NULL}; + if (pdn_connect->apn) { + apn.length = strlen(pdn_connect->apn); + apn.value = (uint8_t*)pdn_connect->apn; + } + /* Define new PDN context */ + rc = esm_proc_pdn_connectivity(pdn_connect->cid, TRUE, + pdn_connect->pdn_type, &apn, + pdn_connect->is_emergency, NULL); + if ( msg->is_standalone || (rc != RETURNok) ) { + break; + } + } + if (pdn_connect->is_defined) + { + unsigned int pti; + /* Assign new procedure transaction identity */ + rc = esm_proc_pdn_connectivity(pdn_connect->cid, TRUE, + pdn_connect->pdn_type, NULL, + pdn_connect->is_emergency, &pti); + if (rc != RETURNerror) { + /* Send PDN connectivity request */ + rc = _esm_sap_send(PDN_CONNECTIVITY_REQUEST, + msg->is_standalone, + pti, EPS_BEARER_IDENTITY_UNASSIGNED, + &msg->data, &msg->send); + } + } + } +#endif +#ifdef NAS_MME + /* The MME received a PDN connectivity request message */ + rc = _esm_sap_recv(PDN_CONNECTIVITY_REQUEST, msg->is_standalone, + msg->ueid, msg->recv, &msg->send, &msg->err); +#endif + break; + + case ESM_PDN_CONNECTIVITY_REJ: +#ifdef NAS_MME + /* PDN connectivity locally failed */ + pid = esm_proc_default_eps_bearer_context_failure(msg->ueid); + if (pid != RETURNerror) { + rc = esm_proc_pdn_connectivity_failure(msg->ueid, pid); + } +#endif +#ifdef NAS_UE + { + esm_pdn_connectivity_t* pdn_connect = &msg->data.pdn_connect; + if ( msg->is_standalone && pdn_connect->is_defined ) + { + /* Undefine the specified PDN context */ + rc = esm_proc_pdn_connectivity(pdn_connect->cid, FALSE, + pdn_connect->pdn_type, NULL, + pdn_connect->is_emergency, NULL); + } + else if (msg->recv != NULL) { + /* The UE received a PDN connectivity reject message */ + rc = _esm_sap_recv(PDN_CONNECTIVITY_REJECT, msg->is_standalone, + msg->recv, &msg->send, &msg->err); + } + else { + /* The PDN connectivity procedure locally failed */ + rc = esm_proc_pdn_connectivity_failure(TRUE); + } + } +#endif + break; + + case ESM_PDN_DISCONNECT_REQ: +#ifdef NAS_UE + { + unsigned int pti, ebi; + /* Get the procedure transaction identity and the EPS bearer + * identity of the default bearer assigned to the PDN to + * disconnect from */ + rc = esm_proc_pdn_disconnect(msg->data.pdn_disconnect.cid, + &pti, &ebi); + if (rc != RETURNerror) { + /* Send PDN disconnect request */ + rc = _esm_sap_send(PDN_DISCONNECT_REQUEST, TRUE, pti, ebi, + &msg->data, &msg->send); + } + } +#endif + break; + + case ESM_PDN_DISCONNECT_REJ: + break; + + case ESM_BEARER_RESOURCE_ALLOCATE_REQ: + break; + + case ESM_BEARER_RESOURCE_ALLOCATE_REJ: + break; + + case ESM_BEARER_RESOURCE_MODIFY_REQ: + break; + + case ESM_BEARER_RESOURCE_MODIFY_REJ: + break; + + case ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REQ: +#ifdef NAS_UE + /* The UE received activate default ESP bearer context request */ + rc = _esm_sap_recv(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST, + msg->is_standalone, + msg->recv, &msg->send, &msg->err); +#endif + break; + + case ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF: +#ifdef NAS_MME + /* The MME received activate default ESP bearer context accept */ + rc = _esm_sap_recv(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT, + msg->is_standalone, msg->ueid, + msg->recv, &msg->send, &msg->err); +#endif +#ifdef NAS_UE + /* + * The activate default ESP bearer context accept message + * has been successfully delivered to the other side + */ + rc = esm_proc_default_eps_bearer_context_complete(); + if (rc != RETURNerror) { + rc = esm_proc_pdn_connectivity_complete(); + } +#endif + break; + + case ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ: +#ifdef NAS_MME + /* The MME received activate default ESP bearer context reject */ + rc = _esm_sap_recv(ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT, + msg->is_standalone, msg->ueid, + msg->recv, &msg->send, &msg->err); +#endif +#ifdef NAS_UE + /* + * Default ESP bearer context activation procedure locally failed + */ + rc = esm_proc_default_eps_bearer_context_failure(); + if (rc != RETURNerror) { + rc = esm_proc_pdn_connectivity_failure(FALSE); + } +#endif + break; + + case ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REQ: + break; + + case ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_CNF: + break; + + case ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REJ: + break; + + case ESM_EPS_BEARER_CONTEXT_MODIFY_REQ: + break; + + case ESM_EPS_BEARER_CONTEXT_MODIFY_CNF: + break; + + case ESM_EPS_BEARER_CONTEXT_MODIFY_REJ: + break; + + case ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ: + { + int bid; + /* + * Locally deactivate EPS bearer context + */ +#ifdef NAS_UE + rc = esm_proc_eps_bearer_context_deactivate(TRUE, + msg->data.eps_bearer_context_deactivate.ebi, &pid, &bid); +#endif +#ifdef NAS_MME + rc = esm_proc_eps_bearer_context_deactivate(msg->ueid, TRUE, + msg->data.eps_bearer_context_deactivate.ebi, + &pid, &bid, NULL); +#endif + } + break; + + case ESM_EPS_BEARER_CONTEXT_DEACTIVATE_CNF: + break; + + case ESM_UNITDATA_IND: +#ifdef NAS_UE + rc = _esm_sap_recv(-1, msg->is_standalone, msg->recv, + &msg->send, &msg->err); +#endif +#ifdef NAS_MME + rc = _esm_sap_recv(-1, msg->is_standalone, msg->ueid, + msg->recv, &msg->send, &msg->err); +#endif + break; + + default: + break; + } + +#ifdef NAS_MME + if (rc != RETURNok) { + LOG_TRACE(ERROR, "ESM-SAP - Failed to process primitive %s (%d)", + _esm_sap_primitive_str[primitive - ESM_START - 1], primitive); + } +#endif + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _esm_sap_recv() ** + ** ** + ** Description: Processes ESM messages received from the network: Decodes ** + ** the message and checks whether it is of the expected ty- ** + ** pe, checks the validity of the procedure transaction iden-** + ** tity, checks the validity of the EPS bearer identity, and ** + ** parses the message content. ** + ** If no protocol error is found the ESM response message is ** + ** returned in order to be sent back onto the network upon ** + ** the relevant ESM procedure completion. ** + ** If a protocol error is found the ESM status message is ** + ** returned including the value of the ESM cause code. ** + ** ** + ** Inputs: msg_type: Expected type of the received ESM message ** + ** is_standalone: Indicates whether the ESM message has been ** + ** received standalone or together within EMM ** + ** attach related message ** + ** ueid: UE identifier within the MME ** + ** req: The encoded ESM request message to process ** + ** Others: None ** + ** ** + ** Outputs: rsp: The encoded ESM response message to be re- ** + ** turned upon ESM procedure completion ** + ** err: Error code of the ESM procedure ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_sap_buffer ** + ** ** + ***************************************************************************/ +static int _esm_sap_recv(int msg_type, int is_standalone, +#ifdef NAS_MME + unsigned int ueid, +#endif + const OctetString* req, OctetString* rsp, + esm_sap_error_t* err) +{ + LOG_FUNC_IN; + + esm_proc_procedure_t esm_procedure = NULL; + int esm_cause = ESM_CAUSE_SUCCESS; + int rc = RETURNerror; + + ESM_msg esm_msg; + memset(&esm_msg, 0 , sizeof(ESM_msg)); + + /* Decode the received ESM message */ + int decoder_rc = esm_msg_decode(&esm_msg, req->value, req->length); + + /* Process decoding errors */ + if (decoder_rc < 0) { + /* 3GPP TS 24.301, section 7.2 + * Ignore received message that is too short to contain a complete + * message type information element */ + if (decoder_rc == TLV_DECODE_BUFFER_TOO_SHORT) { + LOG_TRACE(WARNING, "ESM-SAP - Discard message too short to " + "contain a complete message type IE"); + /* Return indication that received message has been discarded */ + *err = ESM_SAP_DISCARDED; + LOG_FUNC_RETURN (RETURNok); + } + /* 3GPP TS 24.301, section 7.2 + * Unknown or unforeseen message type */ + else if (decoder_rc == TLV_DECODE_WRONG_MESSAGE_TYPE) { + esm_cause = ESM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED; + } + /* 3GPP TS 24.301, section 7.7.2 + * Conditional IE errors */ + else if (decoder_rc == TLV_DECODE_UNEXPECTED_IEI) { + esm_cause = ESM_CAUSE_CONDITIONAL_IE_ERROR; + } + else { + esm_cause = ESM_CAUSE_PROTOCOL_ERROR; + } + } + /* Check the type of the ESM message actually received */ + else if ( (msg_type > 0) && (msg_type != esm_msg.header.message_type) ) { + if (esm_msg.header.message_type != ESM_STATUS) { + /* Semantically incorrect ESM message */ + LOG_TRACE(ERROR, "ESM-SAP - Received ESM message 0x%x is not " + "of the expected type (0x%x)", + esm_msg.header.message_type, msg_type); + esm_cause = ESM_CAUSE_SEMANTICALLY_INCORRECT; + } + } + + /* Get the procedure transaction identity */ + unsigned int pti = esm_msg.header.procedure_transaction_identity; + /* Get the EPS bearer identity */ + unsigned int ebi = esm_msg.header.eps_bearer_identity; + /* Indicate whether the ESM bearer context related procedure was triggered + * by the receipt of a transaction related request message from the UE or + * was triggered network-internally */ + int triggered_by_ue = (pti != PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED); + /* Indicate whether the received message shall be ignored */ + int is_discarded = FALSE; + + if (esm_cause != ESM_CAUSE_SUCCESS) { + LOG_TRACE(ERROR, "ESM-SAP - Failed to decode expected ESM message " + "0x%x", msg_type); + } + /* Process the received ESM message */ + else switch (esm_msg.header.message_type) + { +#ifdef NAS_UE + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + /* + * Process activate default EPS bearer context request message + * received from the MME + */ + esm_cause = esm_recv_activate_default_eps_bearer_context_request( + pti, ebi, + &esm_msg.activate_default_eps_bearer_context_request); + + if ( (esm_cause == ESM_CAUSE_SUCCESS) || + (esm_cause == ESM_CAUSE_PTI_ALREADY_IN_USE) ) + { + /* Return accept message */ + rc = esm_send_activate_default_eps_bearer_context_accept(ebi, + &esm_msg.activate_default_eps_bearer_context_accept); + /* Setup the callback function used to send activate default + * EPS bearer context accept message onto the network */ + esm_procedure = esm_proc_default_eps_bearer_context_accept; + if (esm_cause == ESM_CAUSE_PTI_ALREADY_IN_USE) { + /* 3GPP TS 24.301, section 7.3.1, case g + * Return accept message, even to network retransmission + * of already accepted activate default EPS bearer context + * request message + */ + is_discarded = TRUE; + } + } + else { + /* Return reject message */ + rc = esm_send_activate_default_eps_bearer_context_reject(ebi, + &esm_msg.activate_default_eps_bearer_context_reject, + esm_cause); + /* Setup the callback function used to send activate default + * EPS bearer context reject message onto the network */ + esm_procedure = esm_proc_default_eps_bearer_context_reject; + } + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST: + /* + * Process activate dedicated EPS bearer context request message + * received from the MME + */ + esm_cause = esm_recv_activate_dedicated_eps_bearer_context_request( + pti, ebi, + &esm_msg.activate_dedicated_eps_bearer_context_request); + + if ( (esm_cause == ESM_CAUSE_SUCCESS) || + (esm_cause == ESM_CAUSE_PTI_ALREADY_IN_USE) ) + { + /* Return accept message */ + rc = esm_send_activate_dedicated_eps_bearer_context_accept(ebi, + &esm_msg.activate_dedicated_eps_bearer_context_accept); + /* Setup the callback function used to send activate dedicated + * EPS bearer context accept message onto the network */ + esm_procedure = esm_proc_dedicated_eps_bearer_context_accept; + if (esm_cause == ESM_CAUSE_PTI_ALREADY_IN_USE) { + /* 3GPP TS 24.301, section 7.3.1, case i + * Return accept message, even to network retransmission + * of already accepted activate dedicated EPS bearer context + * request message + */ + is_discarded = TRUE; + } + } + else { + /* Return reject message */ + rc = esm_send_activate_dedicated_eps_bearer_context_reject(ebi, + &esm_msg.activate_dedicated_eps_bearer_context_reject, + esm_cause); + /* Setup the callback function used to send activate dedicated + * EPS bearer context reject message onto the network */ + esm_procedure = esm_proc_dedicated_eps_bearer_context_reject; + } + break; + + case MODIFY_EPS_BEARER_CONTEXT_REQUEST: + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST: + /* + * Process deactivate EPS bearer context request message + * received from the MME + */ + esm_cause = esm_recv_deactivate_eps_bearer_context_request(pti, ebi, + &esm_msg.deactivate_eps_bearer_context_request); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_PTI_MISMATCH) ) + { + /* 3GPP TS 24.301, section 7.3.1, case m + * Ignore deactivate EPS bearer context request message + * received with PTI reserved value, or assigned value + * that does not match any PTI in use + */ + is_discarded = TRUE; + } + else if ( (esm_cause == ESM_CAUSE_SUCCESS) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* Return accept message */ + rc = esm_send_deactivate_eps_bearer_context_accept(ebi, + &esm_msg.deactivate_eps_bearer_context_accept); + /* Setup the callback function used to send deactivate + * EPS bearer context accept message onto the network */ + esm_procedure = esm_proc_eps_bearer_context_deactivate_accept; + if (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) { + /* 3GPP TS 24.301, section 7.3.2, case j + * Respond with a deactivate EPS bearer context accept + * message with the EPS bearer identity set to the received + * EPS bearer identity + */ + is_discarded = TRUE; + } + } + break; + + case PDN_CONNECTIVITY_REJECT: + /* + * Process PDN connectivity reject message received from the MME + */ + esm_cause = esm_recv_pdn_connectivity_reject(pti, ebi, + &esm_msg.pdn_connectivity_reject); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_PTI_MISMATCH) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case a + * Ignore PDN connectivity reject message received with + * reserved or unassigned PTI value, or assigned value that + * does not match any PTI in use + * 3GPP TS 24.301, section 7.3.2, case a + * Ignore PDN connectivity reject message received with + * reserved or unassigned EPS bearer identity value + */ + is_discarded = TRUE; + } + break; + + case PDN_DISCONNECT_REJECT: + /* + * Process PDN disconnect reject message received from the MME + */ + esm_cause = esm_recv_pdn_disconnect_reject(pti, ebi, + &esm_msg.pdn_disconnect_reject); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_PTI_MISMATCH) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case b + * Ignore PDN disconnect reject message received with + * reserved or unassigned PTI value, or assigned value that + * does not match any PTI in use + * 3GPP TS 24.301, section 7.3.2, case b + * Ignore PDN disconnect reject message received with + * reserved or unassigned EPS bearer identity value + */ + is_discarded = TRUE; + } + break; + + case BEARER_RESOURCE_ALLOCATION_REJECT: + break; + + case BEARER_RESOURCE_MODIFICATION_REJECT: + break; + + case ESM_INFORMATION_REQUEST: + break; + + case ESM_STATUS: + /* + * Process received ESM status message + */ + esm_cause = esm_recv_status(pti, ebi, &esm_msg.esm_status); + break; +#endif + +#ifdef NAS_MME + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + /* + * Process activate default EPS bearer context accept message + * received from the UE + */ + esm_cause = esm_recv_activate_default_eps_bearer_context_accept( + ueid, pti, ebi, + &esm_msg.activate_default_eps_bearer_context_accept); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case f + * Ignore ESM message received with reserved PTI value + * 3GPP TS 24.301, section 7.3.2, case f + * Ignore ESM message received with reserved or assigned + * value that does not match an existing EPS bearer context + */ + is_discarded = TRUE; + } + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + /* + * Process activate default EPS bearer context reject message + * received from the UE + */ + esm_cause = esm_recv_activate_default_eps_bearer_context_reject( + ueid, pti, ebi, + &esm_msg.activate_default_eps_bearer_context_reject); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case f + * Ignore ESM message received with reserved PTI value + * 3GPP TS 24.301, section 7.3.2, case f + * Ignore ESM message received with reserved or assigned + * value that does not match an existing EPS bearer context + */ + is_discarded = TRUE; + } + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + /* + * Process deactivate EPS bearer context accept message + * received from the UE + */ + esm_cause = esm_recv_deactivate_eps_bearer_context_accept( + ueid, pti, ebi, + &esm_msg.deactivate_eps_bearer_context_accept); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case f + * Ignore ESM message received with reserved PTI value + * 3GPP TS 24.301, section 7.3.2, case f + * Ignore ESM message received with reserved or assigned + * value that does not match an existing EPS bearer context + */ + is_discarded = TRUE; + } + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT: + /* + * Process activate dedicated EPS bearer context accept message + * received from the UE + */ + esm_cause = esm_recv_activate_dedicated_eps_bearer_context_accept( + ueid, pti, ebi, + &esm_msg.activate_dedicated_eps_bearer_context_accept); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case f + * Ignore ESM message received with reserved PTI value + * 3GPP TS 24.301, section 7.3.2, case f + * Ignore ESM message received with reserved or assigned + * value that does not match an existing EPS bearer context + */ + is_discarded = TRUE; + } + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT: + /* + * Process activate dedicated EPS bearer context reject message + * received from the UE + */ + esm_cause = esm_recv_activate_dedicated_eps_bearer_context_reject( + ueid, pti, ebi, + &esm_msg.activate_dedicated_eps_bearer_context_reject); + + if ( (esm_cause == ESM_CAUSE_INVALID_PTI_VALUE) || + (esm_cause == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) ) + { + /* 3GPP TS 24.301, section 7.3.1, case f + * Ignore ESM message received with reserved PTI value + * 3GPP TS 24.301, section 7.3.2, case f + * Ignore ESM message received with reserved or assigned + * value that does not match an existing EPS bearer context + */ + is_discarded = TRUE; + } + break; + + case MODIFY_EPS_BEARER_CONTEXT_ACCEPT: + break; + + case MODIFY_EPS_BEARER_CONTEXT_REJECT: + break; + + case PDN_CONNECTIVITY_REQUEST: + { + esm_proc_data_t data; + memset(&data, 0, sizeof(esm_proc_data_t)); + + /* + * Process PDN connectivity request message received from the UE + */ + esm_cause = esm_recv_pdn_connectivity_request(ueid, pti, ebi, + &esm_msg.pdn_connectivity_request, + &ebi, &data); + + if (esm_cause != ESM_CAUSE_SUCCESS) { + /* Return reject message */ + rc = esm_send_pdn_connectivity_reject(pti, + &esm_msg.pdn_connectivity_reject, esm_cause); + /* Setup the callback function used to send PDN connectivity + * reject message onto the network */ + esm_procedure = esm_proc_pdn_connectivity_reject; + /* No ESM status message should be returned */ + esm_cause = ESM_CAUSE_SUCCESS; + } + else { + /* Setup PDN type */ + int pdn_type = -1; + if (data.pdn_type == ESM_PDN_TYPE_IPV4) { + pdn_type = PDN_VALUE_TYPE_IPV4; + } else if (data.pdn_type == ESM_PDN_TYPE_IPV6) { + pdn_type = PDN_VALUE_TYPE_IPV6; + } else if (data.pdn_type == ESM_PDN_TYPE_IPV4V6) { + pdn_type = PDN_VALUE_TYPE_IPV4V6; + } + /* Setup EPS bearer level Quality of Service */ + EpsQualityOfService qos; + qos.bitRatesPresent = 1; + qos.bitRatesExtPresent = 0; + qos.qci = data.qos.qci; + qos.bitRates.maxBitRateForUL = data.qos.mbrUL; + qos.bitRates.maxBitRateForDL = data.qos.mbrDL; + qos.bitRates.guarBitRateForUL = data.qos.gbrUL; + qos.bitRates.guarBitRateForDL = data.qos.gbrDL; + + /* Return default EPS bearer context request message */ + rc = esm_send_activate_default_eps_bearer_context_request( + pti, ebi, + &esm_msg.activate_default_eps_bearer_context_request, + &data.apn, pdn_type, &data.pdn_addr, &qos, esm_cause); +#if 0 + PacketFilters pkfs; + pkfs[0].identifier = 1; + pkfs[0].direction = TRAFFIC_FLOW_TEMPLATE_DOWNLINK_ONLY; + pkfs[0].eval_precedence = 2; + pkfs[0].packetfilter.flags = + (TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG | + TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG | + TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG | + TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG); + pkfs[0].packetfilter.ipv4remoteaddr[0].addr = 192; + pkfs[0].packetfilter.ipv4remoteaddr[1].addr = 168; + pkfs[0].packetfilter.ipv4remoteaddr[2].addr = 12; + pkfs[0].packetfilter.ipv4remoteaddr[3].addr = 1; + pkfs[0].packetfilter.ipv4remoteaddr[0].mask = 255; + pkfs[0].packetfilter.ipv4remoteaddr[1].mask = 255; + pkfs[0].packetfilter.ipv4remoteaddr[2].mask = 255; + pkfs[0].packetfilter.ipv4remoteaddr[3].mask = 0; + pkfs[0].packetfilter.protocolidentifier_nextheader = 17; + pkfs[0].packetfilter.singlelocalport = 10001; + pkfs[0].packetfilter.singleremoteport = 12001; + pkfs[1].identifier = 2; + pkfs[1].direction = TRAFFIC_FLOW_TEMPLATE_UPLINK_ONLY; + pkfs[1].eval_precedence = 3; + pkfs[1].packetfilter.flags = + (TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG | + TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG | + TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG | + TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG); + pkfs[1].packetfilter.ipv4remoteaddr[0].addr = 192; + pkfs[1].packetfilter.ipv4remoteaddr[1].addr = 168; + pkfs[1].packetfilter.ipv4remoteaddr[2].addr = 12; + pkfs[1].packetfilter.ipv4remoteaddr[3].addr = 1; + pkfs[1].packetfilter.ipv4remoteaddr[0].mask = 255; + pkfs[1].packetfilter.ipv4remoteaddr[1].mask = 255; + pkfs[1].packetfilter.ipv4remoteaddr[2].mask = 255; + pkfs[1].packetfilter.ipv4remoteaddr[3].mask = 0; + pkfs[1].packetfilter.protocolidentifier_nextheader = 17; + pkfs[1].packetfilter.singlelocalport = 10002; + pkfs[1].packetfilter.singleremoteport = 12002; + /* Return dedicated EPS bearer context request message */ + rc = esm_send_activate_dedicated_eps_bearer_context_request( + pti, ebi, + &esm_msg.activate_dedicated_eps_bearer_context_request, + ebi, &qos, &pkfs, 2); +#endif + /* Setup the callback function used to send default EPS bearer + * context request message onto the network */ + esm_procedure = esm_proc_default_eps_bearer_context_request; + } + break; + } + + case PDN_DISCONNECT_REQUEST: + /* + * Process PDN disconnect request message received from the UE + */ + esm_cause = esm_recv_pdn_disconnect_request(ueid, pti, ebi, + &esm_msg.pdn_disconnect_request, &ebi); + + if (esm_cause != ESM_CAUSE_SUCCESS) { + /* Return reject message */ + rc = esm_send_pdn_disconnect_reject(pti, + &esm_msg.pdn_disconnect_reject, esm_cause); + /* Setup the callback function used to send PDN connectivity + * reject message onto the network */ + esm_procedure = esm_proc_pdn_disconnect_reject; + /* No ESM status message should be returned */ + esm_cause = ESM_CAUSE_SUCCESS; + } + else { + /* Return deactivate EPS bearer context request message */ + rc = esm_send_deactivate_eps_bearer_context_request(pti, ebi, + &esm_msg.deactivate_eps_bearer_context_request, + ESM_CAUSE_REGULAR_DEACTIVATION); + /* Setup the callback function used to send deactivate EPS + * bearer context request message onto the network */ + esm_procedure = esm_proc_eps_bearer_context_deactivate_request; + } + break; + + case BEARER_RESOURCE_ALLOCATION_REQUEST: + break; + + case BEARER_RESOURCE_MODIFICATION_REQUEST: + break; + + case ESM_INFORMATION_RESPONSE: + break; + + case ESM_STATUS: + /* + * Process received ESM status message + */ + esm_cause = esm_recv_status(ueid, pti, ebi, &esm_msg.esm_status); + break; +#endif + + default: + LOG_TRACE(WARNING, "ESM-SAP - Received unexpected ESM message " + "0x%x", esm_msg.header.message_type); + esm_cause = ESM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED; + break; + } + + if ( (esm_cause != ESM_CAUSE_SUCCESS) && (esm_procedure == NULL) ) { + /* ESM message processing failed */ + if (!is_discarded) { + /* 3GPP TS 24.301, section 7.1 + * Handling of unknown, unforeseen, and erroneous protocol data */ + LOG_TRACE(WARNING, "ESM-SAP - Received ESM message is not valid " + "(cause=%d)", esm_cause); + /* Return an ESM status message */ + rc = esm_send_status(pti, ebi, &esm_msg.esm_status, esm_cause); + /* Setup the callback function used to send ESM status message + * onto the network */ + esm_procedure = esm_proc_status; + /* Discard received ESM message */ + is_discarded = TRUE; + } + } + else { + /* ESM message processing succeed */ + *err = ESM_SAP_SUCCESS; + rc = RETURNok; + } + + if ( (rc != RETURNerror) && (esm_procedure != NULL) ) { + /* Encode the returned ESM response message */ + int size = esm_msg_encode(&esm_msg, (uint8_t*)_esm_sap_buffer, + ESM_SAP_BUFFER_SIZE); + if (size > 0) { + rsp->length = size; + rsp->value = (uint8_t*)(_esm_sap_buffer); + } + /* Complete the relevant ESM procedure */ +#ifdef NAS_UE + rc = (*esm_procedure)(is_standalone, ebi, rsp, triggered_by_ue); +#endif +#ifdef NAS_MME + rc = (*esm_procedure)(is_standalone, ueid, ebi, rsp, triggered_by_ue); +#endif + if (is_discarded) { + /* Return indication that received message has been discarded */ + *err = ESM_SAP_DISCARDED; + } + else if (rc != RETURNok) { + /* Return indication that ESM procedure failed */ + *err = ESM_SAP_FAILED; + } + } + else if (is_discarded) { + LOG_TRACE(WARNING, "ESM-SAP - Silently discard message type 0x%x", + esm_msg.header.message_type); + /* Return indication that received message has been discarded */ + *err = ESM_SAP_DISCARDED; + rc = RETURNok; + } + + LOG_FUNC_RETURN(rc); +} + +/**************************************************************************** + ** ** + ** Name: _esm_sap_send() ** + ** ** + ** Description: Processes ESM messages to send onto the network: Encoded ** + ** the message and execute the relevant ESM procedure. ** + ** ** + ** Inputs: msg_type: Type of the ESM message to be sent ** + ** is_standalone: Indicates whether the ESM message has to ** + ** be sent standalone or together within EMM ** + ** attach related message ** + ** ueid: UE identifier within the MME ** + ** pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** data: Data required to build the message ** + ** Others: None ** + ** ** + ** Outputs: rsp: The encoded ESM response message to be re- ** + ** turned upon ESM procedure completion ** + ** Return: RETURNok, RETURNerror ** + ** Others: _esm_sap_buffer ** + ** ** + ***************************************************************************/ +static int _esm_sap_send(int msg_type, int is_standalone, +#ifdef NAS_MME + unsigned int ueid, +#endif + int pti, int ebi, const esm_sap_data_t* data, + OctetString* rsp) +{ + LOG_FUNC_IN; + + esm_proc_procedure_t esm_procedure = NULL; + int rc = RETURNok; + + /* Indicate whether the message is sent by the UE or the MME */ +#ifdef NAS_UE + int sent_by_ue = TRUE; +#endif +#ifdef NAS_MME + int sent_by_ue = FALSE; +#endif + + ESM_msg esm_msg; + memset(&esm_msg, 0 , sizeof(ESM_msg)); + + /* Process the ESM message to send */ + switch (msg_type) + { +#ifdef NAS_UE + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT: + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT: + break; + + case MODIFY_EPS_BEARER_CONTEXT_ACCEPT: + break; + + case MODIFY_EPS_BEARER_CONTEXT_REJECT: + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + break; + + case PDN_CONNECTIVITY_REQUEST: + { + /* + * Process PDN connectivity request message to send to the MME + */ + const esm_pdn_connectivity_t* msg = &data->pdn_connect; + rc = esm_send_pdn_connectivity_request(pti, msg->is_emergency, + msg->pdn_type, msg->apn, + &esm_msg.pdn_connectivity_request); + /* Setup callback function used to send PDN connectivity request + * message onto the network */ + esm_procedure = esm_proc_pdn_connectivity_request; + break; + } + + case PDN_DISCONNECT_REQUEST: + /* + * Process PDN disconnect request message to send to the MME + */ + rc = esm_send_pdn_disconnect_request(pti, ebi, + &esm_msg.pdn_disconnect_request); + /* Setup callback function used to send PDN disconnect request + * message onto the network */ + esm_procedure = esm_proc_pdn_disconnect_request; + break; + + case BEARER_RESOURCE_ALLOCATION_REQUEST: + break; + + case BEARER_RESOURCE_MODIFICATION_REQUEST: + break; +#endif + +#ifdef NAS_MME + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST: + break; + + case MODIFY_EPS_BEARER_CONTEXT_REQUEST: + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST: + break; + + case PDN_CONNECTIVITY_REJECT: + break; + + case PDN_DISCONNECT_REJECT: + break; + + case BEARER_RESOURCE_ALLOCATION_REJECT: + break; + + case BEARER_RESOURCE_MODIFICATION_REJECT: + break; +#endif + default: + LOG_TRACE(WARNING, "ESM-SAP - Send unexpected ESM message 0x%x", + msg_type); + break; + } + + if (rc != RETURNerror) { + /* Encode the returned ESM response message */ + int size = esm_msg_encode(&esm_msg, (uint8_t*)_esm_sap_buffer, + ESM_SAP_BUFFER_SIZE); + + if (size > 0) { + rsp->length = size; + rsp->value = (uint8_t*)(_esm_sap_buffer); + } + /* Execute the relevant ESM procedure */ + if (esm_procedure) { +#ifdef NAS_UE + rc = (*esm_procedure)(is_standalone, pti, rsp, sent_by_ue); +#endif +#ifdef NAS_MME + rc = (*esm_procedure)(is_standalone, ueid, pti, rsp, sent_by_ue); +#endif + } + } + + LOG_FUNC_RETURN(rc); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h new file mode 100644 index 0000000000..e69196800d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sap.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_sap.h + +Version 0.1 + +Date 2012/11/22 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the ESM Service Access Points at which the EPS + Session Management sublayer provides procedures for the + EPS bearer context handling and resources allocation. + +*****************************************************************************/ +#ifndef __ESM_SAP_H__ +#define __ESM_SAP_H__ + +#include "esm_sapDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void esm_sap_initialize(void); + +int esm_sap_send(esm_sap_t* msg); + +#endif /* __ESM_SAP_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h new file mode 100644 index 0000000000..99b27659c2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_sapDef.h @@ -0,0 +1,150 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_sapDef.h + +Version 0.1 + +Date 2012/11/21 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines the ESM Service Access Point that provides EPS + bearer context handling and resources allocation procedures. + +*****************************************************************************/ +#ifndef __ESM_SAPDEF_H__ +#define __ESM_SAPDEF_H__ + +#include "OctetString.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * EPS Session Management primitives + * --------------------------------- + */ +typedef enum { + ESM_START = 0, + /* Procedures related to EPS bearer contexts (initiated by the network) */ + ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REQ, + ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF, + ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ, + ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REQ, + ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_CNF, + ESM_DEDICATED_EPS_BEARER_CONTEXT_ACTIVATE_REJ, + ESM_EPS_BEARER_CONTEXT_MODIFY_REQ, + ESM_EPS_BEARER_CONTEXT_MODIFY_CNF, + ESM_EPS_BEARER_CONTEXT_MODIFY_REJ, + ESM_EPS_BEARER_CONTEXT_DEACTIVATE_REQ, + ESM_EPS_BEARER_CONTEXT_DEACTIVATE_CNF, + /* Transaction related procedures (initiated by the UE) */ + ESM_PDN_CONNECTIVITY_REQ, + ESM_PDN_CONNECTIVITY_REJ, + ESM_PDN_DISCONNECT_REQ, + ESM_PDN_DISCONNECT_REJ, + ESM_BEARER_RESOURCE_ALLOCATE_REQ, + ESM_BEARER_RESOURCE_ALLOCATE_REJ, + ESM_BEARER_RESOURCE_MODIFY_REQ, + ESM_BEARER_RESOURCE_MODIFY_REJ, + /* ESM data indication ("raw" ESM message) */ + ESM_UNITDATA_IND, + ESM_END +} esm_primitive_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * Error code returned upon processing ESM-SAP primitive + */ +typedef enum { + ESM_SAP_SUCCESS = 1, /* ESM-SAP primitive succeed */ + ESM_SAP_DISCARDED, /* ESM-SAP primitive failed, the caller should + * ignore the error */ + ESM_SAP_FAILED /* ESM-SAP primitive failed, the caller should + * take specific action and state transition may + * occurs */ +} esm_sap_error_t; + +/* + * ESM primitive for activate EPS default bearer context procedure + * --------------------------------------------------------------- + */ +typedef struct { +} esm_activate_eps_default_bearer_context_t; + +/* + * ESM primitive for PDN connectivity procedure + * -------------------------------------------- + */ +typedef struct { + int cid; /* PDN connection local identifier */ + int is_defined; /* Indicates whether a PDN context has been defined + * for the specified APN */ + int pdn_type; /* PDN address type (IPv4, IPv6, IPv4v6) */ + const char* apn; /* PDN's Access Point Name */ + int is_emergency; /* Indicates whether the PDN context has been + * defined to establish connection for emergency + * bearer services */ +} esm_pdn_connectivity_t; + +/* + * ESM primitive for PDN disconnect procedure + * ------------------------------------------ + */ +typedef struct { + int cid; /* PDN connection local identifier */ +} esm_pdn_disconnect_t; + +/* + * ESM primitive for deactivate EPS bearer context procedure + * --------------------------------------------------------- + */ +typedef struct { +#define ESM_SAP_ALL_EBI 0xff + unsigned int ebi; /* EPS bearer identity of the EPS bearer context + * to be deactivated */ +} esm_eps_bearer_context_deactivate_t; + +/* + * ------------------------------ + * Structure of ESM-SAP primitive + * ------------------------------ + */ +typedef union { + esm_pdn_connectivity_t pdn_connect; + esm_pdn_disconnect_t pdn_disconnect; + esm_eps_bearer_context_deactivate_t eps_bearer_context_deactivate; +} esm_sap_data_t; + +typedef struct { + esm_primitive_t primitive; /* ESM-SAP primitive to process */ + int is_standalone; /* Indicates whether the ESM message handled + * within this primitive has to be sent/received + * standalone or together within an EMM related + * message */ + unsigned int ueid; /* Local UE identifier */ + esm_sap_error_t err; /* ESM-SAP error code */ + const OctetString* recv; /* Encoded ESM message received */ + OctetString send; /* Encoded ESM message to be sent */ + esm_sap_data_t data; /* ESM message data parameters */ +} esm_sap_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __ESM_SAPDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.c b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.c new file mode 100644 index 0000000000..8a58c31ef5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.c @@ -0,0 +1,677 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_send.c + +Version 0.1 + +Date 2013/02/11 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions executed at the ESM Service Access + Point to send EPS Session Management messages to the + EPS Mobility Management sublayer. + +*****************************************************************************/ + +#include "esm_send.h" +#include "commonDef.h" +#include "nas_log.h" + +#ifdef NAS_UE +#include "networkDef.h" +#endif + +#include "esm_msgDef.h" +#include "esm_cause.h" + +#include <string.h> // strlen + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME to send ESM messages + * -------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: esm_send_status() ** + ** ** + ** Description: Builds ESM status message ** + ** ** + ** The ESM status message is sent by the network or the UE ** + ** to pass information on the status of the indicated EPS ** + ** bearer context and report certain error conditions. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_status(int pti, int ebi, esm_status_msg* msg, int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ESM_STATUS; + msg->proceduretransactionidentity = pti; + + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + + LOG_TRACE(WARNING, "ESM-SAP - Send ESM Status message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE to send ESM message to the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: esm_send_pdn_connectivity_request() ** + ** ** + ** Description: Builds PDN Connectivity Request message ** + ** ** + ** The PDN connectivity request message is sent by the UE to ** + ** the network to initiate establishment of a PDN connection.** + ** ** + ** Inputs: pti: Procedure transaction identity assigned to ** + ** the PDN connection ** + ** is_emergency: Indicates whether the PDN connectivity is ** + ** requested for emergency bearer services ** + ** pdn_type: PDN address type ** + ** apn: Access Point Name of the PDN to connect to ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_pdn_connectivity_request(int pti, int is_emergency, int pdn_type, + const char* apn, + pdn_connectivity_request_msg* msg) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = EPS_BEARER_IDENTITY_UNASSIGNED; + msg->messagetype = PDN_CONNECTIVITY_REQUEST; + msg->proceduretransactionidentity = pti; + + /* Mandatory - PDN connectivity request type */ + if (is_emergency) { + msg->requesttype = REQUEST_TYPE_EMERGENCY; + } else { + msg->requesttype = REQUEST_TYPE_INITIAL_REQUEST; + } + + /* Mandatory - PDN type */ + if (pdn_type == NET_PDN_TYPE_IPV4) { + msg->pdntype = PDN_TYPE_IPV4; + } else if (pdn_type == NET_PDN_TYPE_IPV6) { + msg->pdntype = PDN_TYPE_IPV6; + } else if (pdn_type == NET_PDN_TYPE_IPV4V6) { + msg->pdntype = PDN_TYPE_IPV4V6; + } + + /* Optional - Access Point Name */ + msg->presencemask = 0; + if (apn) { + size_t len = strlen(apn); + if (len > 0) { + msg->presencemask |= + PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT; + msg->accesspointname.accesspointnamevalue.length = len; + msg->accesspointname.accesspointnamevalue.value = (uint8_t*)apn; + } + } + + LOG_TRACE(INFO, "ESM-SAP - Send PDN Connectivity Request message " + "(pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_pdn_disconnect_request() ** + ** ** + ** Description: Builds PDN Disconnect Request message ** + ** ** + ** The PDN disconnect request message is sent by the UE to ** + ** the network to initiate release of a PDN connection. ** + ** ** + ** Inputs: pti: Procedure transaction identity assigned to ** + ** the PDN connection ** + ** ebi: EPS bearer identity of the default bearer ** + ** associated with the PDN to disconnect from ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_pdn_disconnect_request(int pti, int ebi, + pdn_disconnect_request_msg* msg) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = EPS_BEARER_IDENTITY_UNASSIGNED; + msg->messagetype = PDN_DISCONNECT_REQUEST; + msg->proceduretransactionidentity = pti; + + /* Mandatory - Linked EPS bearer identity */ + msg->linkedepsbeareridentity = ebi; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send PDN Disconnect Request message " + "(pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_default_eps_bearer_context_accept() ** + ** ** + ** Description: Builds Activate Default EPS Bearer Context Accept message ** + ** ** + ** The activate default EPS bearer context accept message is ** + ** sent by the UE to the network to acknowledge activation ** + ** of a default EPS bearer context. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_default_eps_bearer_context_accept(int ebi, + activate_default_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT; + msg->proceduretransactionidentity = PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + /* Mandatory IEs */ + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Default EPS Bearer Context " + "Accept message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_default_eps_bearer_context_reject() ** + ** ** + ** Description: Builds Activate Default EPS Bearer Context Reject message ** + ** ** + ** The activate default EPS bearer context reject message is ** + ** sent by UE to the network to reject activation of a de- ** + ** fault EPS bearer context. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_default_eps_bearer_context_reject(int ebi, + activate_default_eps_bearer_context_reject_msg* msg, int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT; + msg->proceduretransactionidentity = PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Default EPS Bearer Context " + "Reject message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_dedicated_eps_bearer_context_accept() ** + ** ** + ** Description: Builds Activate Dedicated EPS Bearer Context Accept ** + ** message ** + ** ** + ** The activate dedicated EPS bearer context accept message ** + ** is sent by the UE to the network to acknowledge activa- ** + ** tion of a dedicated EPS bearer context associated with ** + ** the same PDN address(es) and APN as an already active EPS ** + ** bearer context. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_dedicated_eps_bearer_context_accept(int ebi, + activate_dedicated_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT; + msg->proceduretransactionidentity = PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + /* Mandatory IEs */ + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Dedicated EPS Bearer Context " + "Accept message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_dedicated_eps_bearer_context_reject() ** + ** ** + ** Description: Builds Activate Dedicated EPS Bearer Context Reject ** + ** message ** + ** ** + ** The activate dedicated EPS bearer context reject message ** + ** is sent by UE to the network to reject activation of a ** + ** dedicated EPS bearer context. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_dedicated_eps_bearer_context_reject(int ebi, + activate_dedicated_eps_bearer_context_reject_msg* msg, int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT; + msg->proceduretransactionidentity = PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Dedicated EPS Bearer Context " + "Reject message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_deactivate_eps_bearer_context_accept() ** + ** ** + ** Description: Builds Deactivate EPS Bearer Context Accept message ** + ** ** + ** The deactivate EPS bearer context accept message is sent ** + ** by the UE to acknowledge deactivation of an EPS bearer ** + ** context. ** + ** ** + ** Inputs: ebi: EPS bearer identity ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_deactivate_eps_bearer_context_accept(int ebi, + deactivate_eps_bearer_context_accept_msg* msg) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT; + msg->proceduretransactionidentity = PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED; + /* Mandatory IEs */ + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Deactivate EPS Bearer Context Accept" + " message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} +#endif // NAS_UE + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME to send ESM message to the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: esm_send_pdn_connectivity_reject() ** + ** ** + ** Description: Builds PDN Connectivity Reject message ** + ** ** + ** The PDN connectivity reject message is sent by the net- ** + ** work to the UE to reject establishment of a PDN connec- ** + ** tion. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_pdn_connectivity_reject(int pti, pdn_connectivity_reject_msg* msg, + int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = EPS_BEARER_IDENTITY_UNASSIGNED; + msg->messagetype = PDN_CONNECTIVITY_REJECT; + msg->proceduretransactionidentity = pti; + + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send PDN Connectivity Reject message " + "(pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_pdn_disconnect_reject() ** + ** ** + ** Description: Builds PDN Disconnect Reject message ** + ** ** + ** The PDN disconnect reject message is sent by the network ** + ** to the UE to reject release of a PDN connection. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_pdn_disconnect_reject(int pti, pdn_disconnect_reject_msg* msg, + int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = EPS_BEARER_IDENTITY_UNASSIGNED; + msg->messagetype = PDN_DISCONNECT_REJECT; + msg->proceduretransactionidentity = pti; + + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send PDN Disconnect Reject message " + "(pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_default_eps_bearer_context_request() ** + ** ** + ** Description: Builds Activate Default EPS Bearer Context Request ** + ** message ** + ** ** + ** The activate default EPS bearer context request message ** + ** is sent by the network to the UE to request activation of ** + ** a default EPS bearer context. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** qos: Subscribed EPS quality of service ** + ** apn: Access Point Name in used ** + ** pdn_addr: PDN IPv4 address and/or IPv6 suffix ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_default_eps_bearer_context_request(int pti, int ebi, + activate_default_eps_bearer_context_request_msg* msg, + const OctetString* apn, + int pdn_type, const OctetString* pdn_addr, + const EpsQualityOfService* qos, int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST; + msg->proceduretransactionidentity = pti; + + /* Mandatory - EPS QoS */ + msg->epsqos = *qos; + + /* Mandatory - Access Point Name */ + msg->accesspointname.accesspointnamevalue = *apn; + + /* Mandatory - PDN address */ + msg->pdnaddress.pdntypevalue = pdn_type; + msg->pdnaddress.pdnaddressinformation = *pdn_addr; + + /* Optional - ESM cause code */ + msg->presencemask = 0; + if (esm_cause != ESM_CAUSE_SUCCESS) { + msg->presencemask |= + ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT; + msg->esmcause = esm_cause; + } + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Default EPS Bearer Context " + "Request message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_activate_dedicated_eps_bearer_context_request() ** + ** ** + ** Description: Builds Activate Dedicated EPS Bearer Context Request ** + ** message ** + ** ** + ** The activate dedicated EPS bearer context request message ** + ** is sent by the network to the UE to request activation of ** + ** a dedicated EPS bearer context associated with the same ** + ** PDN address(es) and APN as an already active default EPS ** + ** bearer context. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** linked_ebi: EPS bearer identity of the default bearer ** + ** associated with the EPS dedicated bearer ** + ** to be activated ** + ** qos: EPS quality of service ** + ** tft: Traffic flow template ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_activate_dedicated_eps_bearer_context_request(int pti, int ebi, + activate_dedicated_eps_bearer_context_request_msg* msg, + int linked_ebi, const EpsQualityOfService* qos, + PacketFilters* pkfs, int n_pkfs) +{ + int i; + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST; + msg->proceduretransactionidentity = pti; + + /* Mandatory - EPS QoS */ + msg->epsqos = *qos; + + /* Mandatory - traffic flow template */ + msg->tft.tftoperationcode = TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE; + msg->tft.ebit = TRAFFIC_FLOW_TEMPLATE_PARAMETER_LIST_IS_NOT_INCLUDED; + msg->tft.numberofpacketfilters = n_pkfs; + for (i = 0; i < msg->tft.numberofpacketfilters; i++) + { + msg->tft.packetfilterlist.createtft[i] = (*pkfs)[i]; + } + + /* Optional */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Activate Dedicated EPS Bearer Context " + "Request message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: esm_send_deactivate_eps_bearer_context_request() ** + ** ** + ** Description: Builds Deactivate EPS Bearer Context Request message ** + ** ** + ** The deactivate EPS bearer context request message is sent ** + ** by the network to request deactivation of an active EPS ** + ** bearer context. ** + ** ** + ** Inputs: pti: Procedure transaction identity ** + ** ebi: EPS bearer identity ** + ** esm_cause: ESM cause code ** + ** Others: None ** + ** ** + ** Outputs: msg: The ESM message to be sent ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int esm_send_deactivate_eps_bearer_context_request(int pti, int ebi, + deactivate_eps_bearer_context_request_msg* msg, + int esm_cause) +{ + LOG_FUNC_IN; + + /* Mandatory - ESM message header */ + msg->protocoldiscriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + msg->epsbeareridentity = ebi; + msg->messagetype = DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST; + msg->proceduretransactionidentity = pti; + + /* Mandatory - ESM cause code */ + msg->esmcause = esm_cause; + /* Optional IEs */ + msg->presencemask = 0; + + LOG_TRACE(INFO, "ESM-SAP - Send Deactivate EPS Bearer Context Request " + "message (pti=%d, ebi=%d)", + msg->proceduretransactionidentity, msg->epsbeareridentity); + + LOG_FUNC_RETURN(RETURNok); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.h b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.h new file mode 100644 index 0000000000..7dd4674900 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/esm/sap/esm_send.h @@ -0,0 +1,134 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source esm_send.h + +Version 0.1 + +Date 2013/02/11 + +Product NAS stack + +Subsystem EPS Session Management + +Author Frederic Maurel + +Description Defines functions executed at the ESM Service Access + Point to send EPS Session Management messages to the + EPS Mobility Management sublayer. + +*****************************************************************************/ +#ifndef __ESM_SEND_H__ +#define __ESM_SEND_H__ + +#include "EsmStatus.h" + +#ifdef NAS_MME +#include "PdnConnectivityReject.h" +#include "PdnDisconnectReject.h" +#include "BearerResourceAllocationReject.h" +#include "BearerResourceModificationReject.h" + +#include "ActivateDefaultEpsBearerContextRequest.h" +#include "ActivateDedicatedEpsBearerContextRequest.h" +#include "ModifyEpsBearerContextRequest.h" +#include "DeactivateEpsBearerContextRequest.h" + +#include "EsmInformationRequest.h" +#endif + +#ifdef NAS_UE +#include "PdnConnectivityRequest.h" +#include "PdnDisconnectRequest.h" +#include "BearerResourceAllocationRequest.h" +#include "BearerResourceModificationRequest.h" + +#include "ActivateDefaultEpsBearerContextAccept.h" +#include "ActivateDefaultEpsBearerContextReject.h" +#include "ActivateDedicatedEpsBearerContextAccept.h" +#include "ActivateDedicatedEpsBearerContextReject.h" +#include "ModifyEpsBearerContextAccept.h" +#include "ModifyEpsBearerContextReject.h" +#include "DeactivateEpsBearerContextAccept.h" + +#include "EsmInformationResponse.h" +#endif + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * -------------------------------------------------------------------------- + * Functions executed by both the UE and the MME to send ESM messages + * -------------------------------------------------------------------------- + */ +int esm_send_status(int pti, int ebi, esm_status_msg* msg, int esm_cause); + +/* + * -------------------------------------------------------------------------- + * Functions executed by the UE to send ESM message to the network + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/* + * Transaction related messages + * ---------------------------- + */ +int esm_send_pdn_connectivity_request(int pti, int is_emergency, int pdn_type, const char* apn, pdn_connectivity_request_msg* msg); +int esm_send_pdn_disconnect_request(int pti, int ebi, pdn_disconnect_request_msg* msg); + +/* + * Messages related to EPS bearer contexts + * --------------------------------------- + */ +int esm_send_activate_default_eps_bearer_context_accept(int ebi, activate_default_eps_bearer_context_accept_msg* msg); +int esm_send_activate_default_eps_bearer_context_reject(int ebi, activate_default_eps_bearer_context_reject_msg* msg, int esm_cause); + +int esm_send_activate_dedicated_eps_bearer_context_accept(int ebi, activate_dedicated_eps_bearer_context_accept_msg* msg); +int esm_send_activate_dedicated_eps_bearer_context_reject(int ebi, activate_dedicated_eps_bearer_context_reject_msg* msg, int esm_cause); + +int esm_send_deactivate_eps_bearer_context_accept(int ebi, deactivate_eps_bearer_context_accept_msg* msg); + +#endif + +/* + * -------------------------------------------------------------------------- + * Functions executed by the MME to send ESM message to the UE + * -------------------------------------------------------------------------- + */ +#ifdef NAS_MME +/* + * Transaction related messages + * ---------------------------- + */ +int esm_send_pdn_connectivity_reject(int pti, pdn_connectivity_reject_msg* msg, int esm_cause); + +int esm_send_pdn_disconnect_reject(int pti, pdn_disconnect_reject_msg* msg, int esm_cause); + +/* + * Messages related to EPS bearer contexts + * --------------------------------------- + */ +int esm_send_activate_default_eps_bearer_context_request(int pti, int ebi, activate_default_eps_bearer_context_request_msg* msg, const OctetString* apn, int pdn_type, const OctetString* pdn_addr, const EpsQualityOfService* qos, int esm_cause); + +int esm_send_activate_dedicated_eps_bearer_context_request(int pti, int ebi, activate_dedicated_eps_bearer_context_request_msg* msg, int linked_ebi, const EpsQualityOfService* qos, PacketFilters* pkfs, int n_pkfs); + +int esm_send_deactivate_eps_bearer_context_request(int pti, int ebi, deactivate_eps_bearer_context_request_msg* msg, int esm_cause); + +#endif + +#endif /* __ESM_SEND_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.c new file mode 100644 index 0000000000..98126bce63 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AccessPointName.h" + +int decode_access_point_name(AccessPointName *accesspointname, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&accesspointname->accesspointnamevalue, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_access_point_name_xml(accesspointname, iei); +#endif + return decoded; +} +int encode_access_point_name(AccessPointName *accesspointname, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ACCESS_POINT_NAME_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_access_point_name_xml(accesspointname, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&accesspointname->accesspointnamevalue, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_access_point_name_xml(AccessPointName *accesspointname, uint8_t iei) +{ + printf("<Access Point Name>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&accesspointname->accesspointnamevalue); + printf("</Access Point Name>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.h new file mode 100644 index 0000000000..4292d23741 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AccessPointName.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ACCESS_POINT_NAME_H_ +#define ACCESS_POINT_NAME_H_ + +#define ACCESS_POINT_NAME_MINIMUM_LENGTH 3 +#define ACCESS_POINT_NAME_MAXIMUM_LENGTH 102 + +typedef struct AccessPointName_tag { + OctetString accesspointnamevalue; +} AccessPointName; + +int encode_access_point_name(AccessPointName *accesspointname, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_access_point_name(AccessPointName *accesspointname, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_access_point_name_xml(AccessPointName *accesspointname, uint8_t iei); + +#endif /* ACCESS POINT NAME_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.c new file mode 100644 index 0000000000..6d8c3e176f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AdditionalUpdateResult.h" + +int decode_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ADDITIONAL_UPDATE_RESULT_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *additionalupdateresult = *buffer & 0x3; + decoded++; +#if defined (NAS_DEBUG) + dump_additional_update_result_xml(additionalupdateresult, iei); +#endif + return decoded; +} + +int decode_u8_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *additionalupdateresult = *buffer & 0x3; + decoded++; +#if defined (NAS_DEBUG) + dump_additional_update_result_xml(additionalupdateresult, iei); +#endif + return decoded; +} + +int encode_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ADDITIONAL_UPDATE_RESULT_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_additional_update_result_xml(additionalupdateresult, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*additionalupdateresult & 0x3); + encoded++; + return encoded; +} + +uint8_t encode_u8_additional_update_result(AdditionalUpdateResult *additionalupdateresult) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_additional_update_result_xml(additionalupdateresult, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*additionalupdateresult & 0x3); + encoded++; + + return bufferReturn; +} + +void dump_additional_update_result_xml(AdditionalUpdateResult *additionalupdateresult, uint8_t iei) +{ + printf("<Additional Update Result>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Additional update result value>%u</Additional update result value>\n", *additionalupdateresult); + printf("</Additional Update Result>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h new file mode 100644 index 0000000000..d4857e34a0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ADDITIONAL_UPDATE_RESULT_H_ +#define ADDITIONAL_UPDATE_RESULT_H_ + +#define ADDITIONAL_UPDATE_RESULT_MINIMUM_LENGTH 1 +#define ADDITIONAL_UPDATE_RESULT_MAXIMUM_LENGTH 1 + +typedef uint8_t AdditionalUpdateResult; + +int encode_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_additional_update_result_xml(AdditionalUpdateResult *additionalupdateresult, uint8_t iei); + +uint8_t encode_u8_additional_update_result(AdditionalUpdateResult *additionalupdateresult); + +int decode_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_additional_update_result(AdditionalUpdateResult *additionalupdateresult, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* ADDITIONAL UPDATE RESULT_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.c new file mode 100644 index 0000000000..e94c47d631 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.c @@ -0,0 +1,34 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AdditionalUpdateType.h" + +int decode_additional_update_type(AdditionalUpdateType *additionalupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + *additionalupdatetype = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_additional_update_type_xml(additionalupdatetype, iei); +#endif + return decoded; +} + +int encode_additional_update_type(AdditionalUpdateType *additionalupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} +void dump_additional_update_type_xml(AdditionalUpdateType *additionalupdatetype, uint8_t iei) +{ + printf("<Additional Update Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <AUTV>%u</AUTV>\n", *additionalupdatetype); + printf("</Additional Update Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h new file mode 100644 index 0000000000..7720f9dea4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ADDITIONAL_UPDATE_TYPE_H_ +#define ADDITIONAL_UPDATE_TYPE_H_ + +#define ADDITIONAL_UPDATE_TYPE_MINIMUM_LENGTH 1 +#define ADDITIONAL_UPDATE_TYPE_MAXIMUM_LENGTH 1 + +typedef uint8_t AdditionalUpdateType; + +int encode_additional_update_type(AdditionalUpdateType *additionalupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_additional_update_type(AdditionalUpdateType *additionalupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_additional_update_type_xml(AdditionalUpdateType *additionalupdatetype, uint8_t iei); + +#endif /* ADDITIONAL UPDATE TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.c new file mode 100644 index 0000000000..8b7cf46319 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ApnAggregateMaximumBitRate.h" + +int decode_apn_aggregate_maximum_bit_rate(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + apnaggregatemaximumbitrate->apnambrfordownlink = *(buffer + decoded); + decoded++; + apnaggregatemaximumbitrate->apnambrforuplink = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_apn_aggregate_maximum_bit_rate_xml(apnaggregatemaximumbitrate, iei); +#endif + return decoded; +} +int encode_apn_aggregate_maximum_bit_rate(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, APN_AGGREGATE_MAXIMUM_BIT_RATE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_apn_aggregate_maximum_bit_rate_xml(apnaggregatemaximumbitrate, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = apnaggregatemaximumbitrate->apnambrfordownlink; + encoded++; + *(buffer + encoded) = apnaggregatemaximumbitrate->apnambrforuplink; + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_apn_aggregate_maximum_bit_rate_xml(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei) +{ + printf("<Apn Aggregate Maximum Bit Rate>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <APN AMBR for downlink>%u</APN AMBR for downlink>\n", apnaggregatemaximumbitrate->apnambrfordownlink); + printf(" <APN AMBR for uplink>%u</APN AMBR for uplink>\n", apnaggregatemaximumbitrate->apnambrforuplink); + printf("</Apn Aggregate Maximum Bit Rate>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h new file mode 100644 index 0000000000..00bbfc9dc6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef APN_AGGREGATE_MAXIMUM_BIT_RATE_H_ +#define APN_AGGREGATE_MAXIMUM_BIT_RATE_H_ + +#define APN_AGGREGATE_MAXIMUM_BIT_RATE_MINIMUM_LENGTH 4 +#define APN_AGGREGATE_MAXIMUM_BIT_RATE_MAXIMUM_LENGTH 8 + +typedef struct ApnAggregateMaximumBitRate_tag { + uint8_t apnambrfordownlink; + uint8_t apnambrforuplink; +} ApnAggregateMaximumBitRate; + +int encode_apn_aggregate_maximum_bit_rate(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_apn_aggregate_maximum_bit_rate(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_apn_aggregate_maximum_bit_rate_xml(ApnAggregateMaximumBitRate *apnaggregatemaximumbitrate, uint8_t iei); + +#endif /* APN AGGREGATE MAXIMUM BIT RATE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.c new file mode 100644 index 0000000000..da9bda99b6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationFailureParameter.h" + +int decode_authentication_failure_parameter(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&authenticationfailureparameter->auts, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_authentication_failure_parameter_xml(authenticationfailureparameter, iei); +#endif + return decoded; +} +int encode_authentication_failure_parameter(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_FAILURE_PARAMETER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_authentication_failure_parameter_xml(authenticationfailureparameter, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&authenticationfailureparameter->auts, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_authentication_failure_parameter_xml(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei) +{ + printf("<Authentication Failure Parameter>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&authenticationfailureparameter->auts); + printf("</Authentication Failure Parameter>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h new file mode 100644 index 0000000000..72464d88f3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef AUTHENTICATION_FAILURE_PARAMETER_H_ +#define AUTHENTICATION_FAILURE_PARAMETER_H_ + +#define AUTHENTICATION_FAILURE_PARAMETER_MINIMUM_LENGTH 16 +#define AUTHENTICATION_FAILURE_PARAMETER_MAXIMUM_LENGTH 16 + +typedef struct AuthenticationFailureParameter_tag { + OctetString auts; +} AuthenticationFailureParameter; + +int encode_authentication_failure_parameter(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_authentication_failure_parameter(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_authentication_failure_parameter_xml(AuthenticationFailureParameter *authenticationfailureparameter, uint8_t iei); + +#endif /* AUTHENTICATION FAILURE PARAMETER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.c new file mode 100644 index 0000000000..783ef63695 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationParameterAutn.h" + +int decode_authentication_parameter_autn(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&authenticationparameterautn->autn, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_authentication_parameter_autn_xml(authenticationparameterautn, iei); +#endif + return decoded; +} +int encode_authentication_parameter_autn(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + int encode_result; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_PARAMETER_AUTN_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_authentication_parameter_autn_xml(authenticationparameterautn, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&authenticationparameterautn->autn, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_authentication_parameter_autn_xml(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei) +{ + printf("<Authentication Parameter Autn>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&authenticationparameterautn->autn); + printf("</Authentication Parameter Autn>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h new file mode 100644 index 0000000000..91b9a98d6d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef AUTHENTICATION_PARAMETER_AUTN_H_ +#define AUTHENTICATION_PARAMETER_AUTN_H_ + +#define AUTHENTICATION_PARAMETER_AUTN_MINIMUM_LENGTH 17 +#define AUTHENTICATION_PARAMETER_AUTN_MAXIMUM_LENGTH 17 + +typedef struct AuthenticationParameterAutn_tag { + OctetString autn; +} AuthenticationParameterAutn; + +int encode_authentication_parameter_autn(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_authentication_parameter_autn(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_authentication_parameter_autn_xml(AuthenticationParameterAutn *authenticationparameterautn, uint8_t iei); + +#endif /* AUTHENTICATION PARAMETER AUTN_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.c new file mode 100644 index 0000000000..da1a84ffe0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.c @@ -0,0 +1,60 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationParameterRand.h" + +int decode_authentication_parameter_rand(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 16; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + if ((decode_result = decode_octet_string(&authenticationparameterrand->rand, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_authentication_parameter_rand_xml(authenticationparameterrand, iei); +#endif + return decoded; +} + +int encode_authentication_parameter_rand(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encode_result; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_PARAMETER_RAND_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_authentication_parameter_rand_xml(authenticationparameterrand, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + if ((encode_result = encode_octet_string(&authenticationparameterrand->rand, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + return encoded; +} + +void dump_authentication_parameter_rand_xml(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei) +{ + printf("<Authentication Parameter Rand>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&authenticationparameterrand->rand); + printf("</Authentication Parameter Rand>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h new file mode 100644 index 0000000000..0cb849645e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef AUTHENTICATION_PARAMETER_RAND_H_ +#define AUTHENTICATION_PARAMETER_RAND_H_ + +#define AUTHENTICATION_PARAMETER_RAND_MINIMUM_LENGTH 16 +#define AUTHENTICATION_PARAMETER_RAND_MAXIMUM_LENGTH 16 + +typedef struct AuthenticationParameterRand_tag { + OctetString rand; +} AuthenticationParameterRand; + +int encode_authentication_parameter_rand(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_authentication_parameter_rand_xml(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei); + +int decode_authentication_parameter_rand(AuthenticationParameterRand *authenticationparameterrand, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* AUTHENTICATION PARAMETER RAND_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.c b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.c new file mode 100644 index 0000000000..5b1f88bf15 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "AuthenticationResponseParameter.h" + +int decode_authentication_response_parameter(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&authenticationresponseparameter->res, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_authentication_response_parameter_xml(authenticationresponseparameter, iei); +#endif + return decoded; +} +int encode_authentication_response_parameter(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, AUTHENTICATION_RESPONSE_PARAMETER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_authentication_response_parameter_xml(authenticationresponseparameter, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&authenticationresponseparameter->res, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_authentication_response_parameter_xml(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei) +{ + printf("<Authentication Response Parameter>\n"); + dump_octet_string_xml(&authenticationresponseparameter->res); + printf("</Authentication Response Parameter>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h new file mode 100644 index 0000000000..bb3530b846 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef AUTHENTICATION_RESPONSE_PARAMETER_H_ +#define AUTHENTICATION_RESPONSE_PARAMETER_H_ + +#define AUTHENTICATION_RESPONSE_PARAMETER_MINIMUM_LENGTH 6 +#define AUTHENTICATION_RESPONSE_PARAMETER_MAXIMUM_LENGTH 18 + +typedef struct AuthenticationResponseParameter_tag { + OctetString res; +} AuthenticationResponseParameter; + +int encode_authentication_response_parameter(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_authentication_response_parameter(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_authentication_response_parameter_xml(AuthenticationResponseParameter *authenticationresponseparameter, uint8_t iei); + +#endif /* AUTHENTICATION RESPONSE PARAMETER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.c b/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.c new file mode 100644 index 0000000000..8c92f42310 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "CipheringKeySequenceNumber.h" + +int decode_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, CIPHERING_KEY_SEQUENCE_NUMBER_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *cipheringkeysequencenumber = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_ciphering_key_sequence_number_xml(cipheringkeysequencenumber, iei); +#endif + return decoded; +} + +int decode_u8_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *cipheringkeysequencenumber = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_ciphering_key_sequence_number_xml(cipheringkeysequencenumber, iei); +#endif + return decoded; +} + +int encode_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, CIPHERING_KEY_SEQUENCE_NUMBER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ciphering_key_sequence_number_xml(cipheringkeysequencenumber, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*cipheringkeysequencenumber & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_ciphering_key_sequence_number_xml(cipheringkeysequencenumber, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*cipheringkeysequencenumber & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_ciphering_key_sequence_number_xml(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei) +{ + printf("<Ciphering Key Sequence Number>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Key sequence>%u</Key sequence>\n", *cipheringkeysequencenumber); + printf("</Ciphering Key Sequence Number>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h b/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h new file mode 100644 index 0000000000..8be169f528 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef CIPHERING_KEY_SEQUENCE_NUMBER_H_ +#define CIPHERING_KEY_SEQUENCE_NUMBER_H_ + +#define CIPHERING_KEY_SEQUENCE_NUMBER_MINIMUM_LENGTH 1 +#define CIPHERING_KEY_SEQUENCE_NUMBER_MAXIMUM_LENGTH 1 + +typedef uint8_t CipheringKeySequenceNumber; + +int encode_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ciphering_key_sequence_number_xml(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei); + +uint8_t encode_u8_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber); + +int decode_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_ciphering_key_sequence_number(CipheringKeySequenceNumber *cipheringkeysequencenumber, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* CIPHERING KEY SEQUENCE NUMBER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.c b/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.c new file mode 100644 index 0000000000..23a67f9036 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "Cli.h" + +int decode_cli(Cli *cli, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&cli->clivalue, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_cli_xml(cli, iei); +#endif + return decoded; +} +int encode_cli(Cli *cli, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, CLI_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_cli_xml(cli, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&cli->clivalue, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_cli_xml(Cli *cli, uint8_t iei) +{ + printf("<Cli>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&cli->clivalue); + printf("</Cli>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.h b/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.h new file mode 100644 index 0000000000..543c000d7d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/Cli.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef CLI_H_ +#define CLI_H_ + +#define CLI_MINIMUM_LENGTH 3 +#define CLI_MAXIMUM_LENGTH 14 + +typedef struct Cli_tag { + OctetString clivalue; +} Cli; + +int encode_cli(Cli *cli, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_cli(Cli *cli, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_cli_xml(Cli *cli, uint8_t iei); + +#endif /* CLI_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.c b/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.c new file mode 100644 index 0000000000..885ca99e31 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "CsfbResponse.h" + +int decode_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, CSFB_RESPONSE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *csfbresponse = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_csfb_response_xml(csfbresponse, iei); +#endif + return decoded; +} + +int decode_u8_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *csfbresponse = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_csfb_response_xml(csfbresponse, iei); +#endif + return decoded; +} + +int encode_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, CSFB_RESPONSE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_csfb_response_xml(csfbresponse, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*csfbresponse & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_csfb_response(CsfbResponse *csfbresponse) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_csfb_response_xml(csfbresponse, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*csfbresponse & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_csfb_response_xml(CsfbResponse *csfbresponse, uint8_t iei) +{ + printf("<Csfb Response>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <CSFB response value>%u</CSFB response value>\n", *csfbresponse); + printf("</Csfb Response>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.h b/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.h new file mode 100644 index 0000000000..d39deb17aa --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/CsfbResponse.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef CSFB_RESPONSE_H_ +#define CSFB_RESPONSE_H_ + +#define CSFB_RESPONSE_MINIMUM_LENGTH 1 +#define CSFB_RESPONSE_MAXIMUM_LENGTH 1 + +typedef uint8_t CsfbResponse; + +int encode_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_csfb_response_xml(CsfbResponse *csfbresponse, uint8_t iei); + +uint8_t encode_u8_csfb_response(CsfbResponse *csfbresponse); + +int decode_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_csfb_response(CsfbResponse *csfbresponse, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* CSFB RESPONSE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.c b/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.c new file mode 100644 index 0000000000..c36b9be5eb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DaylightSavingTime.h" + +int decode_daylight_saving_time(DaylightSavingTime *daylightsavingtime, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + *daylightsavingtime = *buffer & 0x3; + decoded++; +#if defined (NAS_DEBUG) + dump_daylight_saving_time_xml(daylightsavingtime, iei); +#endif + return decoded; +} +int encode_daylight_saving_time(DaylightSavingTime *daylightsavingtime, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DAYLIGHT_SAVING_TIME_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_daylight_saving_time_xml(daylightsavingtime, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + (*daylightsavingtime & 0x3); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_daylight_saving_time_xml(DaylightSavingTime *daylightsavingtime, uint8_t iei) +{ + printf("<Daylight Saving Time>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Value>%u</Value>\n", *daylightsavingtime); + printf("</Daylight Saving Time>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h b/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h new file mode 100644 index 0000000000..df65d9d66c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef DAYLIGHT_SAVING_TIME_H_ +#define DAYLIGHT_SAVING_TIME_H_ + +#define DAYLIGHT_SAVING_TIME_MINIMUM_LENGTH 3 +#define DAYLIGHT_SAVING_TIME_MAXIMUM_LENGTH 3 + +typedef uint8_t DaylightSavingTime; + +int encode_daylight_saving_time(DaylightSavingTime *daylightsavingtime, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_daylight_saving_time(DaylightSavingTime *daylightsavingtime, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_daylight_saving_time_xml(DaylightSavingTime *daylightsavingtime, uint8_t iei); + +#endif /* DAYLIGHT SAVING TIME_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.c new file mode 100644 index 0000000000..674d4697d6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DetachType.h" + +int decode_detach_type(DetachType *detachtype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, DETACH_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + detachtype->switchoff = (*(buffer + decoded) >> 3) & 0x1; + detachtype->typeofdetach = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_detach_type_xml(detachtype, iei); +#endif + return decoded; +} + +int decode_u8_detach_type(DetachType *detachtype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + detachtype->switchoff = (*(buffer + decoded) >> 3) & 0x1; + detachtype->typeofdetach = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_detach_type_xml(detachtype, iei); +#endif + return decoded; +} + +int encode_detach_type(DetachType *detachtype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DETACH_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_detach_type_xml(detachtype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((detachtype->switchoff & 0x1) << 3) | + (detachtype->typeofdetach & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_detach_type(DetachType *detachtype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_detach_type_xml(detachtype, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((detachtype->switchoff & 0x1) << 3) | + (detachtype->typeofdetach & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_detach_type_xml(DetachType *detachtype, uint8_t iei) +{ + printf("<Detach Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Switch off>%u</Switch off>\n", detachtype->switchoff); + printf(" <Type of detach>%u</Type of detach>\n", detachtype->typeofdetach); + printf("</Detach Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.h new file mode 100644 index 0000000000..af6506fc8c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DetachType.h @@ -0,0 +1,36 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef DETACH_TYPE_H_ +#define DETACH_TYPE_H_ + +#define DETACH_TYPE_MINIMUM_LENGTH 1 +#define DETACH_TYPE_MAXIMUM_LENGTH 1 + +typedef struct DetachType_tag { +#define DETACH_TYPE_NORMAL_DETACH 0 +#define DETACH_TYPE_SWITCH_OFF 1 + uint8_t switchoff:1; +#define DETACH_TYPE_EPS 0b001 +#define DETACH_TYPE_IMSI 0b010 +#define DETACH_TYPE_EPS_IMSI 0b011 +#define DETACH_TYPE_RESERVED_1 0b110 +#define DETACH_TYPE_RESERVED_2 0b111 + uint8_t typeofdetach:3; +} DetachType; + +int encode_detach_type(DetachType *detachtype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_detach_type_xml(DetachType *detachtype, uint8_t iei); + +uint8_t encode_u8_detach_type(DetachType *detachtype); + +int decode_detach_type(DetachType *detachtype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_detach_type(DetachType *detachtype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* DETACH TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.c b/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.c new file mode 100644 index 0000000000..9e1a397bc6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.c @@ -0,0 +1,64 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "DrxParameter.h" + +int decode_drx_parameter(DrxParameter *drxparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + drxparameter->splitpgcyclecode = *(buffer + decoded); + decoded++; + drxparameter->cnspecificdrxcyclelengthcoefficientanddrxvaluefors1mode = (*(buffer + decoded) >> 4) & 0xf; + drxparameter->splitonccch = (*(buffer + decoded) >> 3) & 0x1; + drxparameter->nondrxtimer = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_drx_parameter_xml(drxparameter, iei); +#endif + return decoded; +} + +int encode_drx_parameter(DrxParameter *drxparameter, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, DRX_PARAMETER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_drx_parameter_xml(drxparameter, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = drxparameter->splitpgcyclecode; + encoded++; + *(buffer + encoded) = 0x00 | ((drxparameter->cnspecificdrxcyclelengthcoefficientanddrxvaluefors1mode & 0xf) << 4) | + ((drxparameter->splitonccch & 0x1) << 3) | + (drxparameter->nondrxtimer & 0x7); + encoded++; + return encoded; +} + +void dump_drx_parameter_xml(DrxParameter *drxparameter, uint8_t iei) +{ + printf("<Drx Parameter>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <SPLIT PG CYCLE CODE>%u</SPLIT PG CYCLE CODE>\n", drxparameter->splitpgcyclecode); + printf(" <CN specific DRX cycle length coefficient and DRX value for S1 mode>%u</CN specific DRX cycle length coefficient and DRX value for S1 mode>\n", drxparameter->cnspecificdrxcyclelengthcoefficientanddrxvaluefors1mode); + printf(" <SPLIT on CCCH>%u</SPLIT on CCCH>\n", drxparameter->splitonccch); + printf(" <non DRX timer>%u</non DRX timer>\n", drxparameter->nondrxtimer); + printf("</Drx Parameter>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.h b/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.h new file mode 100644 index 0000000000..855cd760fe --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/DrxParameter.h @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef DRX_PARAMETER_H_ +#define DRX_PARAMETER_H_ + +#define DRX_PARAMETER_MINIMUM_LENGTH 3 +#define DRX_PARAMETER_MAXIMUM_LENGTH 3 + +typedef struct DrxParameter_tag { + uint8_t splitpgcyclecode; + uint8_t cnspecificdrxcyclelengthcoefficientanddrxvaluefors1mode:4; + uint8_t splitonccch:1; + uint8_t nondrxtimer:3; +} DrxParameter; + +int encode_drx_parameter(DrxParameter *drxparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_drx_parameter_xml(DrxParameter *drxparameter, uint8_t iei); + +int decode_drx_parameter(DrxParameter *drxparameter, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* DRX PARAMETER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.c new file mode 100644 index 0000000000..057130d058 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EmergencyNumberList.h" + +int decode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + emergencynumberlist->lengthofemergency = *(buffer + decoded); + decoded++; + emergencynumberlist->emergencyservicecategoryvalue = *(buffer + decoded) & 0x1f; + decoded++; +#if defined (NAS_DEBUG) + dump_emergency_number_list_xml(emergencynumberlist, iei); +#endif + return decoded; +} +int encode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EMERGENCY_NUMBER_LIST_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_emergency_number_list_xml(emergencynumberlist, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = emergencynumberlist->lengthofemergency; + encoded++; + *(buffer + encoded) = 0x00 | + (emergencynumberlist->emergencyservicecategoryvalue & 0x1f); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_emergency_number_list_xml(EmergencyNumberList *emergencynumberlist, uint8_t iei) +{ + printf("<Emergency Number List>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Length of emergency>%u</Length of emergency>\n", emergencynumberlist->lengthofemergency); + printf(" <Emergency service category value>%u</Emergency service category value>\n", emergencynumberlist->emergencyservicecategoryvalue); + printf("</Emergency Number List>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h new file mode 100644 index 0000000000..1f7c5d9780 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EMERGENCY_NUMBER_LIST_H_ +#define EMERGENCY_NUMBER_LIST_H_ + +#define EMERGENCY_NUMBER_LIST_MINIMUM_LENGTH 5 +#define EMERGENCY_NUMBER_LIST_MAXIMUM_LENGTH 50 + +typedef struct EmergencyNumberList_tag { + uint8_t lengthofemergency; + uint8_t emergencyservicecategoryvalue:5; +} EmergencyNumberList; + +int encode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_emergency_number_list(EmergencyNumberList *emergencynumberlist, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_emergency_number_list_xml(EmergencyNumberList *emergencynumberlist, uint8_t iei); + +#endif /* EMERGENCY NUMBER LIST_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.c new file mode 100644 index 0000000000..1dc11bb362 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EmmCause.h" + +int decode_emm_cause(EmmCause *emmcause, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *emmcause = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_emm_cause_xml(emmcause, iei); +#endif + return decoded; +} + +int encode_emm_cause(EmmCause *emmcause, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EMM_CAUSE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_emm_cause_xml(emmcause, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = *emmcause; + encoded++; + return encoded; +} + +void dump_emm_cause_xml(EmmCause *emmcause, uint8_t iei) +{ + printf("<Emm Cause>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Cause value>%u</Cause value>\n", *emmcause); + printf("</Emm Cause>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.h new file mode 100644 index 0000000000..93b4bfff1d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EmmCause.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EMM_CAUSE_H_ +#define EMM_CAUSE_H_ + +#define EMM_CAUSE_MINIMUM_LENGTH 1 +#define EMM_CAUSE_MAXIMUM_LENGTH 1 + +typedef uint8_t EmmCause; + +int encode_emm_cause(EmmCause *emmcause, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_emm_cause_xml(EmmCause *emmcause, uint8_t iei); + +int decode_emm_cause(EmmCause *emmcause, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* EMM CAUSE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.c new file mode 100644 index 0000000000..578957e8d8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsAttachResult.h" + +int decode_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EPS_ATTACH_RESULT_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *epsattachresult = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_attach_result_xml(epsattachresult, iei); +#endif + return decoded; +} + +int decode_u8_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *epsattachresult = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_attach_result_xml(epsattachresult, iei); +#endif + return decoded; +} + +int encode_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_ATTACH_RESULT_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_attach_result_xml(epsattachresult, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsattachresult & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_eps_attach_result(EpsAttachResult *epsattachresult) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_eps_attach_result_xml(epsattachresult, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsattachresult & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_eps_attach_result_xml(EpsAttachResult *epsattachresult, uint8_t iei) +{ + printf("<Eps Attach Result>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EPS attach result value>%u</EPS attach result value>\n", *epsattachresult); + printf("</Eps Attach Result>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h new file mode 100644 index 0000000000..918795496f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_ATTACH_RESULT_H_ +#define EPS_ATTACH_RESULT_H_ + +#define EPS_ATTACH_RESULT_MINIMUM_LENGTH 1 +#define EPS_ATTACH_RESULT_MAXIMUM_LENGTH 1 + +#define EPS_ATTACH_RESULT_EPS 0b001 +#define EPS_ATTACH_RESULT_EPS_IMSI 0b010 +typedef uint8_t EpsAttachResult; + +int encode_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_attach_result_xml(EpsAttachResult *epsattachresult, uint8_t iei); + +uint8_t encode_u8_eps_attach_result(EpsAttachResult *epsattachresult); + +int decode_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_eps_attach_result(EpsAttachResult *epsattachresult, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* EPS ATTACH RESULT_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.c new file mode 100644 index 0000000000..c391e85c16 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsAttachType.h" + +int decode_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EPS_ATTACH_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *epsattachtype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_attach_type_xml(epsattachtype, iei); +#endif + return decoded; +} + +int decode_u8_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *epsattachtype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_attach_type_xml(epsattachtype, iei); +#endif + return decoded; +} + +int encode_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_ATTACH_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_attach_type_xml(epsattachtype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsattachtype & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_eps_attach_type(EpsAttachType *epsattachtype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_eps_attach_type_xml(epsattachtype, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsattachtype & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_eps_attach_type_xml(EpsAttachType *epsattachtype, uint8_t iei) +{ + printf("<Eps Attach Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EPS attach type value>%u</EPS attach type value>\n", *epsattachtype); + printf("</Eps Attach Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.h new file mode 100644 index 0000000000..d06d329a02 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsAttachType.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_ATTACH_TYPE_H_ +#define EPS_ATTACH_TYPE_H_ + +#define EPS_ATTACH_TYPE_MINIMUM_LENGTH 1 +#define EPS_ATTACH_TYPE_MAXIMUM_LENGTH 1 + +#define EPS_ATTACH_TYPE_EPS 0b0001 +#define EPS_ATTACH_TYPE_IMSI 0b0010 +#define EPS_ATTACH_TYPE_EMERGENCY 0b0110 +#define EPS_ATTACH_TYPE_RESERVED 0b0111 +typedef uint8_t EpsAttachType; + +int encode_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_attach_type_xml(EpsAttachType *epsattachtype, uint8_t iei); + +uint8_t encode_u8_eps_attach_type(EpsAttachType *epsattachtype); + +int decode_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_eps_attach_type(EpsAttachType *epsattachtype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* EPS ATTACH TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.c new file mode 100644 index 0000000000..5665d36468 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.c @@ -0,0 +1,56 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsBearerContextStatus.h" + +int decode_eps_bearer_context_status(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + //IES_DECODE_U16(*epsbearercontextstatus, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, *epsbearercontextstatus); +#if defined (NAS_DEBUG) + dump_eps_bearer_context_status_xml(epsbearercontextstatus, iei); +#endif + return decoded; +} +int encode_eps_bearer_context_status(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_BEARER_CONTEXT_STATUS_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_bearer_context_status_xml(epsbearercontextstatus, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + IES_ENCODE_U16(buffer, encoded, *epsbearercontextstatus); + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_eps_bearer_context_status_xml(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei) +{ + printf("<Eps Bearer Context Status>\n"); + printf(" <EBI>%u</EBI>\n", *epsbearercontextstatus); + printf("</Eps Bearer Context Status>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h new file mode 100644 index 0000000000..7116eeff5d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_BEARER_CONTEXT_STATUS_H_ +#define EPS_BEARER_CONTEXT_STATUS_H_ + +#define EPS_BEARER_CONTEXT_STATUS_MINIMUM_LENGTH 4 +#define EPS_BEARER_CONTEXT_STATUS_MAXIMUM_LENGTH 4 + +typedef uint16_t EpsBearerContextStatus; + +int encode_eps_bearer_context_status(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_eps_bearer_context_status(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_bearer_context_status_xml(EpsBearerContextStatus *epsbearercontextstatus, uint8_t iei); + +#endif /* EPS BEARER CONTEXT STATUS_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.c new file mode 100644 index 0000000000..b85c62db93 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsBearerIdentity.h" + +int decode_eps_bearer_identity(EpsBearerIdentity *epsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_eps_bearer_identity(EpsBearerIdentity *epsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h new file mode 100644 index 0000000000..47a1466f20 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_BEARER_IDENTITY_H_ +#define EPS_BEARER_IDENTITY_H_ + +#define EPS_BEARER_IDENTITY_MINIMUM_LENGTH 1 +#define EPS_BEARER_IDENTITY_MAXIMUM_LENGTH 1 + +#define EPS_BEARER_IDENTITY_UNASSIGNED 0 +#define EPS_BEARER_IDENTITY_FIRST 5 +#define EPS_BEARER_IDENTITY_LAST 15 +typedef uint8_t EpsBearerIdentity; + +int encode_eps_bearer_identity(EpsBearerIdentity *epsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_bearer_identity_xml(EpsBearerIdentity *epsbeareridentity, uint8_t iei); + +int decode_eps_bearer_identity(EpsBearerIdentity *epsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* EPS BEARER IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.c new file mode 100644 index 0000000000..b06cc0c390 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.c @@ -0,0 +1,346 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsMobileIdentity.h" + +static int decode_guti_eps_mobile_identity(GutiEpsMobileIdentity_t *guti, uint8_t *buffer); +static int decode_imsi_eps_mobile_identity(ImsiEpsMobileIdentity_t *imsi, uint8_t *buffer); +static int decode_imei_eps_mobile_identity(ImeiEpsMobileIdentity_t *imei, uint8_t *buffer); + +static int encode_guti_eps_mobile_identity(GutiEpsMobileIdentity_t *guti, uint8_t *buffer); +static int encode_imsi_eps_mobile_identity(ImsiEpsMobileIdentity_t *imsi, uint8_t *buffer); +static int encode_imei_eps_mobile_identity(ImeiEpsMobileIdentity_t *imei, uint8_t *buffer); + +int decode_eps_mobile_identity(EpsMobileIdentity *epsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded_rc = TLV_DECODE_VALUE_DOESNT_MATCH; + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + + uint8_t typeofidentity = *(buffer + decoded) & 0x7; + if (typeofidentity == EPS_MOBILE_IDENTITY_IMSI) { + decoded_rc = decode_imsi_eps_mobile_identity(&epsmobileidentity->imsi, + buffer + decoded); + } else if (typeofidentity == EPS_MOBILE_IDENTITY_GUTI) { + decoded_rc = decode_guti_eps_mobile_identity(&epsmobileidentity->guti, + buffer + decoded); + } else if (typeofidentity == EPS_MOBILE_IDENTITY_IMEI) { + decoded_rc = decode_imei_eps_mobile_identity(&epsmobileidentity->imei, + buffer + decoded); + } + + if (decoded_rc < 0) { + return decoded_rc; + } +#if defined (NAS_DEBUG) + dump_eps_mobile_identity_xml(epsmobileidentity, iei); +#endif + return (decoded + decoded_rc); +} + +int encode_eps_mobile_identity(EpsMobileIdentity *epsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + int encoded_rc = TLV_ENCODE_VALUE_DOESNT_MATCH; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_MOBILE_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_mobile_identity_xml(epsmobileidentity, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + + if (epsmobileidentity->imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) + { + encoded_rc = encode_imsi_eps_mobile_identity(&epsmobileidentity->imsi, + buffer + encoded); + } + else if (epsmobileidentity->guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) + { + encoded_rc = encode_guti_eps_mobile_identity(&epsmobileidentity->guti, + buffer + encoded); + } + else if (epsmobileidentity->imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) + { + encoded_rc = encode_imei_eps_mobile_identity(&epsmobileidentity->imei, + buffer + encoded); + } + + if (encoded_rc < 0) { + return encoded_rc; + } + *lenPtr = encoded + encoded_rc - 1 - ((iei > 0) ? 1 : 0); + return (encoded + encoded_rc); +} + +void dump_eps_mobile_identity_xml(EpsMobileIdentity *epsmobileidentity, uint8_t iei) +{ + printf("<Eps Mobile Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + + if (epsmobileidentity->imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) { + ImsiEpsMobileIdentity_t* imsi = &epsmobileidentity->imsi; + printf(" <odd even>%u</odd even>\n", imsi->oddeven); + printf(" <Type of identity>IMSI</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", imsi->digit1); + printf(" <digit2>%u</digit2>\n", imsi->digit2); + printf(" <digit3>%u</digit3>\n", imsi->digit3); + printf(" <digit4>%u</digit4>\n", imsi->digit4); + printf(" <digit5>%u</digit5>\n", imsi->digit5); + printf(" <digit6>%u</digit6>\n", imsi->digit6); + printf(" <digit7>%u</digit7>\n", imsi->digit7); + printf(" <digit8>%u</digit8>\n", imsi->digit8); + printf(" <digit9>%u</digit9>\n", imsi->digit9); + printf(" <digit10>%u</digit10>\n", imsi->digit10); + printf(" <digit11>%u</digit11>\n", imsi->digit11); + printf(" <digit12>%u</digit12>\n", imsi->digit12); + printf(" <digit13>%u</digit13>\n", imsi->digit13); + printf(" <digit14>%u</digit14>\n", imsi->digit14); + printf(" <digit15>%u</digit15>\n", imsi->digit15); + } + else if (epsmobileidentity->guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) + { + GutiEpsMobileIdentity_t* guti = &epsmobileidentity->guti; + printf(" <odd even>%u</odd even>\n", guti->oddeven); + printf(" <Type of identity>GUTI</Type of identity>\n"); + printf(" <MCC digit 1>%u</MCC digit 1>\n", guti->mccdigit1); + printf(" <MCC digit 2>%u</MCC digit 2>\n", guti->mccdigit2); + printf(" <MCC digit 3>%u</MCC digit 3>\n", guti->mccdigit3); + printf(" <MNC digit 1>%u</MNC digit 1>\n", guti->mncdigit1); + printf(" <MNC digit 2>%u</MNC digit 2>\n", guti->mncdigit2); + printf(" <MNC digit 3>%u</MNC digit 3>\n", guti->mncdigit3); + printf(" <MME group id>%u</MME group id>\n", guti->mmegroupid); + printf(" <MME code>%u</MME code>\n", guti->mmecode); + printf(" <M TMSI>%u</M TMSI>\n", guti->mtmsi); + } + else if (epsmobileidentity->imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) + { + ImeiEpsMobileIdentity_t* imei = &epsmobileidentity->imei; + printf(" <odd even>%u</odd even>\n", imei->oddeven); + printf(" <Type of identity>IMEI</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", imei->digit1); + printf(" <digit2>%u</digit2>\n", imei->digit2); + printf(" <digit3>%u</digit3>\n", imei->digit3); + printf(" <digit4>%u</digit4>\n", imei->digit4); + printf(" <digit5>%u</digit5>\n", imei->digit5); + printf(" <digit6>%u</digit6>\n", imei->digit6); + printf(" <digit7>%u</digit7>\n", imei->digit7); + printf(" <digit8>%u</digit8>\n", imei->digit8); + printf(" <digit9>%u</digit9>\n", imei->digit9); + printf(" <digit10>%u</digit10>\n", imei->digit10); + printf(" <digit11>%u</digit11>\n", imei->digit11); + printf(" <digit12>%u</digit12>\n", imei->digit12); + printf(" <digit13>%u</digit13>\n", imei->digit13); + printf(" <digit14>%u</digit14>\n", imei->digit14); + printf(" <digit15>%u</digit15>\n", imei->digit15); + } + else { + printf(" Wrong type of EPS mobile identity (%u)\n", epsmobileidentity->guti.typeofidentity); + } + printf("</Eps Mobile Identity>\n"); +} + +static int decode_guti_eps_mobile_identity(GutiEpsMobileIdentity_t *guti, uint8_t *buffer) +{ + int decoded = 0; + guti->spare = (*(buffer + decoded) >> 4) & 0xf; + /* + * For the GUTI, bits 5 to 8 of octet 3 are coded as "1111" + */ + if (guti->spare != 0xf) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + guti->oddeven = (*(buffer + decoded) >> 3) & 0x1; + guti->typeofidentity = *(buffer + decoded) & 0x7; + if (guti->typeofidentity != EPS_MOBILE_IDENTITY_GUTI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + guti->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + guti->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + guti->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + guti->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + guti->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + guti->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; + //IES_DECODE_U16(guti->mmegroupid, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, guti->mmegroupid); + guti->mmecode = *(buffer + decoded); + decoded++; + //IES_DECODE_U32(guti->mtmsi, *(buffer + decoded)); + IES_DECODE_U32(buffer, decoded, guti->mtmsi); + return decoded; +} + +static int decode_imsi_eps_mobile_identity(ImsiEpsMobileIdentity_t *imsi, uint8_t *buffer) +{ + int decoded = 0; + imsi->typeofidentity = *(buffer + decoded) & 0x7; + if (imsi->typeofidentity != EPS_MOBILE_IDENTITY_IMSI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + imsi->oddeven = (*(buffer + decoded) >> 3) & 0x1; + imsi->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit2 = *(buffer + decoded) & 0xf; + imsi->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit4 = *(buffer + decoded) & 0xf; + imsi->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit6 = *(buffer + decoded) & 0xf; + imsi->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit8 = *(buffer + decoded) & 0xf; + imsi->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit10 = *(buffer + decoded) & 0xf; + imsi->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit12 = *(buffer + decoded) & 0xf; + imsi->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit14 = *(buffer + decoded) & 0xf; + imsi->digit15 = (*(buffer + decoded) >> 4) & 0xf; + /* + * IMSI is coded using BCD coding. If the number of identity digits is + * even then bits 5 to 8 of the last octet shall be filled with an end + * mark coded as "1111". + */ + if ((imsi->oddeven == EPS_MOBILE_IDENTITY_EVEN) && (imsi->digit15 != 0x0f)) + { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + return decoded; +} + +static int decode_imei_eps_mobile_identity(ImeiEpsMobileIdentity_t *imei, uint8_t *buffer) +{ + int decoded = 0; + imei->typeofidentity = *(buffer + decoded) & 0x7; + if (imei->typeofidentity != EPS_MOBILE_IDENTITY_IMEI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + imei->oddeven = (*(buffer + decoded) >> 3) & 0x1; + imei->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit2 = *(buffer + decoded) & 0xf; + imei->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit4 = *(buffer + decoded) & 0xf; + imei->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit6 = *(buffer + decoded) & 0xf; + imei->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit8 = *(buffer + decoded) & 0xf; + imei->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit10 = *(buffer + decoded) & 0xf; + imei->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit12 = *(buffer + decoded) & 0xf; + imei->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit14 = *(buffer + decoded) & 0xf; + imei->digit15 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + return decoded; +} + +static int encode_guti_eps_mobile_identity(GutiEpsMobileIdentity_t *guti, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0xf0 | ((guti->oddeven & 0x1) << 3) | + (guti->typeofidentity & 0x7); + encoded++; + *(buffer + encoded) = 0x00 | ((guti->mccdigit2 & 0xf) << 4) | + (guti->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((guti->mncdigit3 & 0xf) << 4) | + (guti->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((guti->mncdigit2 & 0xf) << 4) | + (guti->mncdigit1 & 0xf); + encoded++; + IES_ENCODE_U16(buffer, encoded, guti->mmegroupid); + *(buffer + encoded) = guti->mmecode; + encoded++; + IES_ENCODE_U32(buffer, encoded, guti->mtmsi); + return encoded; +} + +static int encode_imsi_eps_mobile_identity(ImsiEpsMobileIdentity_t *imsi, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | (imsi->digit1 << 4) | (imsi->oddeven << 3) | + (imsi->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit3 << 4) | imsi->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit5 << 4) | imsi->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit7 << 4) | imsi->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit9 << 4) | imsi->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit11 << 4) | imsi->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit13 << 4) | imsi->digit12; + encoded++; + if (imsi->oddeven != EPS_MOBILE_IDENTITY_EVEN) { + *(buffer + encoded) = 0x00 | (imsi->digit15 << 4) | imsi->digit14; + } + else { + *(buffer + encoded) = 0xf0 | imsi->digit14; + } + encoded++; + return encoded; +} + +static int encode_imei_eps_mobile_identity(ImeiEpsMobileIdentity_t *imei, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | (imei->digit1 << 4) | (imei->oddeven << 3) | + (imei->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit3 << 4) | imei->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit5 << 4) | imei->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit7 << 4) | imei->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit9 << 4) | imei->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit11 << 4) | imei->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit13 << 4) | imei->digit12; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit15 << 4) | imei->digit14; + encoded++; + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h new file mode 100644 index 0000000000..64040a9177 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h @@ -0,0 +1,68 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_MOBILE_IDENTITY_H_ +#define EPS_MOBILE_IDENTITY_H_ + +#define EPS_MOBILE_IDENTITY_MINIMUM_LENGTH 3 +#define EPS_MOBILE_IDENTITY_MAXIMUM_LENGTH 13 + +typedef struct { + uint8_t spare:4; +#define EPS_MOBILE_IDENTITY_EVEN 0 +#define EPS_MOBILE_IDENTITY_ODD 1 + uint8_t oddeven:1; + uint8_t typeofidentity:3; + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; + uint16_t mmegroupid; + uint8_t mmecode; + uint32_t mtmsi; +} GutiEpsMobileIdentity_t; + +typedef struct { + uint8_t digit1:4; + uint8_t oddeven:1; + uint8_t typeofidentity:3; + uint8_t digit2:4; + uint8_t digit3:4; + uint8_t digit4:4; + uint8_t digit5:4; + uint8_t digit6:4; + uint8_t digit7:4; + uint8_t digit8:4; + uint8_t digit9:4; + uint8_t digit10:4; + uint8_t digit11:4; + uint8_t digit12:4; + uint8_t digit13:4; + uint8_t digit14:4; + uint8_t digit15:4; +} ImsiEpsMobileIdentity_t; + +typedef ImsiEpsMobileIdentity_t ImeiEpsMobileIdentity_t; + +typedef union EpsMobileIdentity_tag { +#define EPS_MOBILE_IDENTITY_IMSI 0b001 +#define EPS_MOBILE_IDENTITY_GUTI 0b110 +#define EPS_MOBILE_IDENTITY_IMEI 0b011 + ImsiEpsMobileIdentity_t imsi; + GutiEpsMobileIdentity_t guti; + ImeiEpsMobileIdentity_t imei; +} EpsMobileIdentity; + +int encode_eps_mobile_identity(EpsMobileIdentity *epsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_eps_mobile_identity(EpsMobileIdentity *epsmobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_mobile_identity_xml(EpsMobileIdentity *epsmobileidentity, uint8_t iei); + +#endif /* EPS MOBILE IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.c new file mode 100644 index 0000000000..765b4342aa --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsNetworkFeatureSupport.h" + +int decode_eps_network_feature_support(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + *epsnetworkfeaturesupport = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_network_feature_support_xml(epsnetworkfeaturesupport, iei); +#endif + return decoded; +} +int encode_eps_network_feature_support(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_NETWORK_FEATURE_SUPPORT_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_network_feature_support_xml(epsnetworkfeaturesupport, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + (*epsnetworkfeaturesupport & 0x1); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_eps_network_feature_support_xml(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei) +{ + printf("<Eps Network Feature Support>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <IMS VoPS>%u</IMS VoPS>\n", *epsnetworkfeaturesupport); + printf("</Eps Network Feature Support>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h new file mode 100644 index 0000000000..108de972ae --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_NETWORK_FEATURE_SUPPORT_H_ +#define EPS_NETWORK_FEATURE_SUPPORT_H_ + +#define EPS_NETWORK_FEATURE_SUPPORT_MINIMUM_LENGTH 3 +#define EPS_NETWORK_FEATURE_SUPPORT_MAXIMUM_LENGTH 3 + +typedef uint8_t EpsNetworkFeatureSupport; + +int encode_eps_network_feature_support(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_eps_network_feature_support(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_network_feature_support_xml(EpsNetworkFeatureSupport *epsnetworkfeaturesupport, uint8_t iei); + +#endif /* EPS NETWORK FEATURE SUPPORT_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.c new file mode 100644 index 0000000000..fb7b3923c6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.c @@ -0,0 +1,169 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsQualityOfService.h" + +static int decode_eps_qos_bit_rates(EpsQoSBitRates* epsqosbitrates, const uint8_t *buffer) +{ + int decoded = 0; + epsqosbitrates->maxBitRateForUL = *(buffer + decoded); + decoded++; + epsqosbitrates->maxBitRateForDL = *(buffer + decoded); + decoded++; + epsqosbitrates->guarBitRateForUL = *(buffer + decoded); + decoded++; + epsqosbitrates->guarBitRateForDL = *(buffer + decoded); + decoded++; + return decoded; +} + +int decode_eps_quality_of_service(EpsQualityOfService *epsqualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + epsqualityofservice->qci = *(buffer + decoded); + decoded++; + if ( ielen > 2 + (iei > 0) ? 1 : 0 ) { + /* bitRates is present */ + epsqualityofservice->bitRatesPresent = 1; + decoded += decode_eps_qos_bit_rates(&epsqualityofservice->bitRates, + buffer + decoded); + } else { + /* bitRates is not present */ + epsqualityofservice->bitRatesPresent = 0; + } + if ( ielen > 6 + (iei > 0) ? 1 : 0 ) { + /* bitRatesExt is present */ + epsqualityofservice->bitRatesExtPresent = 1; + decoded += decode_eps_qos_bit_rates(&epsqualityofservice->bitRatesExt, + buffer + decoded); + } else { + /* bitRatesExt is not present */ + epsqualityofservice->bitRatesExtPresent = 0; + } + +#if defined (NAS_DEBUG) + dump_eps_quality_of_service_xml(epsqualityofservice, iei); +#endif + return decoded; +} + +static int encode_eps_qos_bit_rates(const EpsQoSBitRates* epsqosbitrates, uint8_t *buffer) +{ + int encoded = 0; + *(buffer + encoded) = epsqosbitrates->maxBitRateForUL; + encoded ++; + *(buffer + encoded) = epsqosbitrates->maxBitRateForDL; + encoded ++; + *(buffer + encoded) = epsqosbitrates->guarBitRateForUL; + encoded ++; + *(buffer + encoded) = epsqosbitrates->guarBitRateForDL; + encoded ++; + return encoded; +} + +int encode_eps_quality_of_service(EpsQualityOfService *epsqualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_QUALITY_OF_SERVICE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_quality_of_service_xml(epsqualityofservice, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = epsqualityofservice->qci; + encoded++; + if (epsqualityofservice->bitRatesPresent) { + encoded += encode_eps_qos_bit_rates(&epsqualityofservice->bitRates, + buffer + encoded); + } + if (epsqualityofservice->bitRatesExtPresent) { + encoded += encode_eps_qos_bit_rates(&epsqualityofservice->bitRatesExt, + buffer + encoded); + } + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_eps_quality_of_service_xml(EpsQualityOfService *epsqualityofservice, uint8_t iei) +{ + printf("<Eps Quality Of Service>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <QCI>%u</QCI>\n", epsqualityofservice->qci); + if (epsqualityofservice->bitRatesPresent) { + printf(" <bitRates>\n"); + printf(" <maxBitRateForUL>%u</maxBitRateForUL>\n", + epsqualityofservice->bitRates.maxBitRateForUL); + printf(" <maxBitRateForDL>%u</maxBitRateForDL>\n", + epsqualityofservice->bitRates.maxBitRateForDL); + printf(" <guarBitRateForUL>%u</guarBitRateForUL>\n", + epsqualityofservice->bitRates.guarBitRateForUL); + printf(" <guarBitRateForDL>%u</guarBitRateForDL>\n", + epsqualityofservice->bitRates.guarBitRateForDL); + printf(" </bitRates>\n"); + } + if (epsqualityofservice->bitRatesExtPresent) { + printf(" <bitRatesExt>\n"); + printf(" <maxBitRateForUL>%u</maxBitRateForUL>\n", + epsqualityofservice->bitRatesExt.maxBitRateForUL); + printf(" <maxBitRateForDL>%u</maxBitRateForDL>\n", + epsqualityofservice->bitRatesExt.maxBitRateForDL); + printf(" <guarBitRateForUL>%u</guarBitRateForUL>\n", + epsqualityofservice->bitRatesExt.guarBitRateForUL); + printf(" <guarBitRateForDL>%u</guarBitRateForDL>\n", + epsqualityofservice->bitRatesExt.guarBitRateForDL); + printf(" </bitRatesExt>\n"); + } + printf("</Eps Quality Of Service>\n"); +} + +#define EPS_QOS_BIT_RATE_MAX 262144 // 256 Mbps +int eps_qos_bit_rate_value(uint8_t br) +{ + if (br < 0b00000001) { + return (EPS_QOS_BIT_RATE_MAX); + } else if ( (br > 0b00000000) && (br < 0b01000000) ) { + return (br); + } else if ( (br > 0b00111111) && (br < 0b10000000) ) { + return (64 + (br - 0b01000000) * 8); + } else if ( (br > 0b01111111) && (br < 0b11111111) ) { + return (576 + (br - 0b10000000) * 64); + } else { + return (0); + } +} + +int eps_qos_bit_rate_ext_value(uint8_t br) +{ + if ( (br > 0b00000000) && (br < 0b01001011) ) { + return (8600 + br * 100); + } else if ( (br > 0b01001010) && (br < 0b10111011) ) { + return (16384 + (br - 0b01001010) * 1024); + } else if ( (br > 0b10111010) && (br < 0b11111011) ) { + return (131072 + (br - 0b10111010) * 2048); + } else { + return (-1); + } +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h new file mode 100644 index 0000000000..603fba9554 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h @@ -0,0 +1,38 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#ifndef EPS_QUALITY_OF_SERVICE_H_ +#define EPS_QUALITY_OF_SERVICE_H_ + +#define EPS_QUALITY_OF_SERVICE_MINIMUM_LENGTH 2 +#define EPS_QUALITY_OF_SERVICE_MAXIMUM_LENGTH 10 + +typedef struct { + uint8_t maxBitRateForUL; + uint8_t maxBitRateForDL; + uint8_t guarBitRateForUL; + uint8_t guarBitRateForDL; +} EpsQoSBitRates; + +typedef struct { + uint8_t bitRatesPresent:1; + uint8_t bitRatesExtPresent:1; + uint8_t qci; + EpsQoSBitRates bitRates; + EpsQoSBitRates bitRatesExt; +} EpsQualityOfService; + +//typedef uint8_t EpsQualityOfService; + +int encode_eps_quality_of_service(EpsQualityOfService *epsqualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_eps_quality_of_service(EpsQualityOfService *epsqualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_quality_of_service_xml(EpsQualityOfService *epsqualityofservice, uint8_t iei); + +int eps_qos_bit_rate_value(uint8_t br); +int eps_qos_bit_rate_ext_value(uint8_t br); + +#endif /* EPS QUALITY OF SERVICE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.c new file mode 100644 index 0000000000..3db8ffff0f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsUpdateResult.h" + +int decode_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EPS_UPDATE_RESULT_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *epsupdateresult = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_update_result_xml(epsupdateresult, iei); +#endif + return decoded; +} + +int decode_u8_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *epsupdateresult = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_update_result_xml(epsupdateresult, iei); +#endif + return decoded; +} + +int encode_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_UPDATE_RESULT_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_update_result_xml(epsupdateresult, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsupdateresult & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_eps_update_result(EpsUpdateResult *epsupdateresult) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_eps_update_result_xml(epsupdateresult, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*epsupdateresult & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_eps_update_result_xml(EpsUpdateResult *epsupdateresult, uint8_t iei) +{ + printf("<Eps Update Result>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EPS update result value>%u</EPS update result value>\n", *epsupdateresult); + printf("</Eps Update Result>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h new file mode 100644 index 0000000000..48f4471e91 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_UPDATE_RESULT_H_ +#define EPS_UPDATE_RESULT_H_ + +#define EPS_UPDATE_RESULT_MINIMUM_LENGTH 1 +#define EPS_UPDATE_RESULT_MAXIMUM_LENGTH 1 + +typedef uint8_t EpsUpdateResult; + +int encode_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_update_result_xml(EpsUpdateResult *epsupdateresult, uint8_t iei); + +uint8_t encode_u8_eps_update_result(EpsUpdateResult *epsupdateresult); + +int decode_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_eps_update_result(EpsUpdateResult *epsupdateresult, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* EPS UPDATE RESULT_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.c new file mode 100644 index 0000000000..5281bfcd0b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.c @@ -0,0 +1,80 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EpsUpdateType.h" + +int decode_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, EPS_UPDATE_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + epsupdatetype->activeflag = (*(buffer + decoded) >> 3) & 0x1; + epsupdatetype->epsupdatetypevalue = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_update_type_xml(epsupdatetype, iei); +#endif + return decoded; +} + +int decode_u8_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + epsupdatetype->activeflag = (*(buffer + decoded) >> 3) & 0x1; + epsupdatetype->epsupdatetypevalue = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_eps_update_type_xml(epsupdatetype, iei); +#endif + return decoded; +} + +int encode_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, EPS_UPDATE_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_eps_update_type_xml(epsupdatetype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((epsupdatetype->activeflag & 0x1) << 3) | + (epsupdatetype->epsupdatetypevalue & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_eps_update_type(EpsUpdateType *epsupdatetype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_eps_update_type_xml(epsupdatetype, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((epsupdatetype->activeflag & 0x1) << 3) | + (epsupdatetype->epsupdatetypevalue & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_eps_update_type_xml(EpsUpdateType *epsupdatetype, uint8_t iei) +{ + printf("<Eps Update Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <active flag>%u</active flag>\n", epsupdatetype->activeflag); + printf(" <EPS update type value>%u</EPS update type value>\n", epsupdatetype->epsupdatetypevalue); + printf("</Eps Update Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h new file mode 100644 index 0000000000..0f1004c60d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef EPS_UPDATE_TYPE_H_ +#define EPS_UPDATE_TYPE_H_ + +#define EPS_UPDATE_TYPE_MINIMUM_LENGTH 1 +#define EPS_UPDATE_TYPE_MAXIMUM_LENGTH 1 + +typedef struct EpsUpdateType_tag { + uint8_t activeflag:1; + uint8_t epsupdatetypevalue:3; +} EpsUpdateType; + +int encode_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_eps_update_type_xml(EpsUpdateType *epsupdatetype, uint8_t iei); + +uint8_t encode_u8_eps_update_type(EpsUpdateType *epsupdatetype); + +int decode_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_eps_update_type(EpsUpdateType *epsupdatetype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* EPS UPDATE TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.c new file mode 100644 index 0000000000..2753cc9b50 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmCause.h" + +int decode_esm_cause(EsmCause *esmcause, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *esmcause = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_esm_cause_xml(esmcause, iei); +#endif + return decoded; +} + +int encode_esm_cause(EsmCause *esmcause, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_CAUSE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_esm_cause_xml(esmcause, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = *esmcause; + encoded++; + return encoded; +} + +void dump_esm_cause_xml(EsmCause *esmcause, uint8_t iei) +{ + printf("<Esm Cause>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Cause value>%u</Cause value>\n", *esmcause); + printf("</Esm Cause>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.h new file mode 100644 index 0000000000..df44cc7770 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmCause.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ESM_CAUSE_H_ +#define ESM_CAUSE_H_ + +#define ESM_CAUSE_MINIMUM_LENGTH 1 +#define ESM_CAUSE_MAXIMUM_LENGTH 1 + +typedef uint8_t EsmCause; + +int encode_esm_cause(EsmCause *esmcause, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_esm_cause_xml(EsmCause *esmcause, uint8_t iei); + +int decode_esm_cause(EsmCause *esmcause, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* ESM CAUSE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.c new file mode 100644 index 0000000000..34f04b7dcf --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmInformationTransferFlag.h" + +int decode_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, ESM_INFORMATION_TRANSFER_FLAG_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *esminformationtransferflag = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_esm_information_transfer_flag_xml(esminformationtransferflag, iei); +#endif + return decoded; +} + +int decode_u8_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *esminformationtransferflag = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_esm_information_transfer_flag_xml(esminformationtransferflag, iei); +#endif + return decoded; +} + +int encode_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_INFORMATION_TRANSFER_FLAG_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_esm_information_transfer_flag_xml(esminformationtransferflag, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*esminformationtransferflag & 0x1); + encoded++; + return encoded; +} + +uint8_t encode_u8_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_esm_information_transfer_flag_xml(esminformationtransferflag, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*esminformationtransferflag & 0x1); + encoded++; + + return bufferReturn; +} + +void dump_esm_information_transfer_flag_xml(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei) +{ + printf("<Esm Information Transfer Flag>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EIT value>%u</EIT value>\n", *esminformationtransferflag); + printf("</Esm Information Transfer Flag>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h new file mode 100644 index 0000000000..f9961bdd5a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ESM_INFORMATION_TRANSFER_FLAG_H_ +#define ESM_INFORMATION_TRANSFER_FLAG_H_ + +#define ESM_INFORMATION_TRANSFER_FLAG_MINIMUM_LENGTH 1 +#define ESM_INFORMATION_TRANSFER_FLAG_MAXIMUM_LENGTH 1 + +typedef uint8_t EsmInformationTransferFlag; + +int encode_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_esm_information_transfer_flag_xml(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei); + +uint8_t encode_u8_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag); + +int decode_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_esm_information_transfer_flag(EsmInformationTransferFlag *esminformationtransferflag, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* ESM INFORMATION TRANSFER FLAG_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.c b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.c new file mode 100644 index 0000000000..79fb31b4b6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.c @@ -0,0 +1,78 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "EsmMessageContainer.h" +#include "nas_log.h" + +int decode_esm_message_container(EsmMessageContainer *esmmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + int decode_result; + uint16_t ielen; + + LOG_FUNC_IN; + + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + + DECODE_LENGTH_U16(buffer + decoded, ielen, decoded); + + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&esmmessagecontainer->esmmessagecontainercontents, ielen, buffer + decoded, len - decoded)) < 0) { + LOG_FUNC_RETURN(decode_result); + } else { + decoded += decode_result; + } +#if defined (NAS_DEBUG) + dump_esm_message_container_xml(esmmessagecontainer, iei); +#endif + LOG_FUNC_RETURN(decoded); +} + +int encode_esm_message_container(EsmMessageContainer *esmmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int32_t encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_esm_message_container_xml(esmmessagecontainer, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + //encoded += 2; + //if ((encode_result = encode_octet_string(&esmmessagecontainer->esmmessagecontainercontents, buffer + sizeof(uint16_t), len - sizeof(uint16_t))) < 0) + if ((encode_result = encode_octet_string(&esmmessagecontainer->esmmessagecontainercontents, lenPtr + sizeof(uint16_t), len - sizeof(uint16_t))) < 0) + return encode_result; + else + encoded += encode_result; + + ENCODE_U16(lenPtr, encode_result, encoded); +#if 0 + lenPtr[1] = (((encoded - 2 - ((iei > 0) ? 1: 0))) & 0x0000ff00) >> 8; + lenPtr[0] = ((encoded - 2 - ((iei > 0) ? 1: 0))) & 0x000000ff; +#endif + return encoded; +} + +void dump_esm_message_container_xml(EsmMessageContainer *esmmessagecontainer, uint8_t iei) +{ + printf("<Esm Message Container>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&esmmessagecontainer->esmmessagecontainercontents); + printf("</Esm Message Container>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h new file mode 100644 index 0000000000..dbb4b8833e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef ESM_MESSAGE_CONTAINER_H_ +#define ESM_MESSAGE_CONTAINER_H_ + +#define ESM_MESSAGE_CONTAINER_MINIMUM_LENGTH 2 // [length]+[length] +#define ESM_MESSAGE_CONTAINER_MAXIMUM_LENGTH 65538 // [IEI]+[length]+[length]+[ESM msg] + +typedef struct EsmMessageContainer_tag { + OctetString esmmessagecontainercontents; +} EsmMessageContainer; + +int encode_esm_message_container(EsmMessageContainer *esmmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_esm_message_container(EsmMessageContainer *esmmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_esm_message_container_xml(EsmMessageContainer *esmmessagecontainer, uint8_t iei); + +#endif /* ESM MESSAGE CONTAINER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.c b/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.c new file mode 100644 index 0000000000..d59f901171 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "GprsTimer.h" + +static const long _gprs_timer_unit[] = {2, 60, 360, 60, 60, 60, 60, 0}; + +int decode_gprs_timer(GprsTimer *gprstimer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + gprstimer->unit = (*(buffer + decoded) >> 5) & 0x7; + gprstimer->timervalue = *(buffer + decoded) & 0x1f; + decoded++; +#if defined (NAS_DEBUG) + dump_gprs_timer_xml(gprstimer, iei); +#endif + return decoded; +} + +int encode_gprs_timer(GprsTimer *gprstimer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, GPRS_TIMER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_gprs_timer_xml(gprstimer, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | ((gprstimer->unit & 0x7) << 5) | + (gprstimer->timervalue & 0x1f); + encoded++; + return encoded; +} + +void dump_gprs_timer_xml(GprsTimer *gprstimer, uint8_t iei) +{ + printf("<Gprs Timer>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Unit>%u</Unit>\n", gprstimer->unit); + printf(" <Timer value>%u</Timer value>\n", gprstimer->timervalue); + printf("</Gprs Timer>\n"); +} + +long gprs_timer_value(GprsTimer *gprstimer) +{ + return (gprstimer->timervalue * _gprs_timer_unit[gprstimer->unit]); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.h b/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.h new file mode 100644 index 0000000000..004e71117b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/GprsTimer.h @@ -0,0 +1,31 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef GPRS_TIMER_H_ +#define GPRS_TIMER_H_ + +#define GPRS_TIMER_MINIMUM_LENGTH 2 +#define GPRS_TIMER_MAXIMUM_LENGTH 2 + +typedef struct GprsTimer_tag { +#define GPRS_TIMER_UNIT_2S 0b000 /* 2 seconds */ +#define GPRS_TIMER_UNIT_60S 0b001 /* 1 minute */ +#define GPRS_TIMER_UNIT_360S 0b010 /* decihours */ +#define GPRS_TIMER_UNIT_0S 0b111 /* deactivated */ + uint8_t unit:3; + uint8_t timervalue:5; +} GprsTimer; + +int encode_gprs_timer(GprsTimer *gprstimer, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_gprs_timer_xml(GprsTimer *gprstimer, uint8_t iei); + +int decode_gprs_timer(GprsTimer *gprstimer, uint8_t iei, uint8_t *buffer, uint32_t len); + +long gprs_timer_value(GprsTimer *gprstimer); + +#endif /* GPRS TIMER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.c new file mode 100644 index 0000000000..74d96df180 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "GutiType.h" + +int decode_guti_type(GutiType *gutitype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, GUTI_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *gutitype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_guti_type_xml(gutitype, iei); +#endif + return decoded; +} + +int decode_u8_guti_type(GutiType *gutitype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *gutitype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_guti_type_xml(gutitype, iei); +#endif + return decoded; +} + +int encode_guti_type(GutiType *gutitype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, GUTI_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_guti_type_xml(gutitype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*gutitype & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_guti_type(GutiType *gutitype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_guti_type_xml(gutitype, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*gutitype & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_guti_type_xml(GutiType *gutitype, uint8_t iei) +{ + printf("<Guti Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Guti type value>%u</Guti type value>\n", *gutitype); + printf("</Guti Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.h new file mode 100644 index 0000000000..2c0c082dcc --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/GutiType.h @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef GUTI_TYPE_H_ +#define GUTI_TYPE_H_ + +#define GUTI_TYPE_MINIMUM_LENGTH 1 +#define GUTI_TYPE_MAXIMUM_LENGTH 1 + +#define GUTI_NATIVE 0 +#define GUTI_MAPPED 1 +typedef uint8_t GutiType; + +int encode_guti_type(GutiType *gutitype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_guti_type_xml(GutiType *gutitype, uint8_t iei); + +uint8_t encode_u8_guti_type(GutiType *gutitype); + +int decode_guti_type(GutiType *gutitype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_guti_type(GutiType *gutitype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* GUTI_TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.c b/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.c new file mode 100644 index 0000000000..694b47ae62 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "IdentityType2.h" + +int decode_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, IDENTITY_TYPE_2_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *identitytype2 = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_identity_type_2_xml(identitytype2, iei); +#endif + return decoded; +} + +int decode_u8_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *identitytype2 = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_identity_type_2_xml(identitytype2, iei); +#endif + return decoded; +} + +int encode_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, IDENTITY_TYPE_2_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_identity_type_2_xml(identitytype2, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*identitytype2 & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_identity_type_2(IdentityType2 *identitytype2) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_identity_type_2_xml(identitytype2, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*identitytype2 & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_identity_type_2_xml(IdentityType2 *identitytype2, uint8_t iei) +{ + printf("<Identity Type 2>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Type of identity>%u</Type of identity>\n", *identitytype2); + printf("</Identity Type 2>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.h b/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.h new file mode 100644 index 0000000000..5fceaa3d73 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/IdentityType2.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef IDENTITY_TYPE_2_H_ +#define IDENTITY_TYPE_2_H_ + +#define IDENTITY_TYPE_2_MINIMUM_LENGTH 1 +#define IDENTITY_TYPE_2_MAXIMUM_LENGTH 1 + +#define IDENTITY_TYPE_2_IMSI 0b001 +#define IDENTITY_TYPE_2_IMEI 0b010 +#define IDENTITY_TYPE_2_IMEISV 0b011 +#define IDENTITY_TYPE_2_TMSI 0b100 +typedef uint8_t IdentityType2; + +int encode_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_identity_type_2_xml(IdentityType2 *identitytype2, uint8_t iei); + +uint8_t encode_u8_identity_type_2(IdentityType2 *identitytype2); + +int decode_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_identity_type_2(IdentityType2 *identitytype2, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* IDENTITY TYPE 2_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.c new file mode 100644 index 0000000000..5629ac0a18 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ImeisvRequest.h" + +int decode_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, IMEISV_REQUEST_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *imeisvrequest = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_imeisv_request_xml(imeisvrequest, iei); +#endif + return decoded; +} + +int decode_u8_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *imeisvrequest = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_imeisv_request_xml(imeisvrequest, iei); +#endif + return decoded; +} + +int encode_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, IMEISV_REQUEST_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_imeisv_request_xml(imeisvrequest, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*imeisvrequest & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_imeisv_request(ImeisvRequest *imeisvrequest) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_imeisv_request_xml(imeisvrequest, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*imeisvrequest & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_imeisv_request_xml(ImeisvRequest *imeisvrequest, uint8_t iei) +{ + printf("<Imeisv Request>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <IMEISV request value>%u</IMEISV request value>\n", *imeisvrequest); + printf("</Imeisv Request>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h new file mode 100644 index 0000000000..5187a6126c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef IMEISV_REQUEST_H_ +#define IMEISV_REQUEST_H_ + +#define IMEISV_REQUEST_MINIMUM_LENGTH 1 +#define IMEISV_REQUEST_MAXIMUM_LENGTH 1 + +typedef uint8_t ImeisvRequest; + +int encode_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_imeisv_request_xml(ImeisvRequest *imeisvrequest, uint8_t iei); + +uint8_t encode_u8_imeisv_request(ImeisvRequest *imeisvrequest); + +int decode_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_imeisv_request(ImeisvRequest *imeisvrequest, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* IMEISV REQUEST_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.c b/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.c new file mode 100644 index 0000000000..23547e1c50 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.c @@ -0,0 +1,56 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "KsiAndSequenceNumber.h" + +int decode_ksi_and_sequence_number(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ksiandsequencenumber->ksi = (*(buffer + decoded) >> 5) & 0x7; + ksiandsequencenumber->sequencenumber = *(buffer + decoded) & 0x1f; + decoded++; +#if defined (NAS_DEBUG) + dump_ksi_and_sequence_number_xml(ksiandsequencenumber, iei); +#endif + return decoded; +} + +int encode_ksi_and_sequence_number(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, KSI_AND_SEQUENCE_NUMBER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ksi_and_sequence_number_xml(ksiandsequencenumber, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | ((ksiandsequencenumber->ksi & 0x7) << 5) | + (ksiandsequencenumber->sequencenumber & 0x1f); + encoded++; + return encoded; +} + +void dump_ksi_and_sequence_number_xml(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei) +{ + printf("<Ksi And Sequence Number>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <KSI>%u</KSI>\n", ksiandsequencenumber->ksi); + printf(" <Sequence number>%u</Sequence number>\n", ksiandsequencenumber->sequencenumber); + printf("</Ksi And Sequence Number>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h b/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h new file mode 100644 index 0000000000..f7ba055b18 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef KSI_AND_SEQUENCE_NUMBER_H_ +#define KSI_AND_SEQUENCE_NUMBER_H_ + +#define KSI_AND_SEQUENCE_NUMBER_MINIMUM_LENGTH 2 +#define KSI_AND_SEQUENCE_NUMBER_MAXIMUM_LENGTH 2 + +typedef struct KsiAndSequenceNumber_tag { + uint8_t ksi:3; + uint8_t sequencenumber:5; +} KsiAndSequenceNumber; + +int encode_ksi_and_sequence_number(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ksi_and_sequence_number_xml(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei); + +int decode_ksi_and_sequence_number(KsiAndSequenceNumber *ksiandsequencenumber, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* KSI AND SEQUENCE NUMBER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.c new file mode 100644 index 0000000000..aa4f9fc0ea --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "LcsClientIdentity.h" + +int decode_lcs_client_identity(LcsClientIdentity *lcsclientidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&lcsclientidentity->lcsclientidentityvalue, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_lcs_client_identity_xml(lcsclientidentity, iei); +#endif + return decoded; +} +int encode_lcs_client_identity(LcsClientIdentity *lcsclientidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, LCS_CLIENT_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_lcs_client_identity_xml(lcsclientidentity, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&lcsclientidentity->lcsclientidentityvalue, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_lcs_client_identity_xml(LcsClientIdentity *lcsclientidentity, uint8_t iei) +{ + printf("<Lcs Client Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&lcsclientidentity->lcsclientidentityvalue); + printf("</Lcs Client Identity>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h new file mode 100644 index 0000000000..30002b564b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef LCS_CLIENT_IDENTITY_H_ +#define LCS_CLIENT_IDENTITY_H_ + +#define LCS_CLIENT_IDENTITY_MINIMUM_LENGTH 3 +#define LCS_CLIENT_IDENTITY_MAXIMUM_LENGTH 257 + +typedef struct LcsClientIdentity_tag { + OctetString lcsclientidentityvalue; +} LcsClientIdentity; + +int encode_lcs_client_identity(LcsClientIdentity *lcsclientidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_lcs_client_identity(LcsClientIdentity *lcsclientidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_lcs_client_identity_xml(LcsClientIdentity *lcsclientidentity, uint8_t iei); + +#endif /* LCS CLIENT IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.c b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.c new file mode 100644 index 0000000000..37eecc95ba --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "LcsIndicator.h" + +int decode_lcs_indicator(LcsIndicator *lcsindicator, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *lcsindicator = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_lcs_indicator_xml(lcsindicator, iei); +#endif + return decoded; +} + +int encode_lcs_indicator(LcsIndicator *lcsindicator, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, LCS_INDICATOR_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_lcs_indicator_xml(lcsindicator, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = *lcsindicator; + encoded++; + return encoded; +} + +void dump_lcs_indicator_xml(LcsIndicator *lcsindicator, uint8_t iei) +{ + printf("<Lcs Indicator>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <LCS indicator value>%u</LCS indicator value>\n", *lcsindicator); + printf("</Lcs Indicator>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.h b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.h new file mode 100644 index 0000000000..3b866d8c8e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LcsIndicator.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef LCS_INDICATOR_H_ +#define LCS_INDICATOR_H_ + +#define LCS_INDICATOR_MINIMUM_LENGTH 2 +#define LCS_INDICATOR_MAXIMUM_LENGTH 2 + +typedef uint8_t LcsIndicator; + +int encode_lcs_indicator(LcsIndicator *lcsindicator, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_lcs_indicator_xml(LcsIndicator *lcsindicator, uint8_t iei); + +int decode_lcs_indicator(LcsIndicator *lcsindicator, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* LCS INDICATOR_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.c new file mode 100644 index 0000000000..3488ffbf1c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "LinkedEpsBearerIdentity.h" + +int decode_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, LINKED_EPS_BEARER_IDENTITY_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *linkedepsbeareridentity = *buffer & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_linked_eps_bearer_identity_xml(linkedepsbeareridentity, iei); +#endif + return decoded; +} + +int decode_u8_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *linkedepsbeareridentity = *buffer & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_linked_eps_bearer_identity_xml(linkedepsbeareridentity, iei); +#endif + return decoded; +} + +int encode_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, LINKED_EPS_BEARER_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_linked_eps_bearer_identity_xml(linkedepsbeareridentity, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*linkedepsbeareridentity & 0xf); + encoded++; + return encoded; +} + +uint8_t encode_u8_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_linked_eps_bearer_identity_xml(linkedepsbeareridentity, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*linkedepsbeareridentity & 0xf); + encoded++; + + return bufferReturn; +} + +void dump_linked_eps_bearer_identity_xml(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei) +{ + printf("<Linked Eps Bearer Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Linked EPS bearer identity value>%u</Linked EPS bearer identity value>\n", *linkedepsbeareridentity); + printf("</Linked Eps Bearer Identity>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h new file mode 100644 index 0000000000..a231525112 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef LINKED_EPS_BEARER_IDENTITY_H_ +#define LINKED_EPS_BEARER_IDENTITY_H_ + +#define LINKED_EPS_BEARER_IDENTITY_MINIMUM_LENGTH 1 +#define LINKED_EPS_BEARER_IDENTITY_MAXIMUM_LENGTH 1 + +typedef uint8_t LinkedEpsBearerIdentity; + +int encode_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_linked_eps_bearer_identity_xml(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei); + +uint8_t encode_u8_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity); + +int decode_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_linked_eps_bearer_identity(LinkedEpsBearerIdentity *linkedepsbeareridentity, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* LINKED EPS BEARER IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.c b/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.c new file mode 100644 index 0000000000..08e7c74874 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.c @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "LlcServiceAccessPointIdentifier.h" + +int decode_llc_service_access_point_identifier(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *llcserviceaccesspointidentifier = *buffer & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_llc_service_access_point_identifier_xml(llcserviceaccesspointidentifier, iei); +#endif + return decoded; +} + +int encode_llc_service_access_point_identifier(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_llc_service_access_point_identifier_xml(llcserviceaccesspointidentifier, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | + (*llcserviceaccesspointidentifier & 0xf); + encoded++; + return encoded; +} + +void dump_llc_service_access_point_identifier_xml(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei) +{ + printf("<Llc Service Access Point Identifier>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <LLC SAPI value>%u</LLC SAPI value>\n", *llcserviceaccesspointidentifier); + printf("</Llc Service Access Point Identifier>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h b/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h new file mode 100644 index 0000000000..ef8f0b3c0a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef LLC_SERVICE_ACCESS_POINT_IDENTIFIER_H_ +#define LLC_SERVICE_ACCESS_POINT_IDENTIFIER_H_ + +#define LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MINIMUM_LENGTH 2 +#define LLC_SERVICE_ACCESS_POINT_IDENTIFIER_MAXIMUM_LENGTH 2 + +typedef uint8_t LlcServiceAccessPointIdentifier; + +int encode_llc_service_access_point_identifier(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_llc_service_access_point_identifier_xml(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei); + +int decode_llc_service_access_point_identifier(LlcServiceAccessPointIdentifier *llcserviceaccesspointidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* LLC SERVICE ACCESS POINT IDENTIFIER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.c b/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.c new file mode 100644 index 0000000000..3c386091f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.c @@ -0,0 +1,76 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "LocationAreaIdentification.h" + +int decode_location_area_identification(LocationAreaIdentification *locationareaidentification, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + locationareaidentification->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + locationareaidentification->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + locationareaidentification->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + locationareaidentification->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + locationareaidentification->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + locationareaidentification->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; + //IES_DECODE_U16(locationareaidentification->lac, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, locationareaidentification->lac); +#if defined (NAS_DEBUG) + dump_location_area_identification_xml(locationareaidentification, iei); +#endif + return decoded; +} + +int encode_location_area_identification(LocationAreaIdentification *locationareaidentification, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, LOCATION_AREA_IDENTIFICATION_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_location_area_identification_xml(locationareaidentification, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | ((locationareaidentification->mccdigit2 & 0xf) << 4) | + (locationareaidentification->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((locationareaidentification->mncdigit3 & 0xf) << 4) | + (locationareaidentification->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((locationareaidentification->mncdigit2 & 0xf) << 4) | + (locationareaidentification->mncdigit1 & 0xf); + encoded++; + IES_ENCODE_U16(buffer, encoded, locationareaidentification->lac); + return encoded; +} + +void dump_location_area_identification_xml(LocationAreaIdentification *locationareaidentification, uint8_t iei) +{ + printf("<Location Area Identification>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <MCC digit 2>%u</MCC digit 2>\n", locationareaidentification->mccdigit2); + printf(" <MCC digit 1>%u</MCC digit 1>\n", locationareaidentification->mccdigit1); + printf(" <MNC digit 3>%u</MNC digit 3>\n", locationareaidentification->mncdigit3); + printf(" <MCC digit 3>%u</MCC digit 3>\n", locationareaidentification->mccdigit3); + printf(" <MNC digit 2>%u</MNC digit 2>\n", locationareaidentification->mncdigit2); + printf(" <MNC digit 1>%u</MNC digit 1>\n", locationareaidentification->mncdigit1); + printf(" <LAC>%u</LAC>\n", locationareaidentification->lac); + printf("</Location Area Identification>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h b/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h new file mode 100644 index 0000000000..20d82bc174 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef LOCATION_AREA_IDENTIFICATION_H_ +#define LOCATION_AREA_IDENTIFICATION_H_ + +#define LOCATION_AREA_IDENTIFICATION_MINIMUM_LENGTH 6 +#define LOCATION_AREA_IDENTIFICATION_MAXIMUM_LENGTH 6 + +typedef struct LocationAreaIdentification_tag { + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; + uint16_t lac; +} LocationAreaIdentification; + +int encode_location_area_identification(LocationAreaIdentification *locationareaidentification, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_location_area_identification_xml(LocationAreaIdentification *locationareaidentification, uint8_t iei); + +int decode_location_area_identification(LocationAreaIdentification *locationareaidentification, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* LOCATION AREA IDENTIFICATION_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/Makefile b/openair-cn/NAS/EURECOM-NAS/src/ies/Makefile new file mode 100644 index 0000000000..b95a950c9b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/Makefile @@ -0,0 +1,969 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(UTILDIR) + +#DEFINES += -DNAS_DEBUG + +TARGET = $(LIBIES) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c %.h Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +AccessPointName.o: /usr/include/stdio.h /usr/include/features.h +AccessPointName.o: /usr/include/libio.h /usr/include/_G_config.h +AccessPointName.o: /usr/include/wchar.h /usr/include/xlocale.h +AccessPointName.o: /usr/include/stdlib.h /usr/include/alloca.h +AccessPointName.o: /usr/include/stdint.h +AccessPointName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AccessPointName.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +AccessPointName.o: /usr/include/endian.h +AccessPointName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AccessPointName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AccessPointName.o: AccessPointName.h +AccessPointName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AdditionalUpdateResult.o: /usr/include/stdio.h /usr/include/features.h +AdditionalUpdateResult.o: /usr/include/libio.h /usr/include/_G_config.h +AdditionalUpdateResult.o: /usr/include/wchar.h /usr/include/xlocale.h +AdditionalUpdateResult.o: /usr/include/stdlib.h /usr/include/alloca.h +AdditionalUpdateResult.o: /usr/include/stdint.h +AdditionalUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AdditionalUpdateResult.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +AdditionalUpdateResult.o: /usr/include/endian.h +AdditionalUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AdditionalUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AdditionalUpdateResult.o: AdditionalUpdateResult.h +AdditionalUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AdditionalUpdateType.o: /usr/include/stdio.h /usr/include/features.h +AdditionalUpdateType.o: /usr/include/libio.h /usr/include/_G_config.h +AdditionalUpdateType.o: /usr/include/wchar.h /usr/include/xlocale.h +AdditionalUpdateType.o: /usr/include/stdlib.h /usr/include/alloca.h +AdditionalUpdateType.o: /usr/include/stdint.h +AdditionalUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AdditionalUpdateType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +AdditionalUpdateType.o: /usr/include/endian.h +AdditionalUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AdditionalUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AdditionalUpdateType.o: AdditionalUpdateType.h +AdditionalUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ApnAggregateMaximumBitRate.o: /usr/include/stdio.h /usr/include/features.h +ApnAggregateMaximumBitRate.o: /usr/include/libio.h /usr/include/_G_config.h +ApnAggregateMaximumBitRate.o: /usr/include/wchar.h /usr/include/xlocale.h +ApnAggregateMaximumBitRate.o: /usr/include/stdlib.h /usr/include/alloca.h +ApnAggregateMaximumBitRate.o: /usr/include/stdint.h +ApnAggregateMaximumBitRate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ApnAggregateMaximumBitRate.o: /usr/include/arpa/inet.h +ApnAggregateMaximumBitRate.o: /usr/include/netinet/in.h /usr/include/endian.h +ApnAggregateMaximumBitRate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ApnAggregateMaximumBitRate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ApnAggregateMaximumBitRate.o: ApnAggregateMaximumBitRate.h +ApnAggregateMaximumBitRate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AuthenticationFailureParameter.o: /usr/include/stdio.h +AuthenticationFailureParameter.o: /usr/include/features.h +AuthenticationFailureParameter.o: /usr/include/libio.h +AuthenticationFailureParameter.o: /usr/include/_G_config.h +AuthenticationFailureParameter.o: /usr/include/wchar.h /usr/include/xlocale.h +AuthenticationFailureParameter.o: /usr/include/stdlib.h /usr/include/alloca.h +AuthenticationFailureParameter.o: /usr/include/stdint.h +AuthenticationFailureParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AuthenticationFailureParameter.o: /usr/include/arpa/inet.h +AuthenticationFailureParameter.o: /usr/include/netinet/in.h +AuthenticationFailureParameter.o: /usr/include/endian.h +AuthenticationFailureParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AuthenticationFailureParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AuthenticationFailureParameter.o: AuthenticationFailureParameter.h +AuthenticationFailureParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AuthenticationParameterAutn.o: /usr/include/stdio.h /usr/include/features.h +AuthenticationParameterAutn.o: /usr/include/libio.h /usr/include/_G_config.h +AuthenticationParameterAutn.o: /usr/include/wchar.h /usr/include/xlocale.h +AuthenticationParameterAutn.o: /usr/include/stdlib.h /usr/include/alloca.h +AuthenticationParameterAutn.o: /usr/include/stdint.h +AuthenticationParameterAutn.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AuthenticationParameterAutn.o: /usr/include/arpa/inet.h +AuthenticationParameterAutn.o: /usr/include/netinet/in.h +AuthenticationParameterAutn.o: /usr/include/endian.h +AuthenticationParameterAutn.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AuthenticationParameterAutn.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AuthenticationParameterAutn.o: AuthenticationParameterAutn.h +AuthenticationParameterAutn.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AuthenticationParameterRand.o: /usr/include/stdio.h /usr/include/features.h +AuthenticationParameterRand.o: /usr/include/libio.h /usr/include/_G_config.h +AuthenticationParameterRand.o: /usr/include/wchar.h /usr/include/xlocale.h +AuthenticationParameterRand.o: /usr/include/stdlib.h /usr/include/alloca.h +AuthenticationParameterRand.o: /usr/include/stdint.h +AuthenticationParameterRand.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AuthenticationParameterRand.o: /usr/include/arpa/inet.h +AuthenticationParameterRand.o: /usr/include/netinet/in.h +AuthenticationParameterRand.o: /usr/include/endian.h +AuthenticationParameterRand.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AuthenticationParameterRand.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AuthenticationParameterRand.o: AuthenticationParameterRand.h +AuthenticationParameterRand.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +AuthenticationResponseParameter.o: /usr/include/stdio.h +AuthenticationResponseParameter.o: /usr/include/features.h +AuthenticationResponseParameter.o: /usr/include/libio.h +AuthenticationResponseParameter.o: /usr/include/_G_config.h +AuthenticationResponseParameter.o: /usr/include/wchar.h +AuthenticationResponseParameter.o: /usr/include/xlocale.h +AuthenticationResponseParameter.o: /usr/include/stdlib.h +AuthenticationResponseParameter.o: /usr/include/alloca.h +AuthenticationResponseParameter.o: /usr/include/stdint.h +AuthenticationResponseParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +AuthenticationResponseParameter.o: /usr/include/arpa/inet.h +AuthenticationResponseParameter.o: /usr/include/netinet/in.h +AuthenticationResponseParameter.o: /usr/include/endian.h +AuthenticationResponseParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +AuthenticationResponseParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +AuthenticationResponseParameter.o: AuthenticationResponseParameter.h +AuthenticationResponseParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +CipheringKeySequenceNumber.o: /usr/include/stdio.h /usr/include/features.h +CipheringKeySequenceNumber.o: /usr/include/libio.h /usr/include/_G_config.h +CipheringKeySequenceNumber.o: /usr/include/wchar.h /usr/include/xlocale.h +CipheringKeySequenceNumber.o: /usr/include/stdlib.h /usr/include/alloca.h +CipheringKeySequenceNumber.o: /usr/include/stdint.h +CipheringKeySequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +CipheringKeySequenceNumber.o: /usr/include/arpa/inet.h +CipheringKeySequenceNumber.o: /usr/include/netinet/in.h /usr/include/endian.h +CipheringKeySequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +CipheringKeySequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +CipheringKeySequenceNumber.o: CipheringKeySequenceNumber.h +CipheringKeySequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Cli.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +Cli.o: /usr/include/_G_config.h /usr/include/wchar.h /usr/include/xlocale.h +Cli.o: /usr/include/stdlib.h /usr/include/alloca.h /usr/include/stdint.h +Cli.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +Cli.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +Cli.o: /usr/include/endian.h +Cli.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +Cli.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Cli.o: Cli.h +Cli.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +CsfbResponse.o: /usr/include/stdio.h /usr/include/features.h +CsfbResponse.o: /usr/include/libio.h /usr/include/_G_config.h +CsfbResponse.o: /usr/include/wchar.h /usr/include/xlocale.h +CsfbResponse.o: /usr/include/stdlib.h /usr/include/alloca.h +CsfbResponse.o: /usr/include/stdint.h +CsfbResponse.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +CsfbResponse.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +CsfbResponse.o: /usr/include/endian.h +CsfbResponse.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +CsfbResponse.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +CsfbResponse.o: CsfbResponse.h +CsfbResponse.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +DaylightSavingTime.o: /usr/include/stdio.h /usr/include/features.h +DaylightSavingTime.o: /usr/include/libio.h /usr/include/_G_config.h +DaylightSavingTime.o: /usr/include/wchar.h /usr/include/xlocale.h +DaylightSavingTime.o: /usr/include/stdlib.h /usr/include/alloca.h +DaylightSavingTime.o: /usr/include/stdint.h +DaylightSavingTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +DaylightSavingTime.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +DaylightSavingTime.o: /usr/include/endian.h +DaylightSavingTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +DaylightSavingTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +DaylightSavingTime.o: DaylightSavingTime.h +DaylightSavingTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +DetachType.o: /usr/include/stdio.h /usr/include/features.h +DetachType.o: /usr/include/libio.h /usr/include/_G_config.h +DetachType.o: /usr/include/wchar.h /usr/include/xlocale.h +DetachType.o: /usr/include/stdlib.h /usr/include/alloca.h +DetachType.o: /usr/include/stdint.h +DetachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +DetachType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +DetachType.o: /usr/include/endian.h +DetachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +DetachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +DetachType.o: DetachType.h +DetachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +DrxParameter.o: /usr/include/stdio.h /usr/include/features.h +DrxParameter.o: /usr/include/libio.h /usr/include/_G_config.h +DrxParameter.o: /usr/include/wchar.h /usr/include/xlocale.h +DrxParameter.o: /usr/include/stdlib.h /usr/include/alloca.h +DrxParameter.o: /usr/include/stdint.h +DrxParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +DrxParameter.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +DrxParameter.o: /usr/include/endian.h +DrxParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +DrxParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +DrxParameter.o: DrxParameter.h +DrxParameter.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EmergencyNumberList.o: /usr/include/stdio.h /usr/include/features.h +EmergencyNumberList.o: /usr/include/libio.h /usr/include/_G_config.h +EmergencyNumberList.o: /usr/include/wchar.h /usr/include/xlocale.h +EmergencyNumberList.o: /usr/include/stdlib.h /usr/include/alloca.h +EmergencyNumberList.o: /usr/include/stdint.h +EmergencyNumberList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EmergencyNumberList.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EmergencyNumberList.o: /usr/include/endian.h +EmergencyNumberList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EmergencyNumberList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EmergencyNumberList.o: EmergencyNumberList.h +EmergencyNumberList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EmmCause.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +EmmCause.o: /usr/include/_G_config.h /usr/include/wchar.h +EmmCause.o: /usr/include/xlocale.h /usr/include/stdlib.h +EmmCause.o: /usr/include/alloca.h /usr/include/stdint.h +EmmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EmmCause.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EmmCause.o: /usr/include/endian.h +EmmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EmmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EmmCause.o: EmmCause.h +EmmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsAttachResult.o: /usr/include/stdio.h /usr/include/features.h +EpsAttachResult.o: /usr/include/libio.h /usr/include/_G_config.h +EpsAttachResult.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsAttachResult.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsAttachResult.o: /usr/include/stdint.h +EpsAttachResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsAttachResult.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsAttachResult.o: /usr/include/endian.h +EpsAttachResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsAttachResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsAttachResult.o: EpsAttachResult.h +EpsAttachResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsAttachType.o: /usr/include/stdio.h /usr/include/features.h +EpsAttachType.o: /usr/include/libio.h /usr/include/_G_config.h +EpsAttachType.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsAttachType.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsAttachType.o: /usr/include/stdint.h +EpsAttachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsAttachType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsAttachType.o: /usr/include/endian.h +EpsAttachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsAttachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsAttachType.o: EpsAttachType.h +EpsAttachType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsBearerContextStatus.o: /usr/include/stdio.h /usr/include/features.h +EpsBearerContextStatus.o: /usr/include/libio.h /usr/include/_G_config.h +EpsBearerContextStatus.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsBearerContextStatus.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsBearerContextStatus.o: /usr/include/stdint.h +EpsBearerContextStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsBearerContextStatus.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsBearerContextStatus.o: /usr/include/endian.h +EpsBearerContextStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsBearerContextStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsBearerContextStatus.o: EpsBearerContextStatus.h +EpsBearerContextStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsBearerIdentity.o: /usr/include/stdio.h /usr/include/features.h +EpsBearerIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +EpsBearerIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsBearerIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsBearerIdentity.o: /usr/include/stdint.h +EpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsBearerIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsBearerIdentity.o: /usr/include/endian.h +EpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsBearerIdentity.o: EpsBearerIdentity.h +EpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsMobileIdentity.o: /usr/include/stdio.h /usr/include/features.h +EpsMobileIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +EpsMobileIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsMobileIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsMobileIdentity.o: /usr/include/stdint.h +EpsMobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsMobileIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsMobileIdentity.o: /usr/include/endian.h +EpsMobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsMobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsMobileIdentity.o: EpsMobileIdentity.h +EpsMobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsNetworkFeatureSupport.o: /usr/include/stdio.h /usr/include/features.h +EpsNetworkFeatureSupport.o: /usr/include/libio.h /usr/include/_G_config.h +EpsNetworkFeatureSupport.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsNetworkFeatureSupport.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsNetworkFeatureSupport.o: /usr/include/stdint.h +EpsNetworkFeatureSupport.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsNetworkFeatureSupport.o: /usr/include/arpa/inet.h +EpsNetworkFeatureSupport.o: /usr/include/netinet/in.h /usr/include/endian.h +EpsNetworkFeatureSupport.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsNetworkFeatureSupport.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsNetworkFeatureSupport.o: EpsNetworkFeatureSupport.h +EpsNetworkFeatureSupport.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsQualityOfService.o: /usr/include/stdio.h /usr/include/features.h +EpsQualityOfService.o: /usr/include/libio.h /usr/include/_G_config.h +EpsQualityOfService.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsQualityOfService.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsQualityOfService.o: /usr/include/stdint.h +EpsQualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsQualityOfService.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsQualityOfService.o: /usr/include/endian.h +EpsQualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsQualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsQualityOfService.o: EpsQualityOfService.h +EpsUpdateResult.o: /usr/include/stdio.h /usr/include/features.h +EpsUpdateResult.o: /usr/include/libio.h /usr/include/_G_config.h +EpsUpdateResult.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsUpdateResult.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsUpdateResult.o: /usr/include/stdint.h +EpsUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsUpdateResult.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsUpdateResult.o: /usr/include/endian.h +EpsUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsUpdateResult.o: EpsUpdateResult.h +EpsUpdateResult.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EpsUpdateType.o: /usr/include/stdio.h /usr/include/features.h +EpsUpdateType.o: /usr/include/libio.h /usr/include/_G_config.h +EpsUpdateType.o: /usr/include/wchar.h /usr/include/xlocale.h +EpsUpdateType.o: /usr/include/stdlib.h /usr/include/alloca.h +EpsUpdateType.o: /usr/include/stdint.h +EpsUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EpsUpdateType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EpsUpdateType.o: /usr/include/endian.h +EpsUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EpsUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EpsUpdateType.o: EpsUpdateType.h +EpsUpdateType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EsmCause.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +EsmCause.o: /usr/include/_G_config.h /usr/include/wchar.h +EsmCause.o: /usr/include/xlocale.h /usr/include/stdlib.h +EsmCause.o: /usr/include/alloca.h /usr/include/stdint.h +EsmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EsmCause.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EsmCause.o: /usr/include/endian.h +EsmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EsmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EsmCause.o: EsmCause.h +EsmCause.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EsmInformationTransferFlag.o: /usr/include/stdio.h /usr/include/features.h +EsmInformationTransferFlag.o: /usr/include/libio.h /usr/include/_G_config.h +EsmInformationTransferFlag.o: /usr/include/wchar.h /usr/include/xlocale.h +EsmInformationTransferFlag.o: /usr/include/stdlib.h /usr/include/alloca.h +EsmInformationTransferFlag.o: /usr/include/stdint.h +EsmInformationTransferFlag.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EsmInformationTransferFlag.o: /usr/include/arpa/inet.h +EsmInformationTransferFlag.o: /usr/include/netinet/in.h /usr/include/endian.h +EsmInformationTransferFlag.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EsmInformationTransferFlag.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EsmInformationTransferFlag.o: EsmInformationTransferFlag.h +EsmInformationTransferFlag.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +EsmMessageContainer.o: /usr/include/stdio.h /usr/include/features.h +EsmMessageContainer.o: /usr/include/libio.h /usr/include/_G_config.h +EsmMessageContainer.o: /usr/include/wchar.h /usr/include/xlocale.h +EsmMessageContainer.o: /usr/include/stdlib.h /usr/include/alloca.h +EsmMessageContainer.o: /usr/include/stdint.h +EsmMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +EsmMessageContainer.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +EsmMessageContainer.o: /usr/include/endian.h +EsmMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +EsmMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +EsmMessageContainer.o: EsmMessageContainer.h +EsmMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +GprsTimer.o: /usr/include/stdio.h /usr/include/features.h +GprsTimer.o: /usr/include/libio.h /usr/include/_G_config.h +GprsTimer.o: /usr/include/wchar.h /usr/include/xlocale.h +GprsTimer.o: /usr/include/stdlib.h /usr/include/alloca.h +GprsTimer.o: /usr/include/stdint.h +GprsTimer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +GprsTimer.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +GprsTimer.o: /usr/include/endian.h +GprsTimer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +GprsTimer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +GprsTimer.o: GprsTimer.h +GprsTimer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +GutiType.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +GutiType.o: /usr/include/_G_config.h /usr/include/wchar.h +GutiType.o: /usr/include/xlocale.h /usr/include/stdlib.h +GutiType.o: /usr/include/alloca.h /usr/include/stdint.h +GutiType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +GutiType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +GutiType.o: /usr/include/endian.h +GutiType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +GutiType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +GutiType.o: GutiType.h +GutiType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +IdentityType2.o: /usr/include/stdio.h /usr/include/features.h +IdentityType2.o: /usr/include/libio.h /usr/include/_G_config.h +IdentityType2.o: /usr/include/wchar.h /usr/include/xlocale.h +IdentityType2.o: /usr/include/stdlib.h /usr/include/alloca.h +IdentityType2.o: /usr/include/stdint.h +IdentityType2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +IdentityType2.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +IdentityType2.o: /usr/include/endian.h +IdentityType2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +IdentityType2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +IdentityType2.o: IdentityType2.h +IdentityType2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ImeisvRequest.o: /usr/include/stdio.h /usr/include/features.h +ImeisvRequest.o: /usr/include/libio.h /usr/include/_G_config.h +ImeisvRequest.o: /usr/include/wchar.h /usr/include/xlocale.h +ImeisvRequest.o: /usr/include/stdlib.h /usr/include/alloca.h +ImeisvRequest.o: /usr/include/stdint.h +ImeisvRequest.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ImeisvRequest.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +ImeisvRequest.o: /usr/include/endian.h +ImeisvRequest.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ImeisvRequest.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ImeisvRequest.o: ImeisvRequest.h +ImeisvRequest.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +KsiAndSequenceNumber.o: /usr/include/stdio.h /usr/include/features.h +KsiAndSequenceNumber.o: /usr/include/libio.h /usr/include/_G_config.h +KsiAndSequenceNumber.o: /usr/include/wchar.h /usr/include/xlocale.h +KsiAndSequenceNumber.o: /usr/include/stdlib.h /usr/include/alloca.h +KsiAndSequenceNumber.o: /usr/include/stdint.h +KsiAndSequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +KsiAndSequenceNumber.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +KsiAndSequenceNumber.o: /usr/include/endian.h +KsiAndSequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +KsiAndSequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +KsiAndSequenceNumber.o: KsiAndSequenceNumber.h +KsiAndSequenceNumber.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LcsClientIdentity.o: /usr/include/stdio.h /usr/include/features.h +LcsClientIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +LcsClientIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +LcsClientIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +LcsClientIdentity.o: /usr/include/stdint.h +LcsClientIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +LcsClientIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +LcsClientIdentity.o: /usr/include/endian.h +LcsClientIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +LcsClientIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LcsClientIdentity.o: LcsClientIdentity.h +LcsClientIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LcsIndicator.o: /usr/include/stdio.h /usr/include/features.h +LcsIndicator.o: /usr/include/libio.h /usr/include/_G_config.h +LcsIndicator.o: /usr/include/wchar.h /usr/include/xlocale.h +LcsIndicator.o: /usr/include/stdlib.h /usr/include/alloca.h +LcsIndicator.o: /usr/include/stdint.h +LcsIndicator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +LcsIndicator.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +LcsIndicator.o: /usr/include/endian.h +LcsIndicator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +LcsIndicator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LcsIndicator.o: LcsIndicator.h +LcsIndicator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LinkedEpsBearerIdentity.o: /usr/include/stdio.h /usr/include/features.h +LinkedEpsBearerIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +LinkedEpsBearerIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +LinkedEpsBearerIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +LinkedEpsBearerIdentity.o: /usr/include/stdint.h +LinkedEpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +LinkedEpsBearerIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +LinkedEpsBearerIdentity.o: /usr/include/endian.h +LinkedEpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +LinkedEpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LinkedEpsBearerIdentity.o: LinkedEpsBearerIdentity.h +LinkedEpsBearerIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LlcServiceAccessPointIdentifier.o: /usr/include/stdio.h +LlcServiceAccessPointIdentifier.o: /usr/include/features.h +LlcServiceAccessPointIdentifier.o: /usr/include/libio.h +LlcServiceAccessPointIdentifier.o: /usr/include/_G_config.h +LlcServiceAccessPointIdentifier.o: /usr/include/wchar.h +LlcServiceAccessPointIdentifier.o: /usr/include/xlocale.h +LlcServiceAccessPointIdentifier.o: /usr/include/stdlib.h +LlcServiceAccessPointIdentifier.o: /usr/include/alloca.h +LlcServiceAccessPointIdentifier.o: /usr/include/stdint.h +LlcServiceAccessPointIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +LlcServiceAccessPointIdentifier.o: /usr/include/arpa/inet.h +LlcServiceAccessPointIdentifier.o: /usr/include/netinet/in.h +LlcServiceAccessPointIdentifier.o: /usr/include/endian.h +LlcServiceAccessPointIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +LlcServiceAccessPointIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LlcServiceAccessPointIdentifier.o: LlcServiceAccessPointIdentifier.h +LlcServiceAccessPointIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +LocationAreaIdentification.o: /usr/include/stdio.h /usr/include/features.h +LocationAreaIdentification.o: /usr/include/libio.h /usr/include/_G_config.h +LocationAreaIdentification.o: /usr/include/wchar.h /usr/include/xlocale.h +LocationAreaIdentification.o: /usr/include/stdlib.h /usr/include/alloca.h +LocationAreaIdentification.o: /usr/include/stdint.h +LocationAreaIdentification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +LocationAreaIdentification.o: /usr/include/arpa/inet.h +LocationAreaIdentification.o: /usr/include/netinet/in.h /usr/include/endian.h +LocationAreaIdentification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +LocationAreaIdentification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +LocationAreaIdentification.o: LocationAreaIdentification.h +LocationAreaIdentification.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +MessageType.o: /usr/include/stdio.h /usr/include/features.h +MessageType.o: /usr/include/libio.h /usr/include/_G_config.h +MessageType.o: /usr/include/wchar.h /usr/include/xlocale.h +MessageType.o: /usr/include/stdlib.h /usr/include/alloca.h +MessageType.o: /usr/include/stdint.h +MessageType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +MessageType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +MessageType.o: /usr/include/endian.h +MessageType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +MessageType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MessageType.o: MessageType.h +MessageType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +MobileIdentity.o: /usr/include/stdio.h /usr/include/features.h +MobileIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +MobileIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +MobileIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +MobileIdentity.o: /usr/include/stdint.h +MobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +MobileIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +MobileIdentity.o: /usr/include/endian.h +MobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +MobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MobileIdentity.o: MobileIdentity.h +MobileIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +MobileStationClassmark2.o: /usr/include/stdio.h /usr/include/features.h +MobileStationClassmark2.o: /usr/include/libio.h /usr/include/_G_config.h +MobileStationClassmark2.o: /usr/include/wchar.h /usr/include/xlocale.h +MobileStationClassmark2.o: /usr/include/stdlib.h /usr/include/alloca.h +MobileStationClassmark2.o: /usr/include/stdint.h +MobileStationClassmark2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +MobileStationClassmark2.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +MobileStationClassmark2.o: /usr/include/endian.h +MobileStationClassmark2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +MobileStationClassmark2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MobileStationClassmark2.o: MobileStationClassmark2.h +MobileStationClassmark2.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +MobileStationClassmark3.o: /usr/include/stdio.h /usr/include/features.h +MobileStationClassmark3.o: /usr/include/libio.h /usr/include/_G_config.h +MobileStationClassmark3.o: /usr/include/wchar.h /usr/include/xlocale.h +MobileStationClassmark3.o: /usr/include/stdlib.h /usr/include/alloca.h +MobileStationClassmark3.o: /usr/include/stdint.h +MobileStationClassmark3.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +MobileStationClassmark3.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +MobileStationClassmark3.o: /usr/include/endian.h +MobileStationClassmark3.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +MobileStationClassmark3.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MobileStationClassmark3.o: MobileStationClassmark3.h +MobileStationClassmark3.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +MsNetworkCapability.o: /usr/include/stdio.h /usr/include/features.h +MsNetworkCapability.o: /usr/include/libio.h /usr/include/_G_config.h +MsNetworkCapability.o: /usr/include/wchar.h /usr/include/xlocale.h +MsNetworkCapability.o: /usr/include/stdlib.h /usr/include/alloca.h +MsNetworkCapability.o: /usr/include/stdint.h +MsNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +MsNetworkCapability.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +MsNetworkCapability.o: /usr/include/endian.h +MsNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +MsNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +MsNetworkCapability.o: MsNetworkCapability.h +MsNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +NasKeySetIdentifier.o: /usr/include/stdio.h /usr/include/features.h +NasKeySetIdentifier.o: /usr/include/libio.h /usr/include/_G_config.h +NasKeySetIdentifier.o: /usr/include/wchar.h /usr/include/xlocale.h +NasKeySetIdentifier.o: /usr/include/stdlib.h /usr/include/alloca.h +NasKeySetIdentifier.o: /usr/include/stdint.h +NasKeySetIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +NasKeySetIdentifier.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +NasKeySetIdentifier.o: /usr/include/endian.h +NasKeySetIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +NasKeySetIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +NasKeySetIdentifier.o: NasKeySetIdentifier.h +NasKeySetIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +NasMessageContainer.o: /usr/include/stdio.h /usr/include/features.h +NasMessageContainer.o: /usr/include/libio.h /usr/include/_G_config.h +NasMessageContainer.o: /usr/include/wchar.h /usr/include/xlocale.h +NasMessageContainer.o: /usr/include/stdlib.h /usr/include/alloca.h +NasMessageContainer.o: /usr/include/stdint.h +NasMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +NasMessageContainer.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +NasMessageContainer.o: /usr/include/endian.h +NasMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +NasMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +NasMessageContainer.o: NasMessageContainer.h +NasMessageContainer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +NasSecurityAlgorithms.o: /usr/include/stdio.h /usr/include/features.h +NasSecurityAlgorithms.o: /usr/include/libio.h /usr/include/_G_config.h +NasSecurityAlgorithms.o: /usr/include/wchar.h /usr/include/xlocale.h +NasSecurityAlgorithms.o: /usr/include/stdlib.h /usr/include/alloca.h +NasSecurityAlgorithms.o: /usr/include/stdint.h +NasSecurityAlgorithms.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +NasSecurityAlgorithms.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +NasSecurityAlgorithms.o: /usr/include/endian.h +NasSecurityAlgorithms.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +NasSecurityAlgorithms.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +NasSecurityAlgorithms.o: NasSecurityAlgorithms.h +NasSecurityAlgorithms.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +NetworkName.o: /usr/include/stdio.h /usr/include/features.h +NetworkName.o: /usr/include/libio.h /usr/include/_G_config.h +NetworkName.o: /usr/include/wchar.h /usr/include/xlocale.h +NetworkName.o: /usr/include/stdlib.h /usr/include/alloca.h +NetworkName.o: /usr/include/stdint.h +NetworkName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +NetworkName.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +NetworkName.o: /usr/include/endian.h +NetworkName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +NetworkName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +NetworkName.o: NetworkName.h +NetworkName.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +Nonce.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +Nonce.o: /usr/include/_G_config.h /usr/include/wchar.h /usr/include/xlocale.h +Nonce.o: /usr/include/stdlib.h /usr/include/alloca.h /usr/include/stdint.h +Nonce.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +Nonce.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +Nonce.o: /usr/include/endian.h +Nonce.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +Nonce.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +Nonce.o: Nonce.h +Nonce.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PacketFlowIdentifier.o: /usr/include/stdio.h /usr/include/features.h +PacketFlowIdentifier.o: /usr/include/libio.h /usr/include/_G_config.h +PacketFlowIdentifier.o: /usr/include/wchar.h /usr/include/xlocale.h +PacketFlowIdentifier.o: /usr/include/stdlib.h /usr/include/alloca.h +PacketFlowIdentifier.o: /usr/include/stdint.h +PacketFlowIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PacketFlowIdentifier.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PacketFlowIdentifier.o: /usr/include/endian.h +PacketFlowIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PacketFlowIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PacketFlowIdentifier.o: PacketFlowIdentifier.h +PacketFlowIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PagingIdentity.o: /usr/include/stdio.h /usr/include/features.h +PagingIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +PagingIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +PagingIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +PagingIdentity.o: /usr/include/stdint.h +PagingIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PagingIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PagingIdentity.o: /usr/include/endian.h +PagingIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PagingIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PagingIdentity.o: PagingIdentity.h +PagingIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PdnAddress.o: /usr/include/stdio.h /usr/include/features.h +PdnAddress.o: /usr/include/libio.h /usr/include/_G_config.h +PdnAddress.o: /usr/include/wchar.h /usr/include/xlocale.h +PdnAddress.o: /usr/include/stdlib.h /usr/include/alloca.h +PdnAddress.o: /usr/include/stdint.h +PdnAddress.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PdnAddress.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PdnAddress.o: /usr/include/endian.h +PdnAddress.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PdnAddress.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PdnAddress.o: PdnAddress.h +PdnAddress.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PdnType.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +PdnType.o: /usr/include/_G_config.h /usr/include/wchar.h +PdnType.o: /usr/include/xlocale.h /usr/include/stdlib.h /usr/include/alloca.h +PdnType.o: /usr/include/stdint.h +PdnType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PdnType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PdnType.o: /usr/include/endian.h +PdnType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PdnType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PdnType.o: PdnType.h +PdnType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PlmnList.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +PlmnList.o: /usr/include/_G_config.h /usr/include/wchar.h +PlmnList.o: /usr/include/xlocale.h /usr/include/stdlib.h +PlmnList.o: /usr/include/alloca.h /usr/include/stdint.h +PlmnList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PlmnList.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PlmnList.o: /usr/include/endian.h +PlmnList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PlmnList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PlmnList.o: PlmnList.h +PlmnList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ProcedureTransactionIdentity.o: /usr/include/stdio.h /usr/include/features.h +ProcedureTransactionIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +ProcedureTransactionIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +ProcedureTransactionIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +ProcedureTransactionIdentity.o: /usr/include/stdint.h +ProcedureTransactionIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ProcedureTransactionIdentity.o: /usr/include/arpa/inet.h +ProcedureTransactionIdentity.o: /usr/include/netinet/in.h +ProcedureTransactionIdentity.o: /usr/include/endian.h +ProcedureTransactionIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ProcedureTransactionIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ProcedureTransactionIdentity.o: ProcedureTransactionIdentity.h +ProcedureTransactionIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ProtocolConfigurationOptions.o: /usr/include/stdio.h /usr/include/features.h +ProtocolConfigurationOptions.o: /usr/include/libio.h /usr/include/_G_config.h +ProtocolConfigurationOptions.o: /usr/include/wchar.h /usr/include/xlocale.h +ProtocolConfigurationOptions.o: /usr/include/stdlib.h /usr/include/alloca.h +ProtocolConfigurationOptions.o: /usr/include/stdint.h +ProtocolConfigurationOptions.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ProtocolConfigurationOptions.o: /usr/include/arpa/inet.h +ProtocolConfigurationOptions.o: /usr/include/netinet/in.h +ProtocolConfigurationOptions.o: /usr/include/endian.h +ProtocolConfigurationOptions.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ProtocolConfigurationOptions.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ProtocolConfigurationOptions.o: ProtocolConfigurationOptions.h +ProtocolConfigurationOptions.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ProtocolDiscriminator.o: /usr/include/stdio.h /usr/include/features.h +ProtocolDiscriminator.o: /usr/include/libio.h /usr/include/_G_config.h +ProtocolDiscriminator.o: /usr/include/wchar.h /usr/include/xlocale.h +ProtocolDiscriminator.o: /usr/include/stdlib.h /usr/include/alloca.h +ProtocolDiscriminator.o: /usr/include/stdint.h +ProtocolDiscriminator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ProtocolDiscriminator.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +ProtocolDiscriminator.o: /usr/include/endian.h +ProtocolDiscriminator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ProtocolDiscriminator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ProtocolDiscriminator.o: ProtocolDiscriminator.h +ProtocolDiscriminator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +PTmsiSignature.o: /usr/include/stdio.h /usr/include/features.h +PTmsiSignature.o: /usr/include/libio.h /usr/include/_G_config.h +PTmsiSignature.o: /usr/include/wchar.h /usr/include/xlocale.h +PTmsiSignature.o: /usr/include/stdlib.h /usr/include/alloca.h +PTmsiSignature.o: /usr/include/stdint.h +PTmsiSignature.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +PTmsiSignature.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +PTmsiSignature.o: /usr/include/endian.h +PTmsiSignature.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +PTmsiSignature.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +PTmsiSignature.o: PTmsiSignature.h +PTmsiSignature.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +QualityOfService.o: /usr/include/stdio.h /usr/include/features.h +QualityOfService.o: /usr/include/libio.h /usr/include/_G_config.h +QualityOfService.o: /usr/include/wchar.h /usr/include/xlocale.h +QualityOfService.o: /usr/include/stdlib.h /usr/include/alloca.h +QualityOfService.o: /usr/include/stdint.h +QualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +QualityOfService.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +QualityOfService.o: /usr/include/endian.h +QualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +QualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +QualityOfService.o: QualityOfService.h +QualityOfService.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +RadioPriority.o: /usr/include/stdio.h /usr/include/features.h +RadioPriority.o: /usr/include/libio.h /usr/include/_G_config.h +RadioPriority.o: /usr/include/wchar.h /usr/include/xlocale.h +RadioPriority.o: /usr/include/stdlib.h /usr/include/alloca.h +RadioPriority.o: /usr/include/stdint.h +RadioPriority.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +RadioPriority.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +RadioPriority.o: /usr/include/endian.h +RadioPriority.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +RadioPriority.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +RadioPriority.o: RadioPriority.h +RadioPriority.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +RequestType.o: /usr/include/stdio.h /usr/include/features.h +RequestType.o: /usr/include/libio.h /usr/include/_G_config.h +RequestType.o: /usr/include/wchar.h /usr/include/xlocale.h +RequestType.o: /usr/include/stdlib.h /usr/include/alloca.h +RequestType.o: /usr/include/stdint.h +RequestType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +RequestType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +RequestType.o: /usr/include/endian.h +RequestType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +RequestType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +RequestType.o: RequestType.h +RequestType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +SecurityHeaderType.o: /usr/include/stdio.h /usr/include/features.h +SecurityHeaderType.o: /usr/include/libio.h /usr/include/_G_config.h +SecurityHeaderType.o: /usr/include/wchar.h /usr/include/xlocale.h +SecurityHeaderType.o: /usr/include/stdlib.h /usr/include/alloca.h +SecurityHeaderType.o: /usr/include/stdint.h +SecurityHeaderType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +SecurityHeaderType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +SecurityHeaderType.o: /usr/include/endian.h +SecurityHeaderType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +SecurityHeaderType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +SecurityHeaderType.o: SecurityHeaderType.h +SecurityHeaderType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ServiceType.o: /usr/include/stdio.h /usr/include/features.h +ServiceType.o: /usr/include/libio.h /usr/include/_G_config.h +ServiceType.o: /usr/include/wchar.h /usr/include/xlocale.h +ServiceType.o: /usr/include/stdlib.h /usr/include/alloca.h +ServiceType.o: /usr/include/stdint.h +ServiceType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ServiceType.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +ServiceType.o: /usr/include/endian.h +ServiceType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ServiceType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ServiceType.o: ServiceType.h +ServiceType.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ShortMac.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +ShortMac.o: /usr/include/_G_config.h /usr/include/wchar.h +ShortMac.o: /usr/include/xlocale.h /usr/include/stdlib.h +ShortMac.o: /usr/include/alloca.h /usr/include/stdint.h +ShortMac.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +ShortMac.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +ShortMac.o: /usr/include/endian.h +ShortMac.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +ShortMac.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +ShortMac.o: ShortMac.h +ShortMac.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +SsCode.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +SsCode.o: /usr/include/_G_config.h /usr/include/wchar.h +SsCode.o: /usr/include/xlocale.h /usr/include/stdlib.h /usr/include/alloca.h +SsCode.o: /usr/include/stdint.h +SsCode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +SsCode.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +SsCode.o: /usr/include/endian.h +SsCode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +SsCode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +SsCode.o: SsCode.h +SsCode.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +SupportedCodecList.o: /usr/include/stdio.h /usr/include/features.h +SupportedCodecList.o: /usr/include/libio.h /usr/include/_G_config.h +SupportedCodecList.o: /usr/include/wchar.h /usr/include/xlocale.h +SupportedCodecList.o: /usr/include/stdlib.h /usr/include/alloca.h +SupportedCodecList.o: /usr/include/stdint.h +SupportedCodecList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +SupportedCodecList.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +SupportedCodecList.o: /usr/include/endian.h +SupportedCodecList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +SupportedCodecList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +SupportedCodecList.o: SupportedCodecList.h +SupportedCodecList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TimeZoneAndTime.o: /usr/include/stdio.h /usr/include/features.h +TimeZoneAndTime.o: /usr/include/libio.h /usr/include/_G_config.h +TimeZoneAndTime.o: /usr/include/wchar.h /usr/include/xlocale.h +TimeZoneAndTime.o: /usr/include/stdlib.h /usr/include/alloca.h +TimeZoneAndTime.o: /usr/include/stdint.h +TimeZoneAndTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TimeZoneAndTime.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TimeZoneAndTime.o: /usr/include/endian.h +TimeZoneAndTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TimeZoneAndTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TimeZoneAndTime.o: TimeZoneAndTime.h +TimeZoneAndTime.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TimeZone.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +TimeZone.o: /usr/include/_G_config.h /usr/include/wchar.h +TimeZone.o: /usr/include/xlocale.h /usr/include/stdlib.h +TimeZone.o: /usr/include/alloca.h /usr/include/stdint.h +TimeZone.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TimeZone.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TimeZone.o: /usr/include/endian.h +TimeZone.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TimeZone.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TimeZone.o: TimeZone.h +TimeZone.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TmsiStatus.o: /usr/include/stdio.h /usr/include/features.h +TmsiStatus.o: /usr/include/libio.h /usr/include/_G_config.h +TmsiStatus.o: /usr/include/wchar.h /usr/include/xlocale.h +TmsiStatus.o: /usr/include/stdlib.h /usr/include/alloca.h +TmsiStatus.o: /usr/include/stdint.h +TmsiStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TmsiStatus.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TmsiStatus.o: /usr/include/endian.h +TmsiStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TmsiStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TmsiStatus.o: TmsiStatus.h +TmsiStatus.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TrackingAreaIdentity.o: /usr/include/stdio.h /usr/include/features.h +TrackingAreaIdentity.o: /usr/include/libio.h /usr/include/_G_config.h +TrackingAreaIdentity.o: /usr/include/wchar.h /usr/include/xlocale.h +TrackingAreaIdentity.o: /usr/include/stdlib.h /usr/include/alloca.h +TrackingAreaIdentity.o: /usr/include/stdint.h +TrackingAreaIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TrackingAreaIdentity.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TrackingAreaIdentity.o: /usr/include/endian.h +TrackingAreaIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TrackingAreaIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TrackingAreaIdentity.o: TrackingAreaIdentity.h +TrackingAreaIdentity.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TrackingAreaIdentityList.o: /usr/include/stdio.h /usr/include/features.h +TrackingAreaIdentityList.o: /usr/include/libio.h /usr/include/_G_config.h +TrackingAreaIdentityList.o: /usr/include/wchar.h /usr/include/xlocale.h +TrackingAreaIdentityList.o: /usr/include/stdlib.h /usr/include/alloca.h +TrackingAreaIdentityList.o: /usr/include/stdint.h +TrackingAreaIdentityList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TrackingAreaIdentityList.o: /usr/include/arpa/inet.h +TrackingAreaIdentityList.o: /usr/include/netinet/in.h /usr/include/endian.h +TrackingAreaIdentityList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TrackingAreaIdentityList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TrackingAreaIdentityList.o: TrackingAreaIdentityList.h +TrackingAreaIdentityList.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TrafficFlowAggregateDescription.o: /usr/include/stdio.h +TrafficFlowAggregateDescription.o: /usr/include/features.h +TrafficFlowAggregateDescription.o: /usr/include/libio.h +TrafficFlowAggregateDescription.o: /usr/include/_G_config.h +TrafficFlowAggregateDescription.o: /usr/include/wchar.h +TrafficFlowAggregateDescription.o: /usr/include/xlocale.h +TrafficFlowAggregateDescription.o: /usr/include/stdlib.h +TrafficFlowAggregateDescription.o: /usr/include/alloca.h +TrafficFlowAggregateDescription.o: /usr/include/stdint.h +TrafficFlowAggregateDescription.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TrafficFlowAggregateDescription.o: /usr/include/arpa/inet.h +TrafficFlowAggregateDescription.o: /usr/include/netinet/in.h +TrafficFlowAggregateDescription.o: /usr/include/endian.h +TrafficFlowAggregateDescription.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TrafficFlowAggregateDescription.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TrafficFlowAggregateDescription.o: TrafficFlowAggregateDescription.h +TrafficFlowAggregateDescription.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +TrafficFlowTemplate.o: /usr/include/stdio.h /usr/include/features.h +TrafficFlowTemplate.o: /usr/include/libio.h /usr/include/_G_config.h +TrafficFlowTemplate.o: /usr/include/wchar.h /usr/include/xlocale.h +TrafficFlowTemplate.o: /usr/include/stdlib.h /usr/include/alloca.h +TrafficFlowTemplate.o: /usr/include/stdint.h +TrafficFlowTemplate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TrafficFlowTemplate.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TrafficFlowTemplate.o: /usr/include/endian.h +TrafficFlowTemplate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TrafficFlowTemplate.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TrafficFlowTemplate.o: TrafficFlowTemplate.h +TransactionIdentifier.o: /usr/include/stdio.h /usr/include/features.h +TransactionIdentifier.o: /usr/include/libio.h /usr/include/_G_config.h +TransactionIdentifier.o: /usr/include/wchar.h /usr/include/xlocale.h +TransactionIdentifier.o: /usr/include/stdlib.h /usr/include/alloca.h +TransactionIdentifier.o: /usr/include/stdint.h +TransactionIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +TransactionIdentifier.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TransactionIdentifier.o: /usr/include/endian.h +TransactionIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +TransactionIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +TransactionIdentifier.o: TransactionIdentifier.h +TransactionIdentifier.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +UeNetworkCapability.o: /usr/include/stdio.h /usr/include/features.h +UeNetworkCapability.o: /usr/include/libio.h /usr/include/_G_config.h +UeNetworkCapability.o: /usr/include/wchar.h /usr/include/xlocale.h +UeNetworkCapability.o: /usr/include/stdlib.h /usr/include/alloca.h +UeNetworkCapability.o: /usr/include/stdint.h +UeNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +UeNetworkCapability.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +UeNetworkCapability.o: /usr/include/endian.h +UeNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +UeNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +UeNetworkCapability.o: UeNetworkCapability.h +UeNetworkCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/stdio.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/features.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/libio.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/_G_config.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/wchar.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/xlocale.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/stdlib.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/alloca.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/stdint.h +UeRadioCapabilityInformationUpdateNeeded.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/arpa/inet.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/netinet/in.h +UeRadioCapabilityInformationUpdateNeeded.o: /usr/include/endian.h +UeRadioCapabilityInformationUpdateNeeded.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +UeRadioCapabilityInformationUpdateNeeded.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +UeRadioCapabilityInformationUpdateNeeded.o: UeRadioCapabilityInformationUpdateNeeded.h +UeRadioCapabilityInformationUpdateNeeded.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +UeSecurityCapability.o: /usr/include/stdio.h /usr/include/features.h +UeSecurityCapability.o: /usr/include/libio.h /usr/include/_G_config.h +UeSecurityCapability.o: /usr/include/wchar.h /usr/include/xlocale.h +UeSecurityCapability.o: /usr/include/stdlib.h /usr/include/alloca.h +UeSecurityCapability.o: /usr/include/stdint.h +UeSecurityCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVEncoder.h +UeSecurityCapability.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +UeSecurityCapability.o: /usr/include/endian.h +UeSecurityCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/TLVDecoder.h +UeSecurityCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +UeSecurityCapability.o: UeSecurityCapability.h +UeSecurityCapability.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.c new file mode 100644 index 0000000000..c13dc08462 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "MessageType.h" + +int decode_message_type(MessageType *messagetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_message_type(MessageType *messagetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.h new file mode 100644 index 0000000000..cb96e8e489 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MessageType.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef MESSAGE_TYPE_H_ +#define MESSAGE_TYPE_H_ + +#define MESSAGE_TYPE_MINIMUM_LENGTH 1 +#define MESSAGE_TYPE_MAXIMUM_LENGTH 1 + +typedef uint8_t MessageType; + +int encode_message_type(MessageType *messagetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_message_type_xml(MessageType *messagetype, uint8_t iei); + +int decode_message_type(MessageType *messagetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* MESSAGE TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.c new file mode 100644 index 0000000000..6a620e339b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.c @@ -0,0 +1,632 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "MobileIdentity.h" + +static int decode_imsi_mobile_identity(ImsiMobileIdentity_t *imsi, uint8_t *buffer); +static int decode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buffer); +static int decode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer); +static int decode_tmsi_mobile_identity(TmsiMobileIdentity_t *tmsi, uint8_t *buffer); +static int decode_tmgi_mobile_identity(TmgiMobileIdentity_t *tmgi, uint8_t *buffer); +static int decode_no_mobile_identity(NoMobileIdentity_t *no_id, uint8_t *buffer); + +static int encode_imsi_mobile_identity(ImsiMobileIdentity_t *imsi, uint8_t *buffer); +static int encode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buffer); +static int encode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer); +static int encode_tmsi_mobile_identity(TmsiMobileIdentity_t *tmsi, uint8_t *buffer); +static int encode_tmgi_mobile_identity(TmgiMobileIdentity_t *tmgi, uint8_t *buffer); +static int encode_no_mobile_identity(NoMobileIdentity_t *no_id, uint8_t *buffer); + +int decode_mobile_identity(MobileIdentity *mobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded_rc = TLV_DECODE_VALUE_DOESNT_MATCH; + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + + uint8_t typeofidentity = *(buffer + decoded) & 0x7; + if (typeofidentity != MOBILE_IDENTITY_NOT_AVAILABLE) { + CHECK_LENGTH_DECODER(len - decoded, ielen); + if (typeofidentity == MOBILE_IDENTITY_IMSI) { + decoded_rc = decode_imsi_mobile_identity(&mobileidentity->imsi, + buffer + decoded); + } else if (typeofidentity == MOBILE_IDENTITY_IMEI) { + decoded_rc = decode_imei_mobile_identity(&mobileidentity->imei, + buffer + decoded); + } else if (typeofidentity == MOBILE_IDENTITY_IMEISV) { + decoded_rc = decode_imeisv_mobile_identity(&mobileidentity->imeisv, + buffer + decoded); + } else if (typeofidentity == MOBILE_IDENTITY_TMSI) { + decoded_rc = decode_tmsi_mobile_identity(&mobileidentity->tmsi, + buffer + decoded); + } else if (typeofidentity == MOBILE_IDENTITY_TMGI) { + decoded_rc = decode_tmgi_mobile_identity(&mobileidentity->tmgi, + buffer + decoded); + } + } else if (ielen == MOBILE_IDENTITY_NOT_AVAILABLE_LTE_LENGTH) { + decoded_rc = decode_no_mobile_identity(&mobileidentity->no_id, + buffer + decoded); + } + + if (decoded_rc < 0) { + return decoded_rc; + } +#if defined (NAS_DEBUG) + dump_mobile_identity_xml(mobileidentity, iei); +#endif + return (decoded + decoded_rc); +} + +int encode_mobile_identity(MobileIdentity *mobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + int encoded_rc = TLV_ENCODE_VALUE_DOESNT_MATCH; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MOBILE_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_mobile_identity_xml(mobileidentity, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + + if (mobileidentity->no_id.typeofidentity != MOBILE_IDENTITY_NOT_AVAILABLE) { + if (mobileidentity->imsi.typeofidentity == MOBILE_IDENTITY_IMSI) + { + encoded_rc = encode_imsi_mobile_identity(&mobileidentity->imsi, + buffer + encoded); + } + else if (mobileidentity->imei.typeofidentity == MOBILE_IDENTITY_IMEI) + { + encoded_rc = encode_imei_mobile_identity(&mobileidentity->imei, + buffer + encoded); + } + else if (mobileidentity->imeisv.typeofidentity == MOBILE_IDENTITY_IMEISV) + { + encoded_rc = encode_imeisv_mobile_identity(&mobileidentity->imeisv, + buffer + encoded); + } + else if (mobileidentity->tmsi.typeofidentity == MOBILE_IDENTITY_TMSI) + { + encoded_rc = encode_tmsi_mobile_identity(&mobileidentity->tmsi, + buffer + encoded); + } + else if (mobileidentity->tmgi.typeofidentity == MOBILE_IDENTITY_TMGI) + { + encoded_rc = encode_tmgi_mobile_identity(&mobileidentity->tmgi, + buffer + encoded); + } + if (encoded_rc > 0) { + *lenPtr = encoded + encoded_rc - 1 - ((iei > 0) ? 1 : 0); + } + } else { + encoded_rc = encode_no_mobile_identity(&mobileidentity->no_id, + buffer + encoded); + if (encoded_rc > 0) { + *lenPtr = MOBILE_IDENTITY_NOT_AVAILABLE_LTE_LENGTH; + } + } + + if (encoded_rc < 0) { + return encoded_rc; + } + return (encoded + encoded_rc); +} + +void dump_mobile_identity_xml(MobileIdentity *mobileidentity, uint8_t iei) +{ + printf("<Mobile Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + + if (mobileidentity->imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + ImsiMobileIdentity_t* imsi = &mobileidentity->imsi; + printf(" <odd even>%u</odd even>\n", imsi->oddeven); + printf(" <Type of identity>IMSI</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", imsi->digit1); + printf(" <digit2>%u</digit2>\n", imsi->digit2); + printf(" <digit3>%u</digit3>\n", imsi->digit3); + printf(" <digit4>%u</digit4>\n", imsi->digit4); + printf(" <digit5>%u</digit5>\n", imsi->digit5); + printf(" <digit6>%u</digit6>\n", imsi->digit6); + printf(" <digit7>%u</digit7>\n", imsi->digit7); + printf(" <digit8>%u</digit8>\n", imsi->digit8); + printf(" <digit9>%u</digit9>\n", imsi->digit9); + printf(" <digit10>%u</digit10>\n", imsi->digit10); + printf(" <digit11>%u</digit11>\n", imsi->digit11); + printf(" <digit12>%u</digit12>\n", imsi->digit12); + printf(" <digit13>%u</digit13>\n", imsi->digit13); + printf(" <digit14>%u</digit14>\n", imsi->digit14); + printf(" <digit15>%u</digit15>\n", imsi->digit15); + } + else if (mobileidentity->imei.typeofidentity == MOBILE_IDENTITY_IMEI) { + ImeiMobileIdentity_t* imei = &mobileidentity->imei; + printf(" <odd even>%u</odd even>\n", imei->oddeven); + printf(" <Type of identity>IMEI</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", imei->digit1); + printf(" <digit2>%u</digit2>\n", imei->digit2); + printf(" <digit3>%u</digit3>\n", imei->digit3); + printf(" <digit4>%u</digit4>\n", imei->digit4); + printf(" <digit5>%u</digit5>\n", imei->digit5); + printf(" <digit6>%u</digit6>\n", imei->digit6); + printf(" <digit7>%u</digit7>\n", imei->digit7); + printf(" <digit8>%u</digit8>\n", imei->digit8); + printf(" <digit9>%u</digit9>\n", imei->digit9); + printf(" <digit10>%u</digit10>\n", imei->digit10); + printf(" <digit11>%u</digit11>\n", imei->digit11); + printf(" <digit12>%u</digit12>\n", imei->digit12); + printf(" <digit13>%u</digit13>\n", imei->digit13); + printf(" <digit14>%u</digit14>\n", imei->digit14); + printf(" <digit15>%u</digit15>\n", imei->digit15); + } + else if (mobileidentity->imeisv.typeofidentity == MOBILE_IDENTITY_IMEISV) { + ImeisvMobileIdentity_t* imeisv = &mobileidentity->imeisv; + printf(" <odd even>%u</odd even>\n", imeisv->oddeven); + printf(" <Type of identity>IMEISV</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", imeisv->digit1); + printf(" <digit2>%u</digit2>\n", imeisv->digit2); + printf(" <digit3>%u</digit3>\n", imeisv->digit3); + printf(" <digit4>%u</digit4>\n", imeisv->digit4); + printf(" <digit5>%u</digit5>\n", imeisv->digit5); + printf(" <digit6>%u</digit6>\n", imeisv->digit6); + printf(" <digit7>%u</digit7>\n", imeisv->digit7); + printf(" <digit8>%u</digit8>\n", imeisv->digit8); + printf(" <digit9>%u</digit9>\n", imeisv->digit9); + printf(" <digit10>%u</digit10>\n", imeisv->digit10); + printf(" <digit11>%u</digit11>\n", imeisv->digit11); + printf(" <digit12>%u</digit12>\n", imeisv->digit12); + printf(" <digit13>%u</digit13>\n", imeisv->digit13); + printf(" <digit14>%u</digit14>\n", imeisv->digit14); + printf(" <digit15>%u</digit15>\n", imeisv->digit15); + } + else if (mobileidentity->tmsi.typeofidentity == MOBILE_IDENTITY_TMSI) { + TmsiMobileIdentity_t* tmsi = &mobileidentity->tmsi; + printf(" <odd even>%u</odd even>\n", tmsi->oddeven); + printf(" <Type of identity>TMSI</Type of identity>\n"); + printf(" <digit1>%u</digit1>\n", tmsi->digit1); + printf(" <digit2>%u</digit2>\n", tmsi->digit2); + printf(" <digit3>%u</digit3>\n", tmsi->digit3); + printf(" <digit4>%u</digit4>\n", tmsi->digit4); + printf(" <digit5>%u</digit5>\n", tmsi->digit5); + printf(" <digit6>%u</digit6>\n", tmsi->digit6); + printf(" <digit7>%u</digit7>\n", tmsi->digit7); + printf(" <digit8>%u</digit8>\n", tmsi->digit8); + printf(" <digit9>%u</digit9>\n", tmsi->digit9); + printf(" <digit10>%u</digit10>\n", tmsi->digit10); + printf(" <digit11>%u</digit11>\n", tmsi->digit11); + printf(" <digit12>%u</digit12>\n", tmsi->digit12); + printf(" <digit13>%u</digit13>\n", tmsi->digit13); + printf(" <digit14>%u</digit14>\n", tmsi->digit14); + printf(" <digit15>%u</digit15>\n", tmsi->digit15); + } + else if (mobileidentity->tmgi.typeofidentity == MOBILE_IDENTITY_TMGI) { + TmgiMobileIdentity_t* tmgi = &mobileidentity->tmgi; + printf(" <MBMS session ID indication>%u</MBMS session ID indication>\n", tmgi->mbmssessionidindication); + printf(" <MCC MNC indication>%u</MCC MNC indication>\n", + tmgi->mccmncindication); + printf(" <Odd even>%u</Odd even>\n", + tmgi->oddeven); + printf(" <Type of identity>TMGI</Type of identity>\n"); + printf(" <MBMS service ID>%u</MBMS service ID>\n", + tmgi->mbmsserviceid); + printf(" <MCC digit 2>%u</MCC digit 2>\n", tmgi->mccdigit2); + printf(" <MCC digit 1>%u</MCC digit 1>\n", tmgi->mccdigit1); + printf(" <MNC digit 3>%u</MNC digit 3>\n", tmgi->mncdigit3); + printf(" <MCC digit 3>%u</MCC digit 3>\n", tmgi->mccdigit3); + printf(" <MNC digit 2>%u</MNC digit 2>\n", tmgi->mncdigit2); + printf(" <MNC digit 1>%u</MNC digit 1>\n", tmgi->mncdigit1); + printf(" <MBMS session ID>%u</MBMS session ID>\n", + tmgi->mbmssessionid); + } + else { + printf(" Wrong type of mobile identity (%u)\n", mobileidentity->imsi.typeofidentity); + } + printf("</Mobile Identity>\n"); +} + +static int decode_imsi_mobile_identity(ImsiMobileIdentity_t *imsi, uint8_t *buffer) +{ + int decoded = 0; + imsi->typeofidentity = *(buffer + decoded) & 0x7; + if (imsi->typeofidentity != MOBILE_IDENTITY_IMSI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + imsi->oddeven = (*(buffer + decoded) >> 3) & 0x1; + imsi->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit2 = *(buffer + decoded) & 0xf; + imsi->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit4 = *(buffer + decoded) & 0xf; + imsi->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit6 = *(buffer + decoded) & 0xf; + imsi->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit8 = *(buffer + decoded) & 0xf; + imsi->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit10 = *(buffer + decoded) & 0xf; + imsi->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit12 = *(buffer + decoded) & 0xf; + imsi->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imsi->digit14 = *(buffer + decoded) & 0xf; + imsi->digit15 = (*(buffer + decoded) >> 4) & 0xf; + /* + * IMSI is coded using BCD coding. If the number of identity digits is + * even then bits 5 to 8 of the last octet shall be filled with an end + * mark coded as "1111". + */ + if ((imsi->oddeven == MOBILE_IDENTITY_EVEN) && (imsi->digit15 != 0x0f)) + { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + return decoded; +} + +static int decode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buffer) +{ + int decoded = 0; + imei->typeofidentity = *(buffer + decoded) & 0x7; + if (imei->typeofidentity != MOBILE_IDENTITY_IMEI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + imei->oddeven = (*(buffer + decoded) >> 3) & 0x1; + imei->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit2 = *(buffer + decoded) & 0xf; + imei->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit4 = *(buffer + decoded) & 0xf; + imei->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit6 = *(buffer + decoded) & 0xf; + imei->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit8 = *(buffer + decoded) & 0xf; + imei->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit10 = *(buffer + decoded) & 0xf; + imei->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit12 = *(buffer + decoded) & 0xf; + imei->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imei->digit14 = *(buffer + decoded) & 0xf; + imei->digit15 = (*(buffer + decoded) >> 4) & 0xf; + /* + * IMEI is coded using BCD coding. If the number of identity digits is + * even then bits 5 to 8 of the last octet shall be filled with an end + * mark coded as "1111". + */ + if ((imei->oddeven == MOBILE_IDENTITY_EVEN) && (imei->digit15 != 0x0f)) + { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + return decoded; +} + +static int decode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer) +{ + int decoded = 0; + imeisv->typeofidentity = *(buffer + decoded) & 0x7; + if (imeisv->typeofidentity != MOBILE_IDENTITY_IMEISV) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + imeisv->oddeven = (*(buffer + decoded) >> 3) & 0x1; + imeisv->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit2 = *(buffer + decoded) & 0xf; + imeisv->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit4 = *(buffer + decoded) & 0xf; + imeisv->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit6 = *(buffer + decoded) & 0xf; + imeisv->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit8 = *(buffer + decoded) & 0xf; + imeisv->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit10 = *(buffer + decoded) & 0xf; + imeisv->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit12 = *(buffer + decoded) & 0xf; + imeisv->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + imeisv->digit14 = *(buffer + decoded) & 0xf; + imeisv->digit15 = (*(buffer + decoded) >> 4) & 0xf; + /* + * IMEISV is coded using BCD coding. If the number of identity digits is + * even then bits 5 to 8 of the last octet shall be filled with an end + * mark coded as "1111". + */ + if ((imeisv->oddeven == MOBILE_IDENTITY_EVEN) && (imeisv->digit15 != 0x0f)) + { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + return decoded; +} + +static int decode_tmsi_mobile_identity(TmsiMobileIdentity_t *tmsi, uint8_t *buffer) +{ + int decoded = 0; + tmsi->typeofidentity = *(buffer + decoded) & 0x7; + if (tmsi->typeofidentity != MOBILE_IDENTITY_TMSI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + tmsi->oddeven = (*(buffer + decoded) >> 3) & 0x1; + tmsi->digit1 = (*(buffer + decoded) >> 4) & 0xf; + /* + * If the mobile identity is the TMSI/P-TMSI/M-TMSI then bits 5 to 8 + * of octet 3 are coded as "1111". + */ + if (tmsi->digit1 != 0xf) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + tmsi->digit2 = *(buffer + decoded) & 0xf; + tmsi->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit4 = *(buffer + decoded) & 0xf; + tmsi->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit6 = *(buffer + decoded) & 0xf; + tmsi->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit8 = *(buffer + decoded) & 0xf; + tmsi->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit10 = *(buffer + decoded) & 0xf; + tmsi->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit12 = *(buffer + decoded) & 0xf; + tmsi->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + tmsi->digit14 = *(buffer + decoded) & 0xf; + tmsi->digit15 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + return decoded; +} + +static int decode_tmgi_mobile_identity(TmgiMobileIdentity_t *tmgi, uint8_t *buffer) +{ + int decoded = 0; + tmgi->spare = (*(buffer + decoded) >> 6) & 0x2; + /* + * Spare bits are coded with 0s + */ + if (tmgi->spare != 0) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + tmgi->mbmssessionidindication = (*(buffer + decoded) >> 5) & 0x1; + tmgi->mccmncindication = (*(buffer + decoded) >> 4) & 0x1; + tmgi->oddeven = (*(buffer + decoded) >> 3) & 0x1; + tmgi->typeofidentity = *(buffer + decoded) & 0x7; + if (tmgi->typeofidentity != MOBILE_IDENTITY_TMGI) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + decoded++; + //IES_DECODE_U24(tmgi->mbmsserviceid, *(buffer + decoded)); + IES_DECODE_U24(buffer, decoded, tmgi->mbmsserviceid); + tmgi->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + tmgi->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + tmgi->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + tmgi->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + tmgi->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + tmgi->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; + tmgi->mbmssessionid = *(buffer + decoded); + decoded++; + return decoded; +} + +static int decode_no_mobile_identity(NoMobileIdentity_t *no_id, uint8_t *buffer) +{ + int decoded = 0; + no_id->typeofidentity = *(buffer + decoded) & 0x7; + if (no_id->typeofidentity != MOBILE_IDENTITY_NOT_AVAILABLE) { + return (TLV_ENCODE_VALUE_DOESNT_MATCH); + } + no_id->oddeven = (*(buffer + decoded) >> 3) & 0x1; + no_id->digit1 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit2 = *(buffer + decoded) & 0xf; + no_id->digit3 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit4 = *(buffer + decoded) & 0xf; + no_id->digit5 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit6 = *(buffer + decoded) & 0xf; + no_id->digit7 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit8 = *(buffer + decoded) & 0xf; + no_id->digit9 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit10 = *(buffer + decoded) & 0xf; + no_id->digit11 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit12 = *(buffer + decoded) & 0xf; + no_id->digit13 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + no_id->digit14 = *(buffer + decoded) & 0xf; + no_id->digit15 = (*(buffer + decoded) >> 4) & 0xf; + decoded++; + return decoded; +} + +static int encode_imsi_mobile_identity(ImsiMobileIdentity_t *imsi, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | (imsi->digit1 << 4) | (imsi->oddeven << 3) | + (imsi->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit3 << 4) | imsi->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit5 << 4) | imsi->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit7 << 4) | imsi->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit9 << 4) | imsi->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit11 << 4) | imsi->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (imsi->digit13 << 4) | imsi->digit12; + encoded++; + if (imsi->oddeven != MOBILE_IDENTITY_EVEN) { + *(buffer + encoded) = 0x00 | (imsi->digit15 << 4) | imsi->digit14; + } + else { + *(buffer + encoded) = 0xf0 | imsi->digit14; + } + encoded++; + return encoded; +} + +static int encode_imei_mobile_identity(ImeiMobileIdentity_t *imei, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | (imei->digit1 << 4) | (imei->oddeven << 3) | + (imei->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit3 << 4) | imei->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit5 << 4) | imei->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit7 << 4) | imei->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit9 << 4) | imei->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit11 << 4) | imei->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (imei->digit13 << 4) | imei->digit12; + encoded++; + if (imei->oddeven != MOBILE_IDENTITY_EVEN) { + *(buffer + encoded) = 0x00 | (imei->digit15 << 4) | imei->digit14; + } + else { + *(buffer + encoded) = 0xf0 | imei->digit14; + } + encoded++; + return encoded; +} + +static int encode_imeisv_mobile_identity(ImeisvMobileIdentity_t *imeisv, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | (imeisv->digit1 << 4) | (imeisv->oddeven << 3) | + (imeisv->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit3 << 4) | imeisv->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit5 << 4) | imeisv->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit7 << 4) | imeisv->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit9 << 4) | imeisv->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit11 << 4) | imeisv->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (imeisv->digit13 << 4) | imeisv->digit12; + encoded++; + if (imeisv->oddeven != MOBILE_IDENTITY_EVEN) { + *(buffer + encoded) = 0x00 | (imeisv->digit15 << 4) | imeisv->digit14; + } + else { + *(buffer + encoded) = 0xf0 | imeisv->digit14; + } + encoded++; + return encoded; +} + +static int encode_tmsi_mobile_identity(TmsiMobileIdentity_t *tmsi, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0xf0 | (tmsi->oddeven << 3) | (tmsi->typeofidentity); + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit3 << 4) | tmsi->digit2; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit5 << 4) | tmsi->digit4; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit7 << 4) | tmsi->digit6; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit9 << 4) | tmsi->digit8; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit11 << 4) | tmsi->digit10; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit13 << 4) | tmsi->digit12; + encoded++; + *(buffer + encoded) = 0x00 | (tmsi->digit15 << 4) | tmsi->digit14; + encoded++; + return encoded; +} + +static int encode_tmgi_mobile_identity(TmgiMobileIdentity_t *tmgi, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = 0x00 | + ((tmgi->mbmssessionidindication & 0x1) << 5) | + ((tmgi->mccmncindication & 0x1) << 4) | + ((tmgi->oddeven & 0x1) << 3) | + (tmgi->typeofidentity & 0x7); + encoded++; + IES_ENCODE_U24(buffer, encoded, tmgi->mbmsserviceid); + *(buffer + encoded) = 0x00 | ((tmgi->mccdigit2 & 0xf) << 4) | + (tmgi->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((tmgi->mncdigit3 & 0xf) << 4) | + (tmgi->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((tmgi->mncdigit2 & 0xf) << 4) | + (tmgi->mncdigit1 & 0xf); + encoded++; + *(buffer + encoded) = tmgi->mbmssessionid; + encoded++; + return encoded; +} + +static int encode_no_mobile_identity(NoMobileIdentity_t *no_id, uint8_t *buffer) +{ + uint32_t encoded = 0; + *(buffer + encoded) = no_id->typeofidentity; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + *(buffer + encoded) = 0x00; + encoded++; + return encoded; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.h new file mode 100644 index 0000000000..fae50d5048 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileIdentity.h @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef MOBILE_IDENTITY_H_ +#define MOBILE_IDENTITY_H_ + +#define MOBILE_IDENTITY_MINIMUM_LENGTH 3 +#define MOBILE_IDENTITY_MAXIMUM_LENGTH 11 + +#define MOBILE_IDENTITY_NOT_AVAILABLE_GSM_LENGTH 1 +#define MOBILE_IDENTITY_NOT_AVAILABLE_GPRS_LENGTH 3 +#define MOBILE_IDENTITY_NOT_AVAILABLE_LTE_LENGTH 3 + +typedef struct { + uint8_t digit1:4; + uint8_t oddeven:1; + uint8_t typeofidentity:3; + uint8_t digit2:4; + uint8_t digit3:4; + uint8_t digit4:4; + uint8_t digit5:4; + uint8_t digit6:4; + uint8_t digit7:4; + uint8_t digit8:4; + uint8_t digit9:4; + uint8_t digit10:4; + uint8_t digit11:4; + uint8_t digit12:4; + uint8_t digit13:4; + uint8_t digit14:4; + uint8_t digit15:4; +} ImsiMobileIdentity_t; + +typedef struct { + uint8_t spare:2; + uint8_t mbmssessionidindication:1; + uint8_t mccmncindication:1; +#define MOBILE_IDENTITY_EVEN 0 +#define MOBILE_IDENTITY_ODD 1 + uint8_t oddeven:1; + uint8_t typeofidentity:3; + uint32_t mbmsserviceid; + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; + uint8_t mbmssessionid; +} TmgiMobileIdentity_t; + +typedef ImsiMobileIdentity_t ImeiMobileIdentity_t; +typedef ImsiMobileIdentity_t ImeisvMobileIdentity_t; +typedef ImsiMobileIdentity_t TmsiMobileIdentity_t; +typedef ImsiMobileIdentity_t NoMobileIdentity_t; + +typedef union MobileIdentity_tag { +#define MOBILE_IDENTITY_IMSI 0b001 +#define MOBILE_IDENTITY_IMEI 0b010 +#define MOBILE_IDENTITY_IMEISV 0b011 +#define MOBILE_IDENTITY_TMSI 0b100 +#define MOBILE_IDENTITY_TMGI 0b101 +#define MOBILE_IDENTITY_NOT_AVAILABLE 0b000 + ImsiMobileIdentity_t imsi; + ImeiMobileIdentity_t imei; + ImeisvMobileIdentity_t imeisv; + TmsiMobileIdentity_t tmsi; + TmgiMobileIdentity_t tmgi; + NoMobileIdentity_t no_id; +} MobileIdentity; + +int encode_mobile_identity(MobileIdentity *mobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_mobile_identity(MobileIdentity *mobileidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_mobile_identity_xml(MobileIdentity *mobileidentity, uint8_t iei); + +#endif /* MOBILE IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.c b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.c new file mode 100644 index 0000000000..3fe9bf69c1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.c @@ -0,0 +1,114 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "MobileStationClassmark2.h" + +int decode_mobile_station_classmark_2(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + mobilestationclassmark2->revisionlevel = (*(buffer + decoded) >> 5) & 0x3; + mobilestationclassmark2->esind = (*(buffer + decoded) >> 4) & 0x1; + mobilestationclassmark2->a51 = (*(buffer + decoded) >> 3) & 0x1; + mobilestationclassmark2->rfpowercapability = *(buffer + decoded) & 0x7; + decoded++; + mobilestationclassmark2->pscapability = (*(buffer + decoded) >> 6) & 0x1; + mobilestationclassmark2->ssscreenindicator = (*(buffer + decoded) >> 4) & 0x3; + mobilestationclassmark2->smcapability = (*(buffer + decoded) >> 3) & 0x1; + mobilestationclassmark2->vbs = (*(buffer + decoded) >> 2) & 0x1; + mobilestationclassmark2->vgcs = (*(buffer + decoded) >> 1) & 0x1; + mobilestationclassmark2->fc = *(buffer + decoded) & 0x1; + decoded++; + mobilestationclassmark2->cm3 = (*(buffer + decoded) >> 7) & 0x1; + mobilestationclassmark2->lcsvacap = (*(buffer + decoded) >> 5) & 0x1; + mobilestationclassmark2->ucs2 = (*(buffer + decoded) >> 4) & 0x1; + mobilestationclassmark2->solsa = (*(buffer + decoded) >> 3) & 0x1; + mobilestationclassmark2->cmsp = (*(buffer + decoded) >> 2) & 0x1; + mobilestationclassmark2->a53 = (*(buffer + decoded) >> 1) & 0x1; + mobilestationclassmark2->a52 = *(buffer + decoded) & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_mobile_station_classmark_2_xml(mobilestationclassmark2, iei); +#endif + return decoded; +} +int encode_mobile_station_classmark_2(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MOBILE_STATION_CLASSMARK_2_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_mobile_station_classmark_2_xml(mobilestationclassmark2, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + ((mobilestationclassmark2->revisionlevel & 0x3) << 5) | + ((mobilestationclassmark2->esind & 0x1) << 4) | + ((mobilestationclassmark2->a51 & 0x1) << 3) | + (mobilestationclassmark2->rfpowercapability & 0x7); + encoded++; + *(buffer + encoded) = 0x00 | + ((mobilestationclassmark2->pscapability & 0x1) << 6) | + ((mobilestationclassmark2->ssscreenindicator & 0x3) << 4) | + ((mobilestationclassmark2->smcapability & 0x1) << 3) | + ((mobilestationclassmark2->vbs & 0x1) << 2) | + ((mobilestationclassmark2->vgcs & 0x1) << 1) | + (mobilestationclassmark2->fc & 0x1); + encoded++; + *(buffer + encoded) = 0x00 | ((mobilestationclassmark2->cm3 & 0x1) << 7) | + ((mobilestationclassmark2->lcsvacap & 0x1) << 5) | + ((mobilestationclassmark2->ucs2 & 0x1) << 4) | + ((mobilestationclassmark2->solsa & 0x1) << 3) | + ((mobilestationclassmark2->cmsp & 0x1) << 2) | + ((mobilestationclassmark2->a53 & 0x1) << 1) | + (mobilestationclassmark2->a52 & 0x1); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_mobile_station_classmark_2_xml(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei) +{ + printf("<Mobile Station Classmark 2>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Revision level>%u</Revision level>\n", mobilestationclassmark2->revisionlevel); + printf(" <ES IND>%u</ES IND>\n", mobilestationclassmark2->esind); + printf(" <A51>%u</A51>\n", mobilestationclassmark2->a51); + printf(" <RF power capability>%u</RF power capability>\n", mobilestationclassmark2->rfpowercapability); + printf(" <PS capability>%u</PS capability>\n", mobilestationclassmark2->pscapability); + printf(" <SS Screen indicator>%u</SS Screen indicator>\n", mobilestationclassmark2->ssscreenindicator); + printf(" <SM capability>%u</SM capability>\n", mobilestationclassmark2->smcapability); + printf(" <VBS>%u</VBS>\n", mobilestationclassmark2->vbs); + printf(" <VGCS>%u</VGCS>\n", mobilestationclassmark2->vgcs); + printf(" <FC>%u</FC>\n", mobilestationclassmark2->fc); + printf(" <CM3>%u</CM3>\n", mobilestationclassmark2->cm3); + printf(" <LCSVA CAP>%u</LCSVA CAP>\n", mobilestationclassmark2->lcsvacap); + printf(" <UCS2>%u</UCS2>\n", mobilestationclassmark2->ucs2); + printf(" <SoLSA>%u</SoLSA>\n", mobilestationclassmark2->solsa); + printf(" <CMSP>%u</CMSP>\n", mobilestationclassmark2->cmsp); + printf(" <A53>%u</A53>\n", mobilestationclassmark2->a53); + printf(" <A52>%u</A52>\n", mobilestationclassmark2->a52); + printf("</Mobile Station Classmark 2>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h new file mode 100644 index 0000000000..b5f048cf53 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h @@ -0,0 +1,40 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef MOBILE_STATION_CLASSMARK_2_H_ +#define MOBILE_STATION_CLASSMARK_2_H_ + +#define MOBILE_STATION_CLASSMARK_2_MINIMUM_LENGTH 5 +#define MOBILE_STATION_CLASSMARK_2_MAXIMUM_LENGTH 5 + +typedef struct MobileStationClassmark2_tag { + uint8_t revisionlevel:2; + uint8_t esind:1; + uint8_t a51:1; + uint8_t rfpowercapability:3; + uint8_t pscapability:1; + uint8_t ssscreenindicator:2; + uint8_t smcapability:1; + uint8_t vbs:1; + uint8_t vgcs:1; + uint8_t fc:1; + uint8_t cm3:1; + uint8_t lcsvacap:1; + uint8_t ucs2:1; + uint8_t solsa:1; + uint8_t cmsp:1; + uint8_t a53:1; + uint8_t a52:1; +} MobileStationClassmark2; + +int encode_mobile_station_classmark_2(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_mobile_station_classmark_2(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_mobile_station_classmark_2_xml(MobileStationClassmark2 *mobilestationclassmark2, uint8_t iei); + +#endif /* MOBILE STATION CLASSMARK 2_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.c b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.c new file mode 100644 index 0000000000..8a85c24e96 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "MobileStationClassmark3.h" + +int decode_mobile_station_classmark_3(MobileStationClassmark3 *mobilestationclassmark3, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_mobile_station_classmark_3(MobileStationClassmark3 *mobilestationclassmark3, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h new file mode 100644 index 0000000000..199f733a7e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef MOBILE_STATION_CLASSMARK_3_H_ +#define MOBILE_STATION_CLASSMARK_3_H_ + +#define MOBILE_STATION_CLASSMARK_3_MINIMUM_LENGTH 1 +#define MOBILE_STATION_CLASSMARK_3_MAXIMUM_LENGTH 1 + +typedef struct { + uint8_t field; +} MobileStationClassmark3; + +int encode_mobile_station_classmark_3(MobileStationClassmark3 *mobilestationclassmark3, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_mobile_station_classmark_3_xml(MobileStationClassmark3 *mobilestationclassmark3, uint8_t iei); + +int decode_mobile_station_classmark_3(MobileStationClassmark3 *mobilestationclassmark3, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* MOBILE STATION CLASSMARK 3_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.c b/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.c new file mode 100644 index 0000000000..1fcec3aa0b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "MsNetworkCapability.h" + +int decode_ms_network_capability(MsNetworkCapability *msnetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&msnetworkcapability->msnetworkcapabilityvalue, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_ms_network_capability_xml(msnetworkcapability, iei); +#endif + return decoded; +} +int encode_ms_network_capability(MsNetworkCapability *msnetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, MS_NETWORK_CAPABILITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ms_network_capability_xml(msnetworkcapability, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&msnetworkcapability->msnetworkcapabilityvalue, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_ms_network_capability_xml(MsNetworkCapability *msnetworkcapability, uint8_t iei) +{ + printf("<Ms Network Capability>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&msnetworkcapability->msnetworkcapabilityvalue); + printf("</Ms Network Capability>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h b/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h new file mode 100644 index 0000000000..ecfec6039e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef MS_NETWORK_CAPABILITY_H_ +#define MS_NETWORK_CAPABILITY_H_ + +#define MS_NETWORK_CAPABILITY_MINIMUM_LENGTH 3 +#define MS_NETWORK_CAPABILITY_MAXIMUM_LENGTH 10 + +typedef struct MsNetworkCapability_tag { + OctetString msnetworkcapabilityvalue; +} MsNetworkCapability; + +int encode_ms_network_capability(MsNetworkCapability *msnetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_ms_network_capability(MsNetworkCapability *msnetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ms_network_capability_xml(MsNetworkCapability *msnetworkcapability, uint8_t iei); + +#endif /* MS NETWORK CAPABILITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.c b/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.c new file mode 100644 index 0000000000..2493b0e691 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "NasKeySetIdentifier.h" + +int decode_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + naskeysetidentifier->tsc = (*(buffer + decoded) >> 3) & 0x1; + naskeysetidentifier->naskeysetidentifier = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_nas_key_set_identifier_xml(naskeysetidentifier, iei); +#endif + return decoded; +} + +int decode_u8_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + naskeysetidentifier->tsc = (*(buffer + decoded) >> 3) & 0x1; + naskeysetidentifier->naskeysetidentifier = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_nas_key_set_identifier_xml(naskeysetidentifier, iei); +#endif + return decoded; +} + +int encode_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_nas_key_set_identifier_xml(naskeysetidentifier, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((naskeysetidentifier->tsc & 0x1) << 3) | + (naskeysetidentifier->naskeysetidentifier & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_nas_key_set_identifier_xml(naskeysetidentifier, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + ((naskeysetidentifier->tsc & 0x1) << 3) | + (naskeysetidentifier->naskeysetidentifier & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_nas_key_set_identifier_xml(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei) +{ + printf("<Nas Key Set Identifier>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <TSC>%u</TSC>\n", naskeysetidentifier->tsc); + printf(" <NAS key set identifier>%u</NAS key set identifier>\n", naskeysetidentifier->naskeysetidentifier); + printf("</Nas Key Set Identifier>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h b/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h new file mode 100644 index 0000000000..54986430a6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef NAS_KEY_SET_IDENTIFIER_H_ +#define NAS_KEY_SET_IDENTIFIER_H_ + +#define NAS_KEY_SET_IDENTIFIER_MINIMUM_LENGTH 1 +#define NAS_KEY_SET_IDENTIFIER_MAXIMUM_LENGTH 1 + +typedef struct NasKeySetIdentifier_tag { +#define NAS_KEY_SET_IDENTIFIER_NATIVE 0 +#define NAS_KEY_SET_IDENTIFIER_MAPPED 1 + uint8_t tsc:1; +#define NAS_KEY_SET_IDENTIFIER_NOT_AVAILABLE 0b111 + uint8_t naskeysetidentifier:3; +} NasKeySetIdentifier; + +int encode_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_nas_key_set_identifier_xml(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei); + +uint8_t encode_u8_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier); + +int decode_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_nas_key_set_identifier(NasKeySetIdentifier *naskeysetidentifier, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* NAS KEY SET IDENTIFIER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.c b/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.c new file mode 100644 index 0000000000..49f703d61b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.c @@ -0,0 +1,66 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "NasMessageContainer.h" + +int decode_nas_message_container(NasMessageContainer *nasmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if ((decode_result = decode_octet_string(&nasmessagecontainer->nasmessagecontainercontents, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_nas_message_container_xml(nasmessagecontainer, iei); +#endif + return decoded; +} +int encode_nas_message_container(NasMessageContainer *nasmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, NAS_MESSAGE_CONTAINER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_nas_message_container_xml(nasmessagecontainer, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + if ((encode_result = encode_octet_string(&nasmessagecontainer->nasmessagecontainercontents, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_nas_message_container_xml(NasMessageContainer *nasmessagecontainer, uint8_t iei) +{ + printf("<Nas Message Container>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&nasmessagecontainer->nasmessagecontainercontents); + printf("</Nas Message Container>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h b/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h new file mode 100644 index 0000000000..23ada8b0b8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef NAS_MESSAGE_CONTAINER_H_ +#define NAS_MESSAGE_CONTAINER_H_ + +#define NAS_MESSAGE_CONTAINER_MINIMUM_LENGTH 4 +#define NAS_MESSAGE_CONTAINER_MAXIMUM_LENGTH 253 + +typedef struct NasMessageContainer_tag { + OctetString nasmessagecontainercontents; +} NasMessageContainer; + +int encode_nas_message_container(NasMessageContainer *nasmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_nas_message_container(NasMessageContainer *nasmessagecontainer, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_nas_message_container_xml(NasMessageContainer *nasmessagecontainer, uint8_t iei); + +#endif /* NAS MESSAGE CONTAINER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.c b/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.c new file mode 100644 index 0000000000..3e2fd9546c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.c @@ -0,0 +1,57 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "NasSecurityAlgorithms.h" + +int decode_nas_security_algorithms(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + nassecurityalgorithms->typeofcipheringalgorithm = (*(buffer + decoded) >> 4) & 0x7; + nassecurityalgorithms->typeofintegrityalgorithm = *(buffer + decoded) & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_nas_security_algorithms_xml(nassecurityalgorithms, iei); +#endif + return decoded; +} + +int encode_nas_security_algorithms(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, NAS_SECURITY_ALGORITHMS_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_nas_security_algorithms_xml(nassecurityalgorithms, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | + ((nassecurityalgorithms->typeofcipheringalgorithm & 0x7) << 4) | + (nassecurityalgorithms->typeofintegrityalgorithm & 0x7); + encoded++; + return encoded; +} + +void dump_nas_security_algorithms_xml(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei) +{ + printf("<Nas Security Algorithms>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Type of ciphering algorithm>%u</Type of ciphering algorithm>\n", nassecurityalgorithms->typeofcipheringalgorithm); + printf(" <Type of integrity algorithm>%u</Type of integrity algorithm>\n", nassecurityalgorithms->typeofintegrityalgorithm); + printf("</Nas Security Algorithms>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h b/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h new file mode 100644 index 0000000000..2dfb237a92 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h @@ -0,0 +1,41 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef NAS_SECURITY_ALGORITHMS_H_ +#define NAS_SECURITY_ALGORITHMS_H_ + +#define NAS_SECURITY_ALGORITHMS_MINIMUM_LENGTH 2 +#define NAS_SECURITY_ALGORITHMS_MAXIMUM_LENGTH 2 + +typedef struct NasSecurityAlgorithms_tag { +#define NAS_SECURITY_ALGORITHMS_EEA0 0b000 +#define NAS_SECURITY_ALGORITHMS_EEA1 0b001 +#define NAS_SECURITY_ALGORITHMS_EEA2 0b010 +#define NAS_SECURITY_ALGORITHMS_EEA3 0b011 +#define NAS_SECURITY_ALGORITHMS_EEA4 0b100 +#define NAS_SECURITY_ALGORITHMS_EEA5 0b101 +#define NAS_SECURITY_ALGORITHMS_EEA6 0b110 +#define NAS_SECURITY_ALGORITHMS_EEA7 0b111 + uint8_t typeofcipheringalgorithm:3; +#define NAS_SECURITY_ALGORITHMS_EIA0 0b000 +#define NAS_SECURITY_ALGORITHMS_EIA1 0b001 +#define NAS_SECURITY_ALGORITHMS_EIA2 0b010 +#define NAS_SECURITY_ALGORITHMS_EIA3 0b011 +#define NAS_SECURITY_ALGORITHMS_EIA4 0b100 +#define NAS_SECURITY_ALGORITHMS_EIA5 0b101 +#define NAS_SECURITY_ALGORITHMS_EIA6 0b110 +#define NAS_SECURITY_ALGORITHMS_EIA7 0b111 + uint8_t typeofintegrityalgorithm:3; +} NasSecurityAlgorithms; + +int encode_nas_security_algorithms(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_nas_security_algorithms_xml(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei); + +int decode_nas_security_algorithms(NasSecurityAlgorithms *nassecurityalgorithms, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* NAS SECURITY ALGORITHMS_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.c b/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.c new file mode 100644 index 0000000000..15f32dedf3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "NetworkName.h" + +int decode_network_name(NetworkName *networkname, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if (((*buffer >> 7) & 0x1) != 1) + { + errorCodeDecoder = TLV_DECODE_VALUE_DOESNT_MATCH; + return TLV_DECODE_VALUE_DOESNT_MATCH; + } + networkname->codingscheme = (*(buffer + decoded) >> 5) & 0x7; + networkname->addci = (*(buffer + decoded) >> 4) & 0x1; + networkname->numberofsparebitsinlastoctet = (*(buffer + decoded) >> 1) & 0x7; + if ((decode_result = decode_octet_string(&networkname->textstring, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_network_name_xml(networkname, iei); +#endif + return decoded; +} +int encode_network_name(NetworkName *networkname, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, NETWORK_NAME_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_network_name_xml(networkname, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | (1 << 7) | + ((networkname->codingscheme & 0x7) << 4) | + ((networkname->addci & 0x1) << 3) | + (networkname->numberofsparebitsinlastoctet & 0x7); + encoded++; + if ((encode_result = encode_octet_string(&networkname->textstring, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_network_name_xml(NetworkName *networkname, uint8_t iei) +{ + printf("<Network Name>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Coding scheme>%u</Coding scheme>\n", networkname->codingscheme); + printf(" <Add CI>%u</Add CI>\n", networkname->addci); + printf(" <Number of spare bits in last octet>%u</Number of spare bits in last octet>\n", networkname->numberofsparebitsinlastoctet); + dump_octet_string_xml(&networkname->textstring); + printf("</Network Name>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.h b/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.h new file mode 100644 index 0000000000..b7ba33fec7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/NetworkName.h @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef NETWORK_NAME_H_ +#define NETWORK_NAME_H_ + +#define NETWORK_NAME_MINIMUM_LENGTH 3 +#define NETWORK_NAME_MAXIMUM_LENGTH 255 + +typedef struct NetworkName_tag { + uint8_t codingscheme:3; + uint8_t addci:1; + uint8_t numberofsparebitsinlastoctet:3; + OctetString textstring; +} NetworkName; + +int encode_network_name(NetworkName *networkname, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_network_name(NetworkName *networkname, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_network_name_xml(NetworkName *networkname, uint8_t iei); + +#endif /* NETWORK NAME_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.c b/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.c new file mode 100644 index 0000000000..d620fef9e7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.c @@ -0,0 +1,52 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "Nonce.h" + +int decode_nonce(Nonce *nonce, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + //IES_DECODE_U32(*nonce, *(buffer + decoded)); + IES_DECODE_U32(buffer, decoded, *nonce); +#if defined (NAS_DEBUG) + dump_nonce_xml(nonce, iei); +#endif + return decoded; +} + +int encode_nonce(Nonce *nonce, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, NONCE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_nonce_xml(nonce, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + IES_ENCODE_U32(buffer, encoded, *nonce); + return encoded; +} + +void dump_nonce_xml(Nonce *nonce, uint8_t iei) +{ + printf("<Nonce>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Nonce value>%u</Nonce value>\n", *nonce); + printf("</Nonce>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.h b/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.h new file mode 100644 index 0000000000..0e8f9441a4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/Nonce.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef NONCE_H_ +#define NONCE_H_ + +#define NONCE_MINIMUM_LENGTH 5 +#define NONCE_MAXIMUM_LENGTH 5 + +typedef uint32_t Nonce; + +int encode_nonce(Nonce *nonce, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_nonce_xml(Nonce *nonce, uint8_t iei); + +int decode_nonce(Nonce *nonce, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* NONCE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.c new file mode 100644 index 0000000000..31e65123b2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.c @@ -0,0 +1,60 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PTmsiSignature.h" + +int decode_p_tmsi_signature(PTmsiSignature *ptmsisignature, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + int decode_result; + uint8_t ielen = 3; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + if ((decode_result = decode_octet_string(&ptmsisignature->ptmsisignaturevalue, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_p_tmsi_signature_xml(ptmsisignature, iei); +#endif + return decoded; +} + +int encode_p_tmsi_signature(PTmsiSignature *ptmsisignature, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encode_result; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, P_TMSI_SIGNATURE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_p_tmsi_signature_xml(ptmsisignature, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + if ((encode_result = encode_octet_string(&ptmsisignature->ptmsisignaturevalue, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + return encoded; +} + +void dump_p_tmsi_signature_xml(PTmsiSignature *ptmsisignature, uint8_t iei) +{ + printf("<P Tmsi Signature>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + dump_octet_string_xml(&ptmsisignature->ptmsisignaturevalue); + printf("</P Tmsi Signature>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h new file mode 100644 index 0000000000..84438b35d8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef P_TMSI_SIGNATURE_H_ +#define P_TMSI_SIGNATURE_H_ + +#define P_TMSI_SIGNATURE_MINIMUM_LENGTH 4 +#define P_TMSI_SIGNATURE_MAXIMUM_LENGTH 4 + +typedef struct PTmsiSignature_tag { + OctetString ptmsisignaturevalue; +} PTmsiSignature; + +int encode_p_tmsi_signature(PTmsiSignature *ptmsisignature, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_p_tmsi_signature_xml(PTmsiSignature *ptmsisignature, uint8_t iei); + +int decode_p_tmsi_signature(PTmsiSignature *ptmsisignature, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* P TMSI SIGNATURE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.c new file mode 100644 index 0000000000..f45f2f25cf --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.c @@ -0,0 +1,61 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PacketFlowIdentifier.h" + +int decode_packet_flow_identifier(PacketFlowIdentifier *packetflowidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + *packetflowidentifier = *buffer & 0x7f; + decoded++; +#if defined (NAS_DEBUG) + dump_packet_flow_identifier_xml(packetflowidentifier, iei); +#endif + return decoded; +} +int encode_packet_flow_identifier(PacketFlowIdentifier *packetflowidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PACKET_FLOW_IDENTIFIER_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_packet_flow_identifier_xml(packetflowidentifier, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + (*packetflowidentifier & 0x7f); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_packet_flow_identifier_xml(PacketFlowIdentifier *packetflowidentifier, uint8_t iei) +{ + printf("<Packet Flow Identifier>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Packet flow identifier value>%u</Packet flow identifier value>\n", *packetflowidentifier); + printf("</Packet Flow Identifier>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h new file mode 100644 index 0000000000..2174b5e2f3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PACKET_FLOW_IDENTIFIER_H_ +#define PACKET_FLOW_IDENTIFIER_H_ + +#define PACKET_FLOW_IDENTIFIER_MINIMUM_LENGTH 3 +#define PACKET_FLOW_IDENTIFIER_MAXIMUM_LENGTH 3 + +typedef uint8_t PacketFlowIdentifier; + +int encode_packet_flow_identifier(PacketFlowIdentifier *packetflowidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_packet_flow_identifier(PacketFlowIdentifier *packetflowidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_packet_flow_identifier_xml(PacketFlowIdentifier *packetflowidentifier, uint8_t iei); + +#endif /* PACKET FLOW IDENTIFIER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.c new file mode 100644 index 0000000000..6e0f89b712 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.c @@ -0,0 +1,54 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PagingIdentity.h" + +int decode_paging_identity(PagingIdentity *pagingidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *pagingidentity = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_paging_identity_xml(pagingidentity, iei); +#endif + return decoded; +} + +int encode_paging_identity(PagingIdentity *pagingidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PAGING_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_paging_identity_xml(pagingidentity, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | + (*pagingidentity & 0x1); + encoded++; + return encoded; +} + +void dump_paging_identity_xml(PagingIdentity *pagingidentity, uint8_t iei) +{ + printf("<Paging Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Paging identity value>%u</Paging identity value>\n", *pagingidentity); + printf("</Paging Identity>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.h new file mode 100644 index 0000000000..8b05345461 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PagingIdentity.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PAGING_IDENTITY_H_ +#define PAGING_IDENTITY_H_ + +#define PAGING_IDENTITY_MINIMUM_LENGTH 2 +#define PAGING_IDENTITY_MAXIMUM_LENGTH 2 + +typedef uint8_t PagingIdentity; + +int encode_paging_identity(PagingIdentity *pagingidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_paging_identity_xml(PagingIdentity *pagingidentity, uint8_t iei); + +int decode_paging_identity(PagingIdentity *pagingidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* PAGING IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.c new file mode 100644 index 0000000000..e5380cbefa --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.c @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnAddress.h" + +int decode_pdn_address(PdnAddress *pdnaddress, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + pdnaddress->pdntypevalue = *(buffer + decoded) & 0x7; + decoded++; + if ((decode_result = decode_octet_string(&pdnaddress->pdnaddressinformation, ielen - 1, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_pdn_address_xml(pdnaddress, iei); +#endif + return decoded; +} +int encode_pdn_address(PdnAddress *pdnaddress, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_ADDRESS_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_pdn_address_xml(pdnaddress, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + (pdnaddress->pdntypevalue & 0x7); + encoded++; + if ((encode_result = encode_octet_string(&pdnaddress->pdnaddressinformation, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_pdn_address_xml(PdnAddress *pdnaddress, uint8_t iei) +{ + printf("<Pdn Address>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <PDN type value>%u</PDN type value>\n", pdnaddress->pdntypevalue); + dump_octet_string_xml(&pdnaddress->pdnaddressinformation); + printf("</Pdn Address>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.h new file mode 100644 index 0000000000..f9c93c764e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnAddress.h @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PDN_ADDRESS_H_ +#define PDN_ADDRESS_H_ + +#define PDN_ADDRESS_MINIMUM_LENGTH 7 +#define PDN_ADDRESS_MAXIMUM_LENGTH 15 + +typedef struct PdnAddress_tag { +#define PDN_VALUE_TYPE_IPV4 0b001 +#define PDN_VALUE_TYPE_IPV6 0b010 +#define PDN_VALUE_TYPE_IPV4V6 0b011 + uint8_t pdntypevalue:3; + OctetString pdnaddressinformation; +} PdnAddress; + +int encode_pdn_address(PdnAddress *pdnaddress, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_pdn_address(PdnAddress *pdnaddress, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_pdn_address_xml(PdnAddress *pdnaddress, uint8_t iei); + +#endif /* PDN ADDRESS_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.c new file mode 100644 index 0000000000..e21d08b0a3 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PdnType.h" + +int decode_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, PDN_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *pdntype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_pdn_type_xml(pdntype, iei); +#endif + return decoded; +} + +int decode_u8_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *pdntype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_pdn_type_xml(pdntype, iei); +#endif + return decoded; +} + +int encode_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PDN_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_pdn_type_xml(pdntype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*pdntype & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_pdn_type(PdnType *pdntype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_pdn_type_xml(pdntype, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*pdntype & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_pdn_type_xml(PdnType *pdntype, uint8_t iei) +{ + printf("<Pdn Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <PDN type value>%u</PDN type value>\n", *pdntype); + printf("</Pdn Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.h new file mode 100644 index 0000000000..8fd02e0ec6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PdnType.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PDN_TYPE_H_ +#define PDN_TYPE_H_ + +#define PDN_TYPE_MINIMUM_LENGTH 1 +#define PDN_TYPE_MAXIMUM_LENGTH 1 + +#define PDN_TYPE_IPV4 0b001 +#define PDN_TYPE_IPV6 0b010 +#define PDN_TYPE_IPV4V6 0b011 +#define PDN_TYPE_UNUSED 0b100 +typedef uint8_t PdnType; + +int encode_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_pdn_type_xml(PdnType *pdntype, uint8_t iei); + +uint8_t encode_u8_pdn_type(PdnType *pdntype); + +int decode_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_pdn_type(PdnType *pdntype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* PDN TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.c b/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.c new file mode 100644 index 0000000000..1d77a743a6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "PlmnList.h" + +int decode_plmn_list(PlmnList *plmnlist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + plmnlist->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + plmnlist->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + plmnlist->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + plmnlist->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + plmnlist->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + plmnlist->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_plmn_list_xml(plmnlist, iei); +#endif + return decoded; +} +int encode_plmn_list(PlmnList *plmnlist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PLMN_LIST_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_plmn_list_xml(plmnlist, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | ((plmnlist->mccdigit2 & 0xf) << 4) | + (plmnlist->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((plmnlist->mncdigit3 & 0xf) << 4) | + (plmnlist->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((plmnlist->mncdigit2 & 0xf) << 4) | + (plmnlist->mncdigit1 & 0xf); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_plmn_list_xml(PlmnList *plmnlist, uint8_t iei) +{ + printf("<Plmn List>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <MCC digit 2>%u</MCC digit 2>\n", plmnlist->mccdigit2); + printf(" <MCC digit 1>%u</MCC digit 1>\n", plmnlist->mccdigit1); + printf(" <MNC digit 3>%u</MNC digit 3>\n", plmnlist->mncdigit3); + printf(" <MCC digit 3>%u</MCC digit 3>\n", plmnlist->mccdigit3); + printf(" <MNC digit 2>%u</MNC digit 2>\n", plmnlist->mncdigit2); + printf(" <MNC digit 1>%u</MNC digit 1>\n", plmnlist->mncdigit1); + printf("</Plmn List>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.h b/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.h new file mode 100644 index 0000000000..9d2ba24bd2 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/PlmnList.h @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PLMN_LIST_H_ +#define PLMN_LIST_H_ + +#define PLMN_LIST_MINIMUM_LENGTH 5 +#define PLMN_LIST_MAXIMUM_LENGTH 47 + +typedef struct PlmnList_tag { + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; +} PlmnList; + +int encode_plmn_list(PlmnList *plmnlist, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_plmn_list(PlmnList *plmnlist, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_plmn_list_xml(PlmnList *plmnlist, uint8_t iei); + +#endif /* PLMN LIST_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.c new file mode 100644 index 0000000000..69ac8f6261 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ProcedureTransactionIdentity.h" + +int decode_procedure_transaction_identity(ProcedureTransactionIdentity *proceduretransactionidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_procedure_transaction_identity(ProcedureTransactionIdentity *proceduretransactionidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h new file mode 100644 index 0000000000..1f0453b086 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PROCEDURE_TRANSACTION_IDENTITY_H_ +#define PROCEDURE_TRANSACTION_IDENTITY_H_ + +#define PROCEDURE_TRANSACTION_IDENTITY_MINIMUM_LENGTH 1 +#define PROCEDURE_TRANSACTION_IDENTITY_MAXIMUM_LENGTH 1 + +#define PROCEDURE_TRANSACTION_IDENTITY_UNASSIGNED 0 +#define PROCEDURE_TRANSACTION_IDENTITY_FIRST 1 +#define PROCEDURE_TRANSACTION_IDENTITY_LAST 254 +typedef uint8_t ProcedureTransactionIdentity; + +int encode_procedure_transaction_identity(ProcedureTransactionIdentity *proceduretransactionidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_procedure_transaction_identity_xml(ProcedureTransactionIdentity *proceduretransactionidentity, uint8_t iei); + +int decode_procedure_transaction_identity(ProcedureTransactionIdentity *proceduretransactionidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* PROCEDURE TRANSACTION IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.c new file mode 100644 index 0000000000..bd3f577af8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.c @@ -0,0 +1,85 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ProtocolConfigurationOptions.h" + +int decode_protocol_configuration_options(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + int decode_result; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + if (((*buffer >> 7) & 0x1) != 1) + { + errorCodeDecoder = TLV_DECODE_VALUE_DOESNT_MATCH; + return TLV_DECODE_VALUE_DOESNT_MATCH; + } + protocolconfigurationoptions->configurationprotol = (*(buffer + decoded) >> 1) & 0x7; + //IES_DECODE_U16(protocolconfigurationoptions->protocolid, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, protocolconfigurationoptions->protocolid); + protocolconfigurationoptions->lengthofprotocolid = *(buffer + decoded); + decoded++; + if ((decode_result = decode_octet_string(&protocolconfigurationoptions->protocolidcontents, ielen, buffer + decoded, len - decoded)) < 0) + return decode_result; + else + decoded += decode_result; +#if defined (NAS_DEBUG) + dump_protocol_configuration_options_xml(protocolconfigurationoptions, iei); +#endif + return decoded; +} +int encode_protocol_configuration_options(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + int encode_result; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, PROTOCOL_CONFIGURATION_OPTIONS_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_protocol_configuration_options_xml(protocolconfigurationoptions, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | (1 << 7) | + (protocolconfigurationoptions->configurationprotol & 0x7); + encoded++; + IES_ENCODE_U16(buffer, encoded, protocolconfigurationoptions->protocolid); + *(buffer + encoded) = protocolconfigurationoptions->lengthofprotocolid; + encoded++; + if ((encode_result = encode_octet_string(&protocolconfigurationoptions->protocolidcontents, buffer + encoded, len - encoded)) < 0) + return encode_result; + else + encoded += encode_result; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_protocol_configuration_options_xml(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei) +{ + printf("<Protocol Configuration Options>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Configuration protol>%u</Configuration protol>\n", protocolconfigurationoptions->configurationprotol); + printf(" <Protocol ID>%u</Protocol ID>\n", protocolconfigurationoptions->protocolid); + printf(" <Length of protocol ID>%u</Length of protocol ID>\n", protocolconfigurationoptions->lengthofprotocolid); + dump_octet_string_xml(&protocolconfigurationoptions->protocolidcontents); + printf("</Protocol Configuration Options>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h new file mode 100644 index 0000000000..1074e3ee83 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h @@ -0,0 +1,27 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PROTOCOL_CONFIGURATION_OPTIONS_H_ +#define PROTOCOL_CONFIGURATION_OPTIONS_H_ + +#define PROTOCOL_CONFIGURATION_OPTIONS_MINIMUM_LENGTH 3 +#define PROTOCOL_CONFIGURATION_OPTIONS_MAXIMUM_LENGTH 253 + +typedef struct ProtocolConfigurationOptions_tag { + uint8_t configurationprotol:3; + uint16_t protocolid; + uint8_t lengthofprotocolid; + OctetString protocolidcontents; +} ProtocolConfigurationOptions; + +int encode_protocol_configuration_options(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_protocol_configuration_options(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_protocol_configuration_options_xml(ProtocolConfigurationOptions *protocolconfigurationoptions, uint8_t iei); + +#endif /* PROTOCOL CONFIGURATION OPTIONS_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.c new file mode 100644 index 0000000000..db171b50e7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ProtocolDiscriminator.h" + +int decode_protocol_discriminator(ProtocolDiscriminator *protocoldiscriminator, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_protocol_discriminator(ProtocolDiscriminator *protocoldiscriminator, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h new file mode 100644 index 0000000000..38d0a6324c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef PROTOCOL_DISCRIMINATOR_H_ +#define PROTOCOL_DISCRIMINATOR_H_ + +#define PROTOCOL_DISCRIMINATOR_MINIMUM_LENGTH 1 +#define PROTOCOL_DISCRIMINATOR_MAXIMUM_LENGTH 1 + +typedef uint8_t ProtocolDiscriminator; + +int encode_protocol_discriminator(ProtocolDiscriminator *protocoldiscriminator, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_protocol_discriminator_xml(ProtocolDiscriminator *protocoldiscriminator, uint8_t iei); + +int decode_protocol_discriminator(ProtocolDiscriminator *protocoldiscriminator, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* PROTOCOL DISCRIMINATOR_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.c b/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.c new file mode 100644 index 0000000000..4ca631554e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.c @@ -0,0 +1,139 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "QualityOfService.h" + +int decode_quality_of_service(QualityOfService *qualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + qualityofservice->delayclass = (*(buffer + decoded) >> 3) & 0x7; + qualityofservice->reliabilityclass = *(buffer + decoded) & 0x7; + decoded++; + qualityofservice->peakthroughput = (*(buffer + decoded) >> 4) & 0xf; + qualityofservice->precedenceclass = *(buffer + decoded) & 0x7; + decoded++; + qualityofservice->meanthroughput = *(buffer + decoded) & 0x1f; + decoded++; + qualityofservice->trafficclass = (*(buffer + decoded) >> 5) & 0x7; + qualityofservice->deliveryorder = (*(buffer + decoded) >> 3) & 0x3; + qualityofservice->deliveryoferroneoussdu = *(buffer + decoded) & 0x7; + decoded++; + qualityofservice->maximumsdusize = *(buffer + decoded); + decoded++; + qualityofservice->maximumbitrateuplink = *(buffer + decoded); + decoded++; + qualityofservice->maximumbitratedownlink = *(buffer + decoded); + decoded++; + qualityofservice->residualber = (*(buffer + decoded) >> 4) & 0xf; + qualityofservice->sduratioerror = *(buffer + decoded) & 0xf; + decoded++; + qualityofservice->transferdelay = (*(buffer + decoded) >> 2) & 0x3f; + qualityofservice->traffichandlingpriority = *(buffer + decoded) & 0x3; + decoded++; + qualityofservice->guaranteedbitrateuplink = *(buffer + decoded); + decoded++; + qualityofservice->guaranteedbitratedownlink = *(buffer + decoded); + decoded++; + qualityofservice->signalingindication = (*(buffer + decoded) >> 4) & 0x1; + qualityofservice->sourcestatisticsdescriptor = *(buffer + decoded) & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_quality_of_service_xml(qualityofservice, iei); +#endif + return decoded; +} +int encode_quality_of_service(QualityOfService *qualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, QUALITY_OF_SERVICE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_quality_of_service_xml(qualityofservice, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + ((qualityofservice->delayclass & 0x7) << 3) | + (qualityofservice->reliabilityclass & 0x7); + encoded++; + *(buffer + encoded) = 0x00 | ((qualityofservice->peakthroughput & 0xf) << 4) | + (qualityofservice->precedenceclass & 0x7); + encoded++; + *(buffer + encoded) = 0x00 | + (qualityofservice->meanthroughput & 0x1f); + encoded++; + *(buffer + encoded) = 0x00 | ((qualityofservice->trafficclass & 0x7) << 5) | + ((qualityofservice->deliveryorder & 0x3) << 3) | + (qualityofservice->deliveryoferroneoussdu & 0x7); + encoded++; + *(buffer + encoded) = qualityofservice->maximumsdusize; + encoded++; + *(buffer + encoded) = qualityofservice->maximumbitrateuplink; + encoded++; + *(buffer + encoded) = qualityofservice->maximumbitratedownlink; + encoded++; + *(buffer + encoded) = 0x00 | ((qualityofservice->residualber & 0xf) << 4) | + (qualityofservice->sduratioerror & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((qualityofservice->transferdelay & 0x3f) << 2) | + (qualityofservice->traffichandlingpriority & 0x3); + encoded++; + *(buffer + encoded) = qualityofservice->guaranteedbitrateuplink; + encoded++; + *(buffer + encoded) = qualityofservice->guaranteedbitratedownlink; + encoded++; + *(buffer + encoded) = 0x00 | + ((qualityofservice->signalingindication & 0x1) << 4) | + (qualityofservice->sourcestatisticsdescriptor & 0xf); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_quality_of_service_xml(QualityOfService *qualityofservice, uint8_t iei) +{ + printf("<Quality Of Service>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Delay class>%u</Delay class>\n", qualityofservice->delayclass); + printf(" <Reliability class>%u</Reliability class>\n", qualityofservice->reliabilityclass); + printf(" <Peak throughput>%u</Peak throughput>\n", qualityofservice->peakthroughput); + printf(" <Precedence class>%u</Precedence class>\n", qualityofservice->precedenceclass); + printf(" <Mean throughput>%u</Mean throughput>\n", qualityofservice->meanthroughput); + printf(" <Traffic class>%u</Traffic class>\n", qualityofservice->trafficclass); + printf(" <Delivery order>%u</Delivery order>\n", qualityofservice->deliveryorder); + printf(" <Delivery of erroneous SDU>%u</Delivery of erroneous SDU>\n", qualityofservice->deliveryoferroneoussdu); + printf(" <Maximum SDU size>%u</Maximum SDU size>\n", qualityofservice->maximumsdusize); + printf(" <Maximum bit rate uplink>%u</Maximum bit rate uplink>\n", qualityofservice->maximumbitrateuplink); + printf(" <Maximum bit rate downlink>%u</Maximum bit rate downlink>\n", qualityofservice->maximumbitratedownlink); + printf(" <Residual BER>%u</Residual BER>\n", qualityofservice->residualber); + printf(" <SDU ratio error>%u</SDU ratio error>\n", qualityofservice->sduratioerror); + printf(" <Transfer delay>%u</Transfer delay>\n", qualityofservice->transferdelay); + printf(" <Traffic handling priority>%u</Traffic handling priority>\n", qualityofservice->traffichandlingpriority); + printf(" <Guaranteed bit rate uplink>%u</Guaranteed bit rate uplink>\n", qualityofservice->guaranteedbitrateuplink); + printf(" <Guaranteed bit rate downlink>%u</Guaranteed bit rate downlink>\n", qualityofservice->guaranteedbitratedownlink); + printf(" <Signaling indication>%u</Signaling indication>\n", qualityofservice->signalingindication); + printf(" <Source statistics descriptor>%u</Source statistics descriptor>\n", qualityofservice->sourcestatisticsdescriptor); + printf("</Quality Of Service>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.h b/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.h new file mode 100644 index 0000000000..63d5a7fe44 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/QualityOfService.h @@ -0,0 +1,42 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef QUALITY_OF_SERVICE_H_ +#define QUALITY_OF_SERVICE_H_ + +#define QUALITY_OF_SERVICE_MINIMUM_LENGTH 14 +#define QUALITY_OF_SERVICE_MAXIMUM_LENGTH 14 + +typedef struct QualityOfService_tag { + uint8_t delayclass:3; + uint8_t reliabilityclass:3; + uint8_t peakthroughput:4; + uint8_t precedenceclass:3; + uint8_t meanthroughput:5; + uint8_t trafficclass:3; + uint8_t deliveryorder:2; + uint8_t deliveryoferroneoussdu:3; + uint8_t maximumsdusize; + uint8_t maximumbitrateuplink; + uint8_t maximumbitratedownlink; + uint8_t residualber:4; + uint8_t sduratioerror:4; + uint8_t transferdelay:6; + uint8_t traffichandlingpriority:2; + uint8_t guaranteedbitrateuplink; + uint8_t guaranteedbitratedownlink; + uint8_t signalingindication:1; + uint8_t sourcestatisticsdescriptor:4; +} QualityOfService; + +int encode_quality_of_service(QualityOfService *qualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_quality_of_service(QualityOfService *qualityofservice, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_quality_of_service_xml(QualityOfService *qualityofservice, uint8_t iei); + +#endif /* QUALITY OF SERVICE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.c b/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.c new file mode 100644 index 0000000000..d3ee86db4a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "RadioPriority.h" + +int decode_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, RADIO_PRIORITY_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *radiopriority = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_radio_priority_xml(radiopriority, iei); +#endif + return decoded; +} + +int decode_u8_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *radiopriority = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_radio_priority_xml(radiopriority, iei); +#endif + return decoded; +} + +int encode_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, RADIO_PRIORITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_radio_priority_xml(radiopriority, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*radiopriority & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_radio_priority(RadioPriority *radiopriority) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_radio_priority_xml(radiopriority, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*radiopriority & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_radio_priority_xml(RadioPriority *radiopriority, uint8_t iei) +{ + printf("<Radio Priority>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Radio priority level value>%u</Radio priority level value>\n", *radiopriority); + printf("</Radio Priority>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.h b/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.h new file mode 100644 index 0000000000..fb9f0880ac --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/RadioPriority.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef RADIO_PRIORITY_H_ +#define RADIO_PRIORITY_H_ + +#define RADIO_PRIORITY_MINIMUM_LENGTH 1 +#define RADIO_PRIORITY_MAXIMUM_LENGTH 1 + +typedef uint8_t RadioPriority; + +int encode_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_radio_priority_xml(RadioPriority *radiopriority, uint8_t iei); + +uint8_t encode_u8_radio_priority(RadioPriority *radiopriority); + +int decode_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_radio_priority(RadioPriority *radiopriority, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* RADIO PRIORITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.c new file mode 100644 index 0000000000..2206ed922f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.c @@ -0,0 +1,77 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "RequestType.h" + +int decode_request_type(RequestType *requesttype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, REQUEST_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *requesttype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_request_type_xml(requesttype, iei); +#endif + return decoded; +} + +int decode_u8_request_type(RequestType *requesttype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *requesttype = *buffer & 0x7; + decoded++; +#if defined (NAS_DEBUG) + dump_request_type_xml(requesttype, iei); +#endif + return decoded; +} + +int encode_request_type(RequestType *requesttype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, REQUEST_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_request_type_xml(requesttype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*requesttype & 0x7); + encoded++; + return encoded; +} + +uint8_t encode_u8_request_type(RequestType *requesttype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; +#if defined (NAS_DEBUG) + dump_request_type_xml(requesttype, 0); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*requesttype & 0x7); + encoded++; + + return bufferReturn; +} + +void dump_request_type_xml(RequestType *requesttype, uint8_t iei) +{ + printf("<Request Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Request type value>%u</Request type value>\n", *requesttype); + printf("</Request Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.h new file mode 100644 index 0000000000..d15e73d9e1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/RequestType.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef REQUEST_TYPE_H_ +#define REQUEST_TYPE_H_ + +#define REQUEST_TYPE_MINIMUM_LENGTH 1 +#define REQUEST_TYPE_MAXIMUM_LENGTH 1 + +#define REQUEST_TYPE_INITIAL_REQUEST 0b001 +#define REQUEST_TYPE_HANDOVER 0b010 +#define REQUEST_TYPE_UNUSED 0b011 +#define REQUEST_TYPE_EMERGENCY 0b100 +typedef uint8_t RequestType; + +int encode_request_type(RequestType *requesttype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_request_type_xml(RequestType *requesttype, uint8_t iei); + +uint8_t encode_u8_request_type(RequestType *requesttype); + +int decode_request_type(RequestType *requesttype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_request_type(RequestType *requesttype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* REQUEST TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.c new file mode 100644 index 0000000000..aa5aa7a998 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SecurityHeaderType.h" + +int decode_security_header_type(SecurityHeaderType *securityheadertype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_security_header_type(SecurityHeaderType *securityheadertype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h new file mode 100644 index 0000000000..227ffa68b4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef SECURITY_HEADER_TYPE_H_ +#define SECURITY_HEADER_TYPE_H_ + +#define SECURITY_HEADER_TYPE_MINIMUM_LENGTH 1 +#define SECURITY_HEADER_TYPE_MAXIMUM_LENGTH 1 + +typedef uint8_t SecurityHeaderType; + +int encode_security_header_type(SecurityHeaderType *securityheadertype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_security_header_type_xml(SecurityHeaderType *securityheadertype, uint8_t iei); + +int decode_security_header_type(SecurityHeaderType *securityheadertype, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* SECURITY HEADER TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.c new file mode 100644 index 0000000000..7f60e21e21 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ServiceType.h" + +int decode_service_type(ServiceType *servicetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, SERVICE_TYPE_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *servicetype = *buffer & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_service_type_xml(servicetype, iei); +#endif + return decoded; +} + +int decode_u8_service_type(ServiceType *servicetype, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *servicetype = *buffer & 0xf; + decoded++; +#if defined (NAS_DEBUG) + dump_service_type_xml(servicetype, iei); +#endif + return decoded; +} + +int encode_service_type(ServiceType *servicetype, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SERVICE_TYPE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_service_type_xml(servicetype, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*servicetype & 0xf); + encoded++; + return encoded; +} + +uint8_t encode_u8_service_type(ServiceType *servicetype) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_service_type_xml(servicetype, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*servicetype & 0xf); + encoded++; + + return bufferReturn; +} + +void dump_service_type_xml(ServiceType *servicetype, uint8_t iei) +{ + printf("<Service Type>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Service type value>%u</Service type value>\n", *servicetype); + printf("</Service Type>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.h new file mode 100644 index 0000000000..60e41d80f0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ServiceType.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef SERVICE_TYPE_H_ +#define SERVICE_TYPE_H_ + +#define SERVICE_TYPE_MINIMUM_LENGTH 1 +#define SERVICE_TYPE_MAXIMUM_LENGTH 1 + +typedef uint8_t ServiceType; + +int encode_service_type(ServiceType *servicetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_service_type_xml(ServiceType *servicetype, uint8_t iei); + +uint8_t encode_u8_service_type(ServiceType *servicetype); + +int decode_service_type(ServiceType *servicetype, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_service_type(ServiceType *servicetype, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* SERVICE TYPE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.c b/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.c new file mode 100644 index 0000000000..f94fb8e52b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.c @@ -0,0 +1,52 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "ShortMac.h" + +int decode_short_mac(ShortMac *shortmac, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + //IES_DECODE_U16(*shortmac, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, *shortmac); +#if defined (NAS_DEBUG) + dump_short_mac_xml(shortmac, iei); +#endif + return decoded; +} + +int encode_short_mac(ShortMac *shortmac, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SHORT_MAC_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_short_mac_xml(shortmac, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + IES_ENCODE_U16(buffer, encoded, *shortmac); + return encoded; +} + +void dump_short_mac_xml(ShortMac *shortmac, uint8_t iei) +{ + printf("<Short Mac>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Short MAC value>%u</Short MAC value>\n", *shortmac); + printf("</Short Mac>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.h b/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.h new file mode 100644 index 0000000000..134a3fcb23 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/ShortMac.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef SHORT_MAC_H_ +#define SHORT_MAC_H_ + +#define SHORT_MAC_MINIMUM_LENGTH 3 +#define SHORT_MAC_MAXIMUM_LENGTH 3 + +typedef uint16_t ShortMac; + +int encode_short_mac(ShortMac *shortmac, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_short_mac_xml(ShortMac *shortmac, uint8_t iei); + +int decode_short_mac(ShortMac *shortmac, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* SHORT MAC_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.c b/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.c new file mode 100644 index 0000000000..feca3d1500 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SsCode.h" + +int decode_ss_code(SsCode *sscode, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *sscode = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_ss_code_xml(sscode, iei); +#endif + return decoded; +} + +int encode_ss_code(SsCode *sscode, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SS_CODE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ss_code_xml(sscode, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = *sscode; + encoded++; + return encoded; +} + +void dump_ss_code_xml(SsCode *sscode, uint8_t iei) +{ + printf("<Ss Code>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <SS code value>%u</SS code value>\n", *sscode); + printf("</Ss Code>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.h b/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.h new file mode 100644 index 0000000000..8b70a1b5fc --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SsCode.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef SS_CODE_H_ +#define SS_CODE_H_ + +#define SS_CODE_MINIMUM_LENGTH 2 +#define SS_CODE_MAXIMUM_LENGTH 2 + +typedef uint8_t SsCode; + +int encode_ss_code(SsCode *sscode, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ss_code_xml(SsCode *sscode, uint8_t iei); + +int decode_ss_code(SsCode *sscode, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* SS CODE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.c b/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.c new file mode 100644 index 0000000000..c3403fdec1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.c @@ -0,0 +1,69 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "SupportedCodecList.h" + +int decode_supported_codec_list(SupportedCodecList *supportedcodeclist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + supportedcodeclist->systemidentification = *(buffer + decoded); + decoded++; + supportedcodeclist->lengthofbitmap = *(buffer + decoded); + decoded++; + //IES_DECODE_U16(supportedcodeclist->codecbitmap, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, supportedcodeclist->codecbitmap); +#if defined (NAS_DEBUG) + dump_supported_codec_list_xml(supportedcodeclist, iei); +#endif + return decoded; +} +int encode_supported_codec_list(SupportedCodecList *supportedcodeclist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, SUPPORTED_CODEC_LIST_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_supported_codec_list_xml(supportedcodeclist, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = supportedcodeclist->systemidentification; + encoded++; + *(buffer + encoded) = supportedcodeclist->lengthofbitmap; + encoded++; + IES_ENCODE_U16(buffer, encoded, supportedcodeclist->codecbitmap); + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_supported_codec_list_xml(SupportedCodecList *supportedcodeclist, uint8_t iei) +{ + printf("<Supported Codec List>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <System identification>%u</System identification>\n", supportedcodeclist->systemidentification); + printf(" <Length of bitmap>%u</Length of bitmap>\n", supportedcodeclist->lengthofbitmap); + printf(" <Codec bitmap>%u</Codec bitmap>\n", supportedcodeclist->codecbitmap); + printf("</Supported Codec List>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h b/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h new file mode 100644 index 0000000000..4550247431 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef SUPPORTED_CODEC_LIST_H_ +#define SUPPORTED_CODEC_LIST_H_ + +#define SUPPORTED_CODEC_LIST_MINIMUM_LENGTH 5 +#define SUPPORTED_CODEC_LIST_MAXIMUM_LENGTH 5 + +typedef struct SupportedCodecList_tag { + uint8_t systemidentification; + uint8_t lengthofbitmap; + uint16_t codecbitmap; +} SupportedCodecList; + +int encode_supported_codec_list(SupportedCodecList *supportedcodeclist, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_supported_codec_list(SupportedCodecList *supportedcodeclist, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_supported_codec_list_xml(SupportedCodecList *supportedcodeclist, uint8_t iei); + +#endif /* SUPPORTED CODEC LIST_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.c new file mode 100644 index 0000000000..297375d5d8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TimeZone.h" + +int decode_time_zone(TimeZone *timezone, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + *timezone = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_time_zone_xml(timezone, iei); +#endif + return decoded; +} + +int encode_time_zone(TimeZone *timezone, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TIME_ZONE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_time_zone_xml(timezone, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = *timezone; + encoded++; + return encoded; +} + +void dump_time_zone_xml(TimeZone *timezone, uint8_t iei) +{ + printf("<Time Zone>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Time zone>%u</Time zone>\n", *timezone); + printf("</Time Zone>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.h new file mode 100644 index 0000000000..6ae377090f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZone.h @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TIME_ZONE_H_ +#define TIME_ZONE_H_ + +#define TIME_ZONE_MINIMUM_LENGTH 2 +#define TIME_ZONE_MAXIMUM_LENGTH 2 + +typedef uint8_t TimeZone; + +int encode_time_zone(TimeZone *timezone, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_time_zone_xml(TimeZone *timezone, uint8_t iei); + +int decode_time_zone(TimeZone *timezone, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* TIME ZONE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.c new file mode 100644 index 0000000000..4a7eda3852 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.c @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TimeZoneAndTime.h" + +int decode_time_zone_and_time(TimeZoneAndTime *timezoneandtime, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + timezoneandtime->year = *(buffer + decoded); + decoded++; + timezoneandtime->month = *(buffer + decoded); + decoded++; + timezoneandtime->day = *(buffer + decoded); + decoded++; + timezoneandtime->hour = *(buffer + decoded); + decoded++; + timezoneandtime->minute = *(buffer + decoded); + decoded++; + timezoneandtime->second = *(buffer + decoded); + decoded++; + timezoneandtime->timezone = *(buffer + decoded); + decoded++; +#if defined (NAS_DEBUG) + dump_time_zone_and_time_xml(timezoneandtime, iei); +#endif + return decoded; +} + +int encode_time_zone_and_time(TimeZoneAndTime *timezoneandtime, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TIME_ZONE_AND_TIME_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_time_zone_and_time_xml(timezoneandtime, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = timezoneandtime->year; + encoded++; + *(buffer + encoded) = timezoneandtime->month; + encoded++; + *(buffer + encoded) = timezoneandtime->day; + encoded++; + *(buffer + encoded) = timezoneandtime->hour; + encoded++; + *(buffer + encoded) = timezoneandtime->minute; + encoded++; + *(buffer + encoded) = timezoneandtime->second; + encoded++; + *(buffer + encoded) = timezoneandtime->timezone; + encoded++; + return encoded; +} + +void dump_time_zone_and_time_xml(TimeZoneAndTime *timezoneandtime, uint8_t iei) +{ + printf("<Time Zone And Time>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Year>%u</Year>\n", timezoneandtime->year); + printf(" <Month>%u</Month>\n", timezoneandtime->month); + printf(" <Day>%u</Day>\n", timezoneandtime->day); + printf(" <Hour>%u</Hour>\n", timezoneandtime->hour); + printf(" <Minute>%u</Minute>\n", timezoneandtime->minute); + printf(" <Second>%u</Second>\n", timezoneandtime->second); + printf(" <Time Zone>%u</Time Zone>\n", timezoneandtime->timezone); + printf("</Time Zone And Time>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h new file mode 100644 index 0000000000..f778b64da6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TIME_ZONE_AND_TIME_H_ +#define TIME_ZONE_AND_TIME_H_ + +#define TIME_ZONE_AND_TIME_MINIMUM_LENGTH 8 +#define TIME_ZONE_AND_TIME_MAXIMUM_LENGTH 8 + +typedef struct TimeZoneAndTime_tag { + uint8_t year; + uint8_t month; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t timezone; +} TimeZoneAndTime; + +int encode_time_zone_and_time(TimeZoneAndTime *timezoneandtime, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_time_zone_and_time_xml(TimeZoneAndTime *timezoneandtime, uint8_t iei); + +int decode_time_zone_and_time(TimeZoneAndTime *timezoneandtime, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* TIME ZONE AND TIME_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.c new file mode 100644 index 0000000000..a2f5e20050 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TmsiStatus.h" + +int decode_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, TMSI_STATUS_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *tmsistatus = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_tmsi_status_xml(tmsistatus, iei); +#endif + return decoded; +} + +int decode_u8_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *tmsistatus = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_tmsi_status_xml(tmsistatus, iei); +#endif + return decoded; +} + +int encode_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TMSI_STATUS_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_tmsi_status_xml(tmsistatus, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*tmsistatus & 0x1); + encoded++; + return encoded; +} + +uint8_t encode_u8_tmsi_status(TmsiStatus *tmsistatus) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_tmsi_status_xml(tmsistatus, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*tmsistatus & 0x1); + encoded++; + + return bufferReturn; +} + +void dump_tmsi_status_xml(TmsiStatus *tmsistatus, uint8_t iei) +{ + printf("<Tmsi Status>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <TMSI flag>%u</TMSI flag>\n", *tmsistatus); + printf("</Tmsi Status>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.h new file mode 100644 index 0000000000..c11f9b9747 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TmsiStatus.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TMSI_STATUS_H_ +#define TMSI_STATUS_H_ + +#define TMSI_STATUS_MINIMUM_LENGTH 1 +#define TMSI_STATUS_MAXIMUM_LENGTH 1 + +typedef uint8_t TmsiStatus; + +int encode_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_tmsi_status_xml(TmsiStatus *tmsistatus, uint8_t iei); + +uint8_t encode_u8_tmsi_status(TmsiStatus *tmsistatus); + +int decode_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_tmsi_status(TmsiStatus *tmsistatus, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* TMSI STATUS_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.c new file mode 100644 index 0000000000..43f8de3948 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.c @@ -0,0 +1,76 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaIdentity.h" + +int decode_tracking_area_identity(TrackingAreaIdentity *trackingareaidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + trackingareaidentity->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentity->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + trackingareaidentity->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentity->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + trackingareaidentity->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentity->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; + //IES_DECODE_U16(trackingareaidentity->tac, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, trackingareaidentity->tac); +#if defined (NAS_DEBUG) + dump_tracking_area_identity_xml(trackingareaidentity, iei); +#endif + return decoded; +} + +int encode_tracking_area_identity(TrackingAreaIdentity *trackingareaidentity, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_IDENTITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_tracking_area_identity_xml(trackingareaidentity, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + *(buffer + encoded) = 0x00 | ((trackingareaidentity->mccdigit2 & 0xf) << 4) | + (trackingareaidentity->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((trackingareaidentity->mncdigit3 & 0xf) << 4) | + (trackingareaidentity->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((trackingareaidentity->mncdigit2 & 0xf) << 4) | + (trackingareaidentity->mncdigit1 & 0xf); + encoded++; + IES_ENCODE_U16(buffer, encoded, trackingareaidentity->tac); + return encoded; +} + +void dump_tracking_area_identity_xml(TrackingAreaIdentity *trackingareaidentity, uint8_t iei) +{ + printf("<Tracking Area Identity>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <MCC digit 2>%u</MCC digit 2>\n", trackingareaidentity->mccdigit2); + printf(" <MCC digit 1>%u</MCC digit 1>\n", trackingareaidentity->mccdigit1); + printf(" <MNC digit 3>%u</MNC digit 3>\n", trackingareaidentity->mncdigit3); + printf(" <MCC digit 3>%u</MCC digit 3>\n", trackingareaidentity->mccdigit3); + printf(" <MNC digit 2>%u</MNC digit 2>\n", trackingareaidentity->mncdigit2); + printf(" <MNC digit 1>%u</MNC digit 1>\n", trackingareaidentity->mncdigit1); + printf(" <TAC>0x%.4x</TAC>\n", trackingareaidentity->tac); + printf("</Tracking Area Identity>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h new file mode 100644 index 0000000000..f4f2cb1e02 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h @@ -0,0 +1,30 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TRACKING_AREA_IDENTITY_H_ +#define TRACKING_AREA_IDENTITY_H_ + +#define TRACKING_AREA_IDENTITY_MINIMUM_LENGTH 6 +#define TRACKING_AREA_IDENTITY_MAXIMUM_LENGTH 6 + +typedef struct TrackingAreaIdentity_tag { + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; + uint16_t tac; +} TrackingAreaIdentity; + +int encode_tracking_area_identity(TrackingAreaIdentity *trackingareaidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_tracking_area_identity_xml(TrackingAreaIdentity *trackingareaidentity, uint8_t iei); + +int decode_tracking_area_identity(TrackingAreaIdentity *trackingareaidentity, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* TRACKING AREA IDENTITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.c new file mode 100644 index 0000000000..90ab0da926 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.c @@ -0,0 +1,92 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrackingAreaIdentityList.h" + +int decode_tracking_area_identity_list(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + trackingareaidentitylist->typeoflist = (*(buffer + decoded) >> 5) & 0x3; + trackingareaidentitylist->numberofelements = *(buffer + decoded) & 0x1f; + decoded++; + trackingareaidentitylist->mccdigit2 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentitylist->mccdigit1 = *(buffer + decoded) & 0xf; + decoded++; + trackingareaidentitylist->mncdigit3 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentitylist->mccdigit3 = *(buffer + decoded) & 0xf; + decoded++; + trackingareaidentitylist->mncdigit2 = (*(buffer + decoded) >> 4) & 0xf; + trackingareaidentitylist->mncdigit1 = *(buffer + decoded) & 0xf; + decoded++; + //IES_DECODE_U16(trackingareaidentitylist->tac, *(buffer + decoded)); + IES_DECODE_U16(buffer, decoded, trackingareaidentitylist->tac); +#if defined (NAS_DEBUG) + dump_tracking_area_identity_list_xml(trackingareaidentitylist, iei); +#endif + return decoded; +} + +int encode_tracking_area_identity_list(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRACKING_AREA_IDENTITY_LIST_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_tracking_area_identity_list_xml(trackingareaidentitylist, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | + ((trackingareaidentitylist->typeoflist & 0x3) << 5) | + (trackingareaidentitylist->numberofelements & 0x1f); + encoded++; + *(buffer + encoded) = 0x00 | ((trackingareaidentitylist->mccdigit2 & 0xf) << 4) | + (trackingareaidentitylist->mccdigit1 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((trackingareaidentitylist->mncdigit3 & 0xf) << 4) | + (trackingareaidentitylist->mccdigit3 & 0xf); + encoded++; + *(buffer + encoded) = 0x00 | ((trackingareaidentitylist->mncdigit2 & 0xf) << 4) | + (trackingareaidentitylist->mncdigit1 & 0xf); + encoded++; + IES_ENCODE_U16(buffer, encoded, trackingareaidentitylist->tac); + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_tracking_area_identity_list_xml(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei) +{ + printf("<Tracking Area Identity List>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <Type of list>%u</Type of list>\n", trackingareaidentitylist->typeoflist); + printf(" <Number of elements>%u</Number of elements>\n", trackingareaidentitylist->numberofelements); + printf(" <MCC digit 2>%u</MCC digit 2>\n", trackingareaidentitylist->mccdigit2); + printf(" <MCC digit 1>%u</MCC digit 1>\n", trackingareaidentitylist->mccdigit1); + printf(" <MNC digit 3>%u</MNC digit 3>\n", trackingareaidentitylist->mncdigit3); + printf(" <MCC digit 3>%u</MCC digit 3>\n", trackingareaidentitylist->mccdigit3); + printf(" <MNC digit 2>%u</MNC digit 2>\n", trackingareaidentitylist->mncdigit2); + printf(" <MNC digit 1>%u</MNC digit 1>\n", trackingareaidentitylist->mncdigit1); + printf(" <TAC>0x%.4x</TAC>\n", trackingareaidentitylist->tac); + printf("</Tracking Area Identity List>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h new file mode 100644 index 0000000000..bcf08f5bc5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h @@ -0,0 +1,37 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TRACKING_AREA_IDENTITY_LIST_H_ +#define TRACKING_AREA_IDENTITY_LIST_H_ + +#define TRACKING_AREA_IDENTITY_LIST_MINIMUM_LENGTH 8 +#define TRACKING_AREA_IDENTITY_LIST_MAXIMUM_LENGTH 98 + +typedef struct TrackingAreaIdentityList_tag { + /* XXX - The only supported type of list is a list of TACs + * belonging to one PLMN, with consecutive TAC values */ +//#define TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_NON_CONSECUTIVE_TACS 0b00 +#define TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS 0b01 +//#define TRACKING_AREA_IDENTITY_LIST_MANY_PLMNS 0b10 + uint8_t typeoflist:2; + uint8_t numberofelements:5; + uint8_t mccdigit2:4; + uint8_t mccdigit1:4; + uint8_t mncdigit3:4; + uint8_t mccdigit3:4; + uint8_t mncdigit2:4; + uint8_t mncdigit1:4; + uint16_t tac; +} TrackingAreaIdentityList; + +int encode_tracking_area_identity_list(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_tracking_area_identity_list(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_tracking_area_identity_list_xml(TrackingAreaIdentityList *trackingareaidentitylist, uint8_t iei); + +#endif /* TRACKING AREA IDENTITY LIST_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.c new file mode 100644 index 0000000000..786a0081e9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrafficFlowAggregateDescription.h" + +int decode_traffic_flow_aggregate_description(TrafficFlowAggregateDescription *trafficflowaggregatedescription, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_traffic_flow_aggregate_description(TrafficFlowAggregateDescription *trafficflowaggregatedescription, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h new file mode 100644 index 0000000000..339dd0eee0 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_H_ +#define TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_H_ + +#define TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MINIMUM_LENGTH 1 +#define TRAFFIC_FLOW_AGGREGATE_DESCRIPTION_MAXIMUM_LENGTH 1 + +typedef struct { + uint8_t field; +} TrafficFlowAggregateDescription; + +int encode_traffic_flow_aggregate_description(TrafficFlowAggregateDescription *trafficflowaggregatedescription, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_traffic_flow_aggregate_description_xml(TrafficFlowAggregateDescription *trafficflowaggregatedescription, uint8_t iei); + +int decode_traffic_flow_aggregate_description(TrafficFlowAggregateDescription *trafficflowaggregatedescription, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* TRAFFIC FLOW AGGREGATE DESCRIPTION_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.c new file mode 100644 index 0000000000..39b398df14 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.c @@ -0,0 +1,520 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TrafficFlowTemplate.h" + +static int decode_traffic_flow_template_delete_packet(DeletePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int decode_traffic_flow_template_create_tft(CreateNewTft* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int decode_traffic_flow_template_add_packet(AddPacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int decode_traffic_flow_template_replace_packet(ReplacePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); + +static int decode_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int decode_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); + +static int encode_traffic_flow_template_delete_packet(DeletePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int encode_traffic_flow_template_create_tft(CreateNewTft* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int encode_traffic_flow_template_add_packet(AddPacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int encode_traffic_flow_template_replace_packet(ReplacePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); + +static int encode_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); +static int encode_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len); + +static void dump_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters); +static void dump_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters); + +int decode_traffic_flow_template(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + int decoded_result = 0; + uint8_t ielen = 0; + + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + trafficflowtemplate->tftoperationcode = (*(buffer + decoded) >> 5) & 0x7; + trafficflowtemplate->ebit = (*(buffer + decoded) >> 4) & 0x1; + trafficflowtemplate->numberofpacketfilters = *(buffer + decoded) & 0xf; + decoded++; + + /* Decoding packet filter list */ + if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_DELETE_PACKET) + { + decoded_result = decode_traffic_flow_template_delete_packet(&trafficflowtemplate->packetfilterlist.deletepacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + decoded), len - decoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE) + { + decoded_result = decode_traffic_flow_template_create_tft(&trafficflowtemplate->packetfilterlist.createtft, trafficflowtemplate->numberofpacketfilters, (buffer + decoded), len - decoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_ADD_PACKET) + { + decoded_result = decode_traffic_flow_template_add_packet(&trafficflowtemplate->packetfilterlist.addpacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + decoded), len - decoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_REPLACE_PACKET) + { + decoded_result = decode_traffic_flow_template_replace_packet(&trafficflowtemplate->packetfilterlist.replacepacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + decoded), len - decoded); + } + +#if defined (NAS_DEBUG) + dump_traffic_flow_template_xml(trafficflowtemplate, iei); +#endif + if (decoded_result < 0) { + return decoded_result; + } + return (decoded + decoded_result); +} + +int encode_traffic_flow_template(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, TRAFFIC_FLOW_TEMPLATE_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_traffic_flow_template_xml(trafficflowtemplate, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = 0x00 | ((trafficflowtemplate->tftoperationcode & 0x7) << 5) | ((trafficflowtemplate->ebit & 0x1) << 4) | (trafficflowtemplate->numberofpacketfilters & 0xf); + encoded++; + + /* Encoding packet filter list */ + if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_DELETE_PACKET) + { + encoded += encode_traffic_flow_template_delete_packet(&trafficflowtemplate->packetfilterlist.deletepacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + encoded), len - encoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE) + { + encoded += encode_traffic_flow_template_create_tft(&trafficflowtemplate->packetfilterlist.createtft, trafficflowtemplate->numberofpacketfilters, (buffer + encoded), len - encoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_ADD_PACKET) + { + encoded += encode_traffic_flow_template_add_packet(&trafficflowtemplate->packetfilterlist.addpacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + encoded), len - encoded); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_REPLACE_PACKET) + { + encoded += encode_traffic_flow_template_replace_packet(&trafficflowtemplate->packetfilterlist.replacepacketfilter, trafficflowtemplate->numberofpacketfilters, (buffer + encoded), len - encoded); + } + + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_traffic_flow_template_xml(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei) +{ + printf("<Traffic Flow Template>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <TFT operation code>%u</TFT operation code>\n", trafficflowtemplate->tftoperationcode); + printf(" <E bit>%u</E bit>\n", trafficflowtemplate->ebit); + printf(" <Number of packet filters>%u</Number of packet filters>\n", trafficflowtemplate->numberofpacketfilters); + + if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_DELETE_PACKET) + { + dump_traffic_flow_template_packet_filter_identifiers(&trafficflowtemplate->packetfilterlist.deletepacketfilter, trafficflowtemplate->numberofpacketfilters); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE) + { + dump_traffic_flow_template_packet_filters(&trafficflowtemplate->packetfilterlist.createtft, trafficflowtemplate->numberofpacketfilters); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_ADD_PACKET) + { + dump_traffic_flow_template_packet_filters(&trafficflowtemplate->packetfilterlist.addpacketfilter, trafficflowtemplate->numberofpacketfilters); + } + else if (trafficflowtemplate->tftoperationcode == TRAFFIC_FLOW_TEMPLATE_OPCODE_REPLACE_PACKET) + { + dump_traffic_flow_template_packet_filters(&trafficflowtemplate->packetfilterlist.replacepacketfilter, trafficflowtemplate->numberofpacketfilters); + } + + printf("</Traffic Flow Template>\n"); +} + +static int decode_traffic_flow_template_delete_packet(DeletePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return decode_traffic_flow_template_packet_filter_identifiers(packetfilter, nbpacketfilters, buffer, len); +} + +static int decode_traffic_flow_template_create_tft(CreateNewTft* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return decode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int decode_traffic_flow_template_add_packet(AddPacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return decode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int decode_traffic_flow_template_replace_packet(ReplacePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return decode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int decode_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + int decoded = 0, i; + + for (i = 0; (i < nbpacketfilters) && (len - decoded > 0); i++) + { + /* Packet filter identifier */ + IES_DECODE_U8(buffer, decoded, (*packetfilteridentifiers)[i].identifier); + } + + return decoded; +} + +static int decode_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + int decoded = 0, i, j; + + for (i = 0; (i < nbpacketfilters); i++) + { + if (len - decoded <= 0) { + /* Mismatch between the number of packet filters subfield, + * and the number of packet filters in the packet filter list */ + return (TLV_DECODE_VALUE_DOESNT_MATCH); + } + /* Initialize the packet filter presence flag indicator */ + (*packetfilters)[i].packetfilter.flags = 0; + /* Packet filter direction */ + (*packetfilters)[i].direction = *(buffer + decoded) >> 4; + /* Packet filter identifier */ + (*packetfilters)[i].identifier = *(buffer + decoded) & 0x0f; + decoded++; + /* Packet filter evaluation precedence */ + IES_DECODE_U8(buffer, decoded, (*packetfilters)[i].eval_precedence); + /* Length of the Packet filter contents field */ + uint8_t pkflen; + IES_DECODE_U8(buffer, decoded, pkflen); + /* Packet filter contents */ + int pkfstart = decoded; + while (decoded - pkfstart < pkflen) + { + /* Packet filter component type identifier */ + uint8_t component_type; + IES_DECODE_U8(buffer, decoded, component_type); + + switch (component_type) + { + case TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR: + /* IPv4 remote address type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG; + for (j = 0; j < TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE; j++) + { + (*packetfilters)[i].packetfilter.ipv4remoteaddr[j].addr = *(buffer + decoded); + (*packetfilters)[i].packetfilter.ipv4remoteaddr[j].mask = *(buffer + decoded + TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE); + decoded++; + } + decoded += TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE; + break; + + case TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR: + /* IPv6 remote address type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR_FLAG; + for (j = 0; j < TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE; j++) + { + (*packetfilters)[i].packetfilter.ipv6remoteaddr[j].addr = *(buffer + decoded); + (*packetfilters)[i].packetfilter.ipv6remoteaddr[j].mask = *(buffer + decoded + TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE); + decoded++; + } + decoded += TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE; + break; + + case TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER: + /* Protocol identifier/Next header type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG; + IES_DECODE_U8(buffer, decoded, (*packetfilters)[i].packetfilter.protocolidentifier_nextheader); + break; + + case TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT: + /* Single local port type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG; + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.singlelocalport); + break; + + case TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE: + /* Local port range type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE_FLAG; + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.localportrange.lowlimit); + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.localportrange.highlimit); + break; + + case TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT: + /* Single remote port type */ + (*packetfilters)[i].packetfilter.flags |=TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG ; + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.singleremoteport); + break; + + case TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE: + /* Remote port range type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE_FLAG; + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.remoteportrange.lowlimit); + IES_DECODE_U16(buffer, decoded, (*packetfilters)[i].packetfilter.remoteportrange.highlimit); + break; + + case TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX: + /* Security parameter index type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX_FLAG; + IES_DECODE_U32(buffer, decoded, (*packetfilters)[i].packetfilter.securityparameterindex); + break; + + case TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS: + /* Type of service/Traffic class type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS_FLAG; + IES_DECODE_U8(buffer, decoded, (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.value); + IES_DECODE_U8(buffer, decoded, (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.mask); + break; + + case TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL: + /* Flow label type */ + (*packetfilters)[i].packetfilter.flags |= TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL_FLAG; + IES_DECODE_U24(buffer, decoded, (*packetfilters)[i].packetfilter.flowlabel); + break; + + default: + /* Packet filter component type identifier is not valid */ + return (TLV_DECODE_UNEXPECTED_IEI); + break; + } + } + } + + if (len - decoded != 0) { + /* Mismatch between the number of packet filters subfield, + * and the number of packet filters in the packet filter list */ + return (TLV_DECODE_VALUE_DOESNT_MATCH); + } + return decoded; +} + +static int encode_traffic_flow_template_delete_packet(DeletePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return encode_traffic_flow_template_packet_filter_identifiers(packetfilter, nbpacketfilters, buffer, len); +} + +static int encode_traffic_flow_template_create_tft(CreateNewTft* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return encode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int encode_traffic_flow_template_add_packet(AddPacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return encode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int encode_traffic_flow_template_replace_packet(ReplacePacketFilter* packetfilter, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + return encode_traffic_flow_template_packet_filters(packetfilter, nbpacketfilters, buffer, len); +} + +static int encode_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + int encoded = 0, i; + + for (i = 0; (i < nbpacketfilters) && (len - encoded > 0); i++) + { + /* Packet filter identifier */ + IES_ENCODE_U8(buffer, encoded, (*packetfilteridentifiers)[i].identifier); + } + + return encoded; +} + +static int encode_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters, uint8_t *buffer, uint32_t len) +{ + int encoded = 0, i, j; + + for (i = 0; (i < nbpacketfilters) && (len - encoded > 0); i++) + { + if (len - encoded <= 0) { + /* Mismatch between the number of packet filters subfield, + * and the number of packet filters in the packet filter list */ + return (TLV_DECODE_VALUE_DOESNT_MATCH); + } + /* Packet filter identifier and direction */ + IES_ENCODE_U8(buffer, encoded, (0x00 | ((*packetfilters)[i].direction << 4) | ((*packetfilters)[i].identifier))); + /* Packet filter evaluation precedence */ + IES_ENCODE_U8(buffer, encoded, (*packetfilters)[i].eval_precedence); + /* Save address of the Packet filter contents field length */ + uint8_t* pkflenPtr = buffer + encoded; + encoded++; + /* Packet filter contents */ + int pkfstart = encoded; + uint16_t flag = TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG; + while (flag <= TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL_FLAG) + { + switch ((*packetfilters)[i].packetfilter.flags & flag) + { + case TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG: + /* IPv4 remote address type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR); + for (j = 0; j < TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE; j++) + { + *(buffer + encoded) = (*packetfilters)[i].packetfilter.ipv4remoteaddr[j].addr; + *(buffer + encoded + TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE) = (*packetfilters)[i].packetfilter.ipv4remoteaddr[j].mask; + encoded++; + } + encoded += TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE; + break; + + case TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR_FLAG: + /* IPv6 remote address type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR); + for (j = 0; j < TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE; j++) + { + *(buffer + encoded) = (*packetfilters)[i].packetfilter.ipv6remoteaddr[j].addr; + *(buffer + encoded + TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE) = (*packetfilters)[i].packetfilter.ipv6remoteaddr[j].mask; + encoded++; + } + encoded += TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE; + break; + + case TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG: + /* Protocol identifier/Next header type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER); + IES_ENCODE_U8(buffer, encoded, (*packetfilters)[i].packetfilter.protocolidentifier_nextheader); + break; + + case TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG: + /* Single local port type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.singlelocalport); + break; + + case TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE_FLAG: + /* Local port range type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.localportrange.lowlimit); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.localportrange.highlimit); + break; + + case TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG: + /* Single remote port type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.singleremoteport); + break; + + case TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE_FLAG: + /* Remote port range type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.remoteportrange.lowlimit); + IES_ENCODE_U16(buffer, encoded, (*packetfilters)[i].packetfilter.remoteportrange.highlimit); + break; + + case TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX_FLAG: + /* Security parameter index type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX); + IES_ENCODE_U32(buffer, encoded, (*packetfilters)[i].packetfilter.securityparameterindex); + break; + + case TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS_FLAG: + /* Type of service/Traffic class type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS); + IES_ENCODE_U8(buffer, encoded, (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.value); + IES_ENCODE_U8(buffer, encoded, (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.mask); + break; + + case TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL_FLAG: + /* Flow label type */ + IES_ENCODE_U8(buffer, encoded, TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL); + IES_ENCODE_U24(buffer, encoded, (*packetfilters)[i].packetfilter.flowlabel & 0x000fffff); + break; + + default: + break; + } + flag = flag << 1; + } + /* Length of the Packet filter contents field */ + *pkflenPtr = encoded - pkfstart; + } + + return encoded; +} + +static void dump_traffic_flow_template_packet_filter_identifiers(PacketFilterIdentifiers* packetfilteridentifiers, uint8_t nbpacketfilters) +{ + int i; + printf(" <Packet filter list>\n"); + for (i = 0; i < nbpacketfilters; i++) + { + printf(" <Identifier>%u</Identifier>\n", (*packetfilteridentifiers)[i].identifier); + } + printf(" </Packet filter list>\n"); +} + +static void dump_traffic_flow_template_packet_filters(PacketFilters* packetfilters, uint8_t nbpacketfilters) +{ + int i; + printf(" <Packet filter list>\n"); + for (i = 0; i < nbpacketfilters; i++) + { + printf(" <Identifier>%u</Identifier>\n", (*packetfilters)[i].identifier); + printf(" <Direction>%u</Direction>\n", (*packetfilters)[i].direction); + printf(" <Evaluation precedence>%u</Evaluation precedence>\n", (*packetfilters)[i].eval_precedence); + printf(" <Packet filter>\n"); + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG) + { + printf(" <IPv4 remote address>%u.%u.%u.%u</IPv4 remote address>\n", (*packetfilters)[i].packetfilter.ipv4remoteaddr[0].addr, (*packetfilters)[i].packetfilter.ipv4remoteaddr[1].addr, (*packetfilters)[i].packetfilter.ipv4remoteaddr[2].addr, (*packetfilters)[i].packetfilter.ipv4remoteaddr[3].addr); + printf(" <IPv4 remote address mask>%u.%u.%u.%u</IPv4 remote address mask>\n", (*packetfilters)[i].packetfilter.ipv4remoteaddr[0].mask, (*packetfilters)[i].packetfilter.ipv4remoteaddr[1].mask, (*packetfilters)[i].packetfilter.ipv4remoteaddr[2].mask, (*packetfilters)[i].packetfilter.ipv4remoteaddr[3].mask); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR_FLAG) + { + printf(" <Ipv6 remote address>%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x</Ipv6 remote address>\n", (*packetfilters)[i].packetfilter.ipv6remoteaddr[0].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[1].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[2].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[3].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[4].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[5].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[6].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[7].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[8].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[9].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[10].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[11].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[12].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[13].addr, (*packetfilters)[i].packetfilter.ipv6remoteaddr[14].addr, (*packetfilters)[i].packetfilter. +ipv6remoteaddr[15].addr); + printf(" <Ipv6 remote address mask>%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x:%x%.2x</Ipv6 remote address mask>\n", (*packetfilters)[i].packetfilter.ipv6remoteaddr[0].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[1].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[2].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[3].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[4].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[5].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[6].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[7].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[8].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[9].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[10].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[11].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[12].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[13].mask, (*packetfilters)[i].packetfilter.ipv6remoteaddr[14].mask, (*packetfilters)[i]. +packetfilter.ipv6remoteaddr[15].mask); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG) + { + printf(" <Protocol identifier - Next header type>%u</Protocol identifier - Next header type>\n", (*packetfilters)[i].packetfilter.protocolidentifier_nextheader); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG) + { + printf(" <Single local port>%u</Single local port>\n", (*packetfilters)[i].packetfilter.singlelocalport); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE_FLAG) + { + printf(" <Local port range low limit>%u</Local port range low limit>\n", (*packetfilters)[i].packetfilter.localportrange.lowlimit); + printf(" <Local port range high limit>%u</Local port range high limit>\n", (*packetfilters)[i].packetfilter.localportrange.highlimit); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG) + { + printf(" <Single remote port>%u</Single remote port>\n", (*packetfilters)[i].packetfilter.singleremoteport); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE_FLAG) + { + printf(" <Remote port range low limit>%u</Remote port range low limit>\n", (*packetfilters)[i].packetfilter.remoteportrange.lowlimit); + printf(" <Remote port range high limit>%u</Remote port range high limit>\n", (*packetfilters)[i].packetfilter.remoteportrange.highlimit); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX_FLAG) + { + printf(" <Security parameter index>%u</Security parameter index>\n", (*packetfilters)[i].packetfilter.securityparameterindex); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS_FLAG) + { + printf(" <Type of service - Traffic class>%u</Type of service - Traffic class>\n", (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.value); + printf(" <Type of service - Traffic class mask>%u</Type of service - Traffic class mask>\n", (*packetfilters)[i].packetfilter.typdeofservice_trafficclass.mask); + } + if ((*packetfilters)[i].packetfilter.flags & TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL_FLAG) + { + printf(" <Flow label>%u</Flow label>\n", (*packetfilters)[i].packetfilter.flowlabel); + } + printf(" </Packet filter>\n"); + } + printf(" </Packet filter list>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h new file mode 100644 index 0000000000..9b22cb8f82 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h @@ -0,0 +1,171 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#ifndef TRAFFIC_FLOW_TEMPLATE_H_ +#define TRAFFIC_FLOW_TEMPLATE_H_ + +#define TRAFFIC_FLOW_TEMPLATE_MINIMUM_LENGTH 2 +#define TRAFFIC_FLOW_TEMPLATE_MAXIMUM_LENGTH 256 + +/* + * ---------------------------------------------------------------------------- + * Packet filter list + * ---------------------------------------------------------------------------- + */ + +#define TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR 0b00010000 +#define TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR 0b00100000 +#define TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER 0b00110000 +#define TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT 0b01000000 +#define TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE 0b01000001 +#define TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT 0b01010000 +#define TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE 0b01010001 +#define TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX 0b01100000 +#define TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS 0b01110000 +#define TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL 0b10000000 + +/* + * Packet filter content + * --------------------- + */ +typedef struct { +#define TRAFFIC_FLOW_TEMPLATE_IPV4_REMOTE_ADDR_FLAG (1<<0) +#define TRAFFIC_FLOW_TEMPLATE_IPV6_REMOTE_ADDR_FLAG (1<<1) +#define TRAFFIC_FLOW_TEMPLATE_PROTOCOL_NEXT_HEADER_FLAG (1<<2) +#define TRAFFIC_FLOW_TEMPLATE_SINGLE_LOCAL_PORT_FLAG (1<<3) +#define TRAFFIC_FLOW_TEMPLATE_LOCAL_PORT_RANGE_FLAG (1<<4) +#define TRAFFIC_FLOW_TEMPLATE_SINGLE_REMOTE_PORT_FLAG (1<<5) +#define TRAFFIC_FLOW_TEMPLATE_REMOTE_PORT_RANGE_FLAG (1<<6) +#define TRAFFIC_FLOW_TEMPLATE_SECURITY_PARAMETER_INDEX_FLAG (1<<7) +#define TRAFFIC_FLOW_TEMPLATE_TYPE_OF_SERVICE_TRAFFIC_CLASS_FLAG (1<<8) +#define TRAFFIC_FLOW_TEMPLATE_FLOW_LABEL_FLAG (1<<9) + uint16_t flags; +#define TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE 4 + struct { + uint8_t addr; + uint8_t mask; + } ipv4remoteaddr[TRAFFIC_FLOW_TEMPLATE_IPV4_ADDR_SIZE]; +#define TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE 16 + struct { + uint8_t addr; + uint8_t mask; + } ipv6remoteaddr[TRAFFIC_FLOW_TEMPLATE_IPV6_ADDR_SIZE]; + uint8_t protocolidentifier_nextheader; + uint16_t singlelocalport; + struct { + uint16_t lowlimit; + uint16_t highlimit; + } localportrange; + uint16_t singleremoteport; + struct { + uint16_t lowlimit; + uint16_t highlimit; + } remoteportrange; + uint32_t securityparameterindex; + struct { + uint8_t value; + uint8_t mask; + } typdeofservice_trafficclass; + uint32_t flowlabel; +} PacketFilter; + +/* + * Packet filter list when the TFP operation is "delete existing TFT" + * and "no TFT operation" shall be empty. + * --------------------------------------------------------------- + */ +typedef struct {} NoPacketFilter; + +typedef NoPacketFilter DeleteExistingTft; +typedef NoPacketFilter NoTftOperation; + +/* + * Packet filter list when the TFT operation is "delete existing TFT" + * shall contain a variable number of packet filter identifiers. + * ------------------------------------------------------------------ + */ +#define TRAFFIC_FLOW_TEMPLATE_PACKET_IDENTIFIER_MAX 16 +typedef struct { + uint8_t identifier; +} PacketFilterIdentifiers[TRAFFIC_FLOW_TEMPLATE_PACKET_IDENTIFIER_MAX]; + +typedef PacketFilterIdentifiers DeletePacketFilter; + +/* + * Packet filter list when the TFT operation is "create new TFT", + * "add packet filters to existing TFT" and "replace packet filters + * in existing TFT" shall contain a variable number of packet filters + * ------------------------------------------------------------------ + */ +#define TRAFFIC_FLOW_TEMPLATE_NB_PACKET_FILTERS_MAX 4 +typedef struct { + uint8_t identifier:4; +#define TRAFFIC_FLOW_TEMPLATE_PRE_REL7_TFT_FILTER 0b00 +#define TRAFFIC_FLOW_TEMPLATE_DOWNLINK_ONLY 0b01 +#define TRAFFIC_FLOW_TEMPLATE_UPLINK_ONLY 0b10 +#define TRAFFIC_FLOW_TEMPLATE_BIDIRECTIONAL 0b11 + uint8_t direction:2; + uint8_t eval_precedence; + PacketFilter packetfilter; +} PacketFilters[TRAFFIC_FLOW_TEMPLATE_NB_PACKET_FILTERS_MAX]; + +typedef PacketFilters CreateNewTft; +typedef PacketFilters AddPacketFilter; +typedef PacketFilters ReplacePacketFilter; + +/* + * Packet filter list + * ------------------ + */ +typedef union { + CreateNewTft createtft; + DeleteExistingTft deletetft; + AddPacketFilter addpacketfilter; + ReplacePacketFilter replacepacketfilter; + DeletePacketFilter deletepacketfilter; + NoTftOperation notftoperation; +} PacketFilterList; + +/* + * ---------------------------------------------------------------------------- + * Parameters list + * ---------------------------------------------------------------------------- + */ + +typedef struct { + /* TODO */ +} ParameterList; + +/* + * ---------------------------------------------------------------------------- + * Traffic Flow Template information element + * ---------------------------------------------------------------------------- + */ + +typedef struct TrafficFlowTemplate_tag { +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_SPARE 0b000 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_CREATE 0b001 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_DELETE 0b010 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_ADD_PACKET 0b011 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_REPLACE_PACKET 0b100 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_DELETE_PACKET 0b101 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_NO_OPERATION 0b110 +#define TRAFFIC_FLOW_TEMPLATE_OPCODE_RESERVED 0b111 + uint8_t tftoperationcode:3; +#define TRAFFIC_FLOW_TEMPLATE_PARAMETER_LIST_IS_NOT_INCLUDED 0 +#define TRAFFIC_FLOW_TEMPLATE_PARAMETER_LIST_IS_INCLUDED 1 + uint8_t ebit:1; + uint8_t numberofpacketfilters:4; + PacketFilterList packetfilterlist; + ParameterList parameterlist; +} TrafficFlowTemplate; + +int encode_traffic_flow_template(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_traffic_flow_template(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_traffic_flow_template_xml(TrafficFlowTemplate *trafficflowtemplate, uint8_t iei); + +#endif /* TRAFFIC FLOW TEMPLATE_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.c b/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.c new file mode 100644 index 0000000000..04ddf4e6d9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.c @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "TransactionIdentifier.h" + +int decode_transaction_identifier(TransactionIdentifier *transactionidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + +int encode_transaction_identifier(TransactionIdentifier *transactionidentifier, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + return 0; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h b/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h new file mode 100644 index 0000000000..5ea7b92449 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h @@ -0,0 +1,24 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef TRANSACTION_IDENTIFIER_H_ +#define TRANSACTION_IDENTIFIER_H_ + +#define TRANSACTION_IDENTIFIER_MINIMUM_LENGTH 1 +#define TRANSACTION_IDENTIFIER_MAXIMUM_LENGTH 1 + +typedef struct { + uint8_t field; +} TransactionIdentifier; + +int encode_transaction_identifier(TransactionIdentifier *transactionidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_transaction_identifier_xml(TransactionIdentifier *transactionidentifier, uint8_t iei); + +int decode_transaction_identifier(TransactionIdentifier *transactionidentifier, uint8_t iei, uint8_t *buffer, uint32_t len); + +#endif /* TRANSACTION IDENTIFIER_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.c b/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.c new file mode 100644 index 0000000000..22db2791a6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.c @@ -0,0 +1,116 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "UeNetworkCapability.h" + +int decode_ue_network_capability(UeNetworkCapability *uenetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + DECODE_U8(buffer + decoded, ielen, decoded); + + CHECK_LENGTH_DECODER(len - decoded, ielen); + uenetworkcapability->eea = *(buffer + decoded); + decoded++; + uenetworkcapability->eia = *(buffer + decoded); + decoded++; + + /* Parts below not mandatory and may not be present */ + if (ielen > 2) { + uenetworkcapability->uea = *(buffer + decoded); + decoded++; + + if (ielen > 3) { + uenetworkcapability->ucs2 = (*(buffer + decoded) >> 7) & 0x1; + uenetworkcapability->uia = *(buffer + decoded) & 0x7f; + decoded++; + + if (ielen >= 4) { + uenetworkcapability->spare = (*(buffer + decoded) >> 5) & 0x7; + uenetworkcapability->csfb = (*(buffer + decoded) >> 4) & 0x1; + uenetworkcapability->lpp = (*(buffer + decoded) >> 3) & 0x1; + uenetworkcapability->lcs = (*(buffer + decoded) >> 2) & 0x1; + uenetworkcapability->srvcc = (*(buffer + decoded) >> 1) & 0x1; + uenetworkcapability->nf = *(buffer + decoded) & 0x1; + decoded++; + } + } + } + + if ((ielen + 2) != decoded) { + decoded = ielen + 1 + (iei > 0 ? 1 : 0) /* Size of header for this IE */; + } + +#if defined (NAS_DEBUG) + dump_ue_network_capability_xml(uenetworkcapability, iei); +#endif + return decoded; +} +int encode_ue_network_capability(UeNetworkCapability *uenetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, UE_NETWORK_CAPABILITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ue_network_capability_xml(uenetworkcapability, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = uenetworkcapability->eea; + encoded++; + *(buffer + encoded) = uenetworkcapability->eia; + encoded++; + *(buffer + encoded) = uenetworkcapability->uea; + encoded++; + *(buffer + encoded) = 0x00 | ((uenetworkcapability->ucs2 & 0x1) << 7) | + (uenetworkcapability->uia & 0x7f); + encoded++; + + *(buffer + encoded) = 0x00 | + //((uenetworkcapability->spare & 0x7) << 5) | // spare coded as zero + ((uenetworkcapability->csfb & 0x1) << 4) | + ((uenetworkcapability->lpp & 0x1) << 3) | + ((uenetworkcapability->lcs & 0x1) << 2) | + ((uenetworkcapability->srvcc & 0x1) << 1) | + (uenetworkcapability->nf & 0x1); + encoded++; + + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_ue_network_capability_xml(UeNetworkCapability *uenetworkcapability, uint8_t iei) +{ + printf("<Ue Network Capability>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EEA>%02x</EEA>\n", uenetworkcapability->eea); + printf(" <EIA>%02x</EIA>\n", uenetworkcapability->eia); + printf(" <UEA>%02x</UEA>\n", uenetworkcapability->uea); + printf(" <UCS2>%u</UCS2>\n", uenetworkcapability->ucs2); + printf(" <UIA>%u</UIA>\n", uenetworkcapability->uia); + printf(" <SPARE>%u</SPARE>\n", uenetworkcapability->spare); + printf(" <CSFB>%u</CSFB>\n", uenetworkcapability->csfb); + printf(" <LPP>%u</LPP>\n", uenetworkcapability->lpp); + printf(" <LCS>%u</LCS>\n", uenetworkcapability->lcs); + printf(" <SR VCC>%u</SR VCC>\n", uenetworkcapability->srvcc); + printf(" <NF>%u<NF/>\n", uenetworkcapability->nf); + printf("</Ue Network Capability>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h b/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h new file mode 100644 index 0000000000..34dff1194b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h @@ -0,0 +1,83 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef UE_NETWORK_CAPABILITY_H_ +#define UE_NETWORK_CAPABILITY_H_ + +#define UE_NETWORK_CAPABILITY_MINIMUM_LENGTH 4 +#define UE_NETWORK_CAPABILITY_MAXIMUM_LENGTH 7 + +typedef struct UeNetworkCapability_tag { + /* EPS encryption algorithms supported (octet 3) */ +#define UE_NETWORK_CAPABILITY_EEA0 0b10000000 +#define UE_NETWORK_CAPABILITY_EEA1 0b01000000 +#define UE_NETWORK_CAPABILITY_EEA2 0b00100000 +#define UE_NETWORK_CAPABILITY_EEA3 0b00010000 +#define UE_NETWORK_CAPABILITY_EEA4 0b00001000 +#define UE_NETWORK_CAPABILITY_EEA5 0b00000100 +#define UE_NETWORK_CAPABILITY_EEA6 0b00000010 +#define UE_NETWORK_CAPABILITY_EEA7 0b00000001 + uint8_t eea; + /* EPS integrity algorithms supported (octet 4) */ +#define UE_NETWORK_CAPABILITY_EIA0 0b10000000 +#define UE_NETWORK_CAPABILITY_EIA1 0b01000000 +#define UE_NETWORK_CAPABILITY_EIA2 0b00100000 +#define UE_NETWORK_CAPABILITY_EIA3 0b00010000 +#define UE_NETWORK_CAPABILITY_EIA4 0b00001000 +#define UE_NETWORK_CAPABILITY_EIA5 0b00000100 +#define UE_NETWORK_CAPABILITY_EIA6 0b00000010 +#define UE_NETWORK_CAPABILITY_EIA7 0b00000001 + uint8_t eia; + /* UMTS encryption algorithms supported (octet 5) */ +#define UE_NETWORK_CAPABILITY_UEA0 0b10000000 +#define UE_NETWORK_CAPABILITY_UEA1 0b01000000 +#define UE_NETWORK_CAPABILITY_UEA2 0b00100000 +#define UE_NETWORK_CAPABILITY_UEA3 0b00010000 +#define UE_NETWORK_CAPABILITY_UEA4 0b00001000 +#define UE_NETWORK_CAPABILITY_UEA5 0b00000100 +#define UE_NETWORK_CAPABILITY_UEA6 0b00000010 +#define UE_NETWORK_CAPABILITY_UEA7 0b00000001 + uint8_t uea; + /* UCS2 support (octet 6, bit 8) */ +#define UE_NETWORK_CAPABILITY_DEFAULT_ALPHABET 0 +#define UE_NETWORK_CAPABILITY_UCS2_ALPHABET 1 + uint8_t ucs2:1; + /* UMTS integrity algorithms supported (octet 6) */ +#define UE_NETWORK_CAPABILITY_UIA1 0b01000000 +#define UE_NETWORK_CAPABILITY_UIA2 0b00100000 +#define UE_NETWORK_CAPABILITY_UIA3 0b00010000 +#define UE_NETWORK_CAPABILITY_UIA4 0b00001000 +#define UE_NETWORK_CAPABILITY_UIA5 0b00000100 +#define UE_NETWORK_CAPABILITY_UIA6 0b00000010 +#define UE_NETWORK_CAPABILITY_UIA7 0b00000001 + uint8_t uia:7; + /* Bits 8 to 6 of octet 7 are spare and shall be coded as zero */ + uint8_t spare:3; + /* eNodeB-based access class control for CSFB capability */ +#define UE_NETWORK_CAPABILITY_CSFB 1 + uint8_t csfb:1; + /* LTE Positioning Protocol capability */ +#define UE_NETWORK_CAPABILITY_LPP 1 + uint8_t lpp:1; + /* Location services notification mechanisms capability */ +#define UE_NETWORK_CAPABILITY_LCS 1 + uint8_t lcs:1; + /* 1xSRVCC capability */ +#define UE_NETWORK_CAPABILITY_SRVCC 1 + uint8_t srvcc:1; + /* NF notification procedure capability */ +#define UE_NETWORK_CAPABILITY_NF 1 + uint8_t nf:1; +} UeNetworkCapability; + +int encode_ue_network_capability(UeNetworkCapability *uenetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_ue_network_capability(UeNetworkCapability *uenetworkcapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ue_network_capability_xml(UeNetworkCapability *uenetworkcapability, uint8_t iei); + +#endif /* UE NETWORK CAPABILITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.c b/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.c new file mode 100644 index 0000000000..b424d3d3e9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "UeRadioCapabilityInformationUpdateNeeded.h" + +int decode_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + CHECK_PDU_POINTER_AND_LENGTH_DECODER(buffer, UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_MINIMUM_LENGTH, len); + if (iei > 0) + { + CHECK_IEI_DECODER((*buffer & 0xf0), iei); + } + *ueradiocapabilityinformationupdateneeded = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_ue_radio_capability_information_update_needed_xml(ueradiocapabilityinformationupdateneeded, iei); +#endif + return decoded; +} + +int decode_u8_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t value, uint32_t len) +{ + int decoded = 0; + uint8_t *buffer = &value; + *ueradiocapabilityinformationupdateneeded = *buffer & 0x1; + decoded++; +#if defined (NAS_DEBUG) + dump_ue_radio_capability_information_update_needed_xml(ueradiocapabilityinformationupdateneeded, iei); +#endif + return decoded; +} + +int encode_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t encoded = 0; + /* Checking length and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ue_radio_capability_information_update_needed_xml(ueradiocapabilityinformationupdateneeded, iei); +#endif + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*ueradiocapabilityinformationupdateneeded & 0x1); + encoded++; + return encoded; +} + +uint8_t encode_u8_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded) +{ + uint8_t bufferReturn; + uint8_t *buffer = &bufferReturn; + uint8_t encoded = 0; + uint8_t iei = 0; + dump_ue_radio_capability_information_update_needed_xml(ueradiocapabilityinformationupdateneeded, 0); + *(buffer + encoded) = 0x00 | (iei & 0xf0) | + (*ueradiocapabilityinformationupdateneeded & 0x1); + encoded++; + + return bufferReturn; +} + +void dump_ue_radio_capability_information_update_needed_xml(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei) +{ + printf("<Ue Radio Capability Information Update Needed>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <URC upd>%u</URC upd>\n", *ueradiocapabilityinformationupdateneeded); + printf("</Ue Radio Capability Information Update Needed>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h b/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h new file mode 100644 index 0000000000..41f1c9f27f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h @@ -0,0 +1,26 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_H_ +#define UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_H_ + +#define UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_MINIMUM_LENGTH 1 +#define UE_RADIO_CAPABILITY_INFORMATION_UPDATE_NEEDED_MAXIMUM_LENGTH 1 + +typedef uint8_t UeRadioCapabilityInformationUpdateNeeded; + +int encode_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ue_radio_capability_information_update_needed_xml(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei); + +uint8_t encode_u8_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded); + +int decode_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_u8_ue_radio_capability_information_update_needed(UeRadioCapabilityInformationUpdateNeeded *ueradiocapabilityinformationupdateneeded, uint8_t iei, uint8_t value, uint32_t len); + +#endif /* UE RADIO CAPABILITY INFORMATION UPDATE NEEDED_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.c b/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.c new file mode 100644 index 0000000000..b5c67f75a9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.c @@ -0,0 +1,82 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "UeSecurityCapability.h" + +int decode_ue_security_capability(UeSecurityCapability *uesecuritycapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + int decoded = 0; + uint8_t ielen = 0; + if (iei > 0) + { + CHECK_IEI_DECODER(iei, *buffer); + decoded++; + } + ielen = *(buffer + decoded); + decoded++; + CHECK_LENGTH_DECODER(len - decoded, ielen); + uesecuritycapability->eea = *(buffer + decoded); + decoded++; + uesecuritycapability->eia = *(buffer + decoded); + decoded++; + uesecuritycapability->uea = *(buffer + decoded); + decoded++; + uesecuritycapability->uia = *(buffer + decoded) & 0x7f; + decoded++; + uesecuritycapability->gea = *(buffer + decoded) & 0x7f; + decoded++; +#if defined (NAS_DEBUG) + dump_ue_security_capability_xml(uesecuritycapability, iei); +#endif + return decoded; +} +int encode_ue_security_capability(UeSecurityCapability *uesecuritycapability, uint8_t iei, uint8_t *buffer, uint32_t len) +{ + uint8_t *lenPtr; + uint32_t encoded = 0; + /* Checking IEI and pointer */ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, UE_SECURITY_CAPABILITY_MINIMUM_LENGTH, len); +#if defined (NAS_DEBUG) + dump_ue_security_capability_xml(uesecuritycapability, iei); +#endif + if (iei > 0) + { + *buffer = iei; + encoded++; + } + lenPtr = (buffer + encoded); + encoded ++; + *(buffer + encoded) = uesecuritycapability->eea; + encoded++; + *(buffer + encoded) = uesecuritycapability->eia; + encoded++; + *(buffer + encoded) = uesecuritycapability->uea; + encoded++; + *(buffer + encoded) = 0x00 | + (uesecuritycapability->uia & 0x7f); + encoded++; + *(buffer + encoded) = 0x00 | + (uesecuritycapability->gea & 0x7f); + encoded++; + *lenPtr = encoded - 1 - ((iei > 0) ? 1 : 0); + return encoded; +} + +void dump_ue_security_capability_xml(UeSecurityCapability *uesecuritycapability, uint8_t iei) +{ + printf("<Ue Security Capability>\n"); + if (iei > 0) + /* Don't display IEI if = 0 */ + printf(" <IEI>0x%X</IEI>\n", iei); + printf(" <EEA>%u</EEA>\n", uesecuritycapability->eea); + printf(" <EIA>%u</EIA>\n", uesecuritycapability->eia); + printf(" <UEA>%u</UEA>\n", uesecuritycapability->uea); + printf(" <UIA>%u</UIA>\n", uesecuritycapability->uia); + printf(" <GEA>%u</GEA>\n", uesecuritycapability->gea); + printf("</Ue Security Capability>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h b/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h new file mode 100644 index 0000000000..c0c1cd8adb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h @@ -0,0 +1,71 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "OctetString.h" + +#ifndef UE_SECURITY_CAPABILITY_H_ +#define UE_SECURITY_CAPABILITY_H_ + +#define UE_SECURITY_CAPABILITY_MINIMUM_LENGTH 4 +#define UE_SECURITY_CAPABILITY_MAXIMUM_LENGTH 7 + +typedef struct UeSecurityCapability_tag { + /* EPS encryption algorithms supported (octet 3) */ +#define UE_SECURITY_CAPABILITY_EEA0 0b10000000 +#define UE_SECURITY_CAPABILITY_EEA1 0b01000000 +#define UE_SECURITY_CAPABILITY_EEA2 0b00100000 +#define UE_SECURITY_CAPABILITY_EEA3 0b00010000 +#define UE_SECURITY_CAPABILITY_EEA4 0b00001000 +#define UE_SECURITY_CAPABILITY_EEA5 0b00000100 +#define UE_SECURITY_CAPABILITY_EEA6 0b00000010 +#define UE_SECURITY_CAPABILITY_EEA7 0b00000001 + uint8_t eea; + /* EPS integrity algorithms supported (octet 4) */ +#define UE_SECURITY_CAPABILITY_EIA0 0b10000000 +#define UE_SECURITY_CAPABILITY_EIA1 0b01000000 +#define UE_SECURITY_CAPABILITY_EIA2 0b00100000 +#define UE_SECURITY_CAPABILITY_EIA3 0b00010000 +#define UE_SECURITY_CAPABILITY_EIA4 0b00001000 +#define UE_SECURITY_CAPABILITY_EIA5 0b00000100 +#define UE_SECURITY_CAPABILITY_EIA6 0b00000010 +#define UE_SECURITY_CAPABILITY_EIA7 0b00000001 + uint8_t eia; + /* UMTS encryption algorithms supported (octet 5) */ +#define UE_SECURITY_CAPABILITY_UEA0 0b10000000 +#define UE_SECURITY_CAPABILITY_UEA1 0b01000000 +#define UE_SECURITY_CAPABILITY_UEA2 0b00100000 +#define UE_SECURITY_CAPABILITY_UEA3 0b00010000 +#define UE_SECURITY_CAPABILITY_UEA4 0b00001000 +#define UE_SECURITY_CAPABILITY_UEA5 0b00000100 +#define UE_SECURITY_CAPABILITY_UEA6 0b00000010 +#define UE_SECURITY_CAPABILITY_UEA7 0b00000001 + uint8_t uea; + /* UMTS integrity algorithms supported (octet 6) */ +#define UE_SECURITY_CAPABILITY_UIA1 0b01000000 +#define UE_SECURITY_CAPABILITY_UIA2 0b00100000 +#define UE_SECURITY_CAPABILITY_UIA3 0b00010000 +#define UE_SECURITY_CAPABILITY_UIA4 0b00001000 +#define UE_SECURITY_CAPABILITY_UIA5 0b00000100 +#define UE_SECURITY_CAPABILITY_UIA6 0b00000010 +#define UE_SECURITY_CAPABILITY_UIA7 0b00000001 + uint8_t uia:7; + /* GPRS encryption algorithms supported (octet 7) */ +#define UE_SECURITY_CAPABILITY_GEA1 0b01000000 +#define UE_SECURITY_CAPABILITY_GEA2 0b00100000 +#define UE_SECURITY_CAPABILITY_GEA3 0b00010000 +#define UE_SECURITY_CAPABILITY_GEA4 0b00001000 +#define UE_SECURITY_CAPABILITY_GEA5 0b00000100 +#define UE_SECURITY_CAPABILITY_GEA6 0b00000010 +#define UE_SECURITY_CAPABILITY_GEA7 0b00000001 + uint8_t gea:7; +} UeSecurityCapability; + +int encode_ue_security_capability(UeSecurityCapability *uesecuritycapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +int decode_ue_security_capability(UeSecurityCapability *uesecuritycapability, uint8_t iei, uint8_t *buffer, uint32_t len); + +void dump_ue_security_capability_xml(UeSecurityCapability *uesecuritycapability, uint8_t iei); + +#endif /* UE SECURITY CAPABILITY_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/include/commonDef.h b/openair-cn/NAS/EURECOM-NAS/src/include/commonDef.h new file mode 100644 index 0000000000..bd488a29c5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/include/commonDef.h @@ -0,0 +1,249 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source commonDef.h + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem include + +Author Frederic Maurel + +Description Contains global common definitions + +*****************************************************************************/ +#ifndef __COMMONDEF_H__ +#define __COMMONDEF_H__ + +#include <stdint.h> +#include <stddef.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#define RETURNok (0) +#define RETURNerror (-1) + +#ifndef FALSE +#define FALSE (0) +#endif +#ifndef TRUE +#define TRUE (1) +#endif + +/* + * Name of the environment variable which defines the default directory + * where the NAS application is executed and where are located files + * where non-volatile data are stored + */ +#define DEFAULT_NAS_PATH "PWD" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* +----------------------------------------------------------------------------- + Standard data type definitions +----------------------------------------------------------------------------- +*/ +typedef int8_t SByte_t; /* 8 bit signed integer */ +typedef int8_t Int8_t; /* 8 bit signed integer */ +typedef int16_t Int16_t; /* 16 bit signed integer */ +typedef int32_t Int32_t; /* 32 bit signed integer */ +typedef int64_t Int64_t; /* 64 bit signed integer */ + + +typedef uint8_t Byte_t; /* 8 bit unsigned integer */ +typedef uint8_t UInt8_t; /* 8 bit unsigned integer */ +typedef uint16_t UInt16_t; /* 16 bit unsigned integer */ +typedef uint32_t UInt32_t; /* 32 bit unsigned integer */ +typedef uint64_t UInt64_t; /* 64 bit unsigned integer */ + +/* +----------------------------------------------------------------------------- + Common NAS data type definitions +----------------------------------------------------------------------------- +*/ + +typedef UInt8_t Stat_t; /* Registration status */ +typedef UInt16_t lac_t; /* Location Area Code */ +typedef UInt8_t rac_t; /* Routing Area Code */ +typedef UInt16_t tac_t; /* Tracking Area Code */ +typedef UInt32_t ci_t; /* Cell Identifier */ +typedef UInt8_t AcT_t; /* Access Technology */ + +/* + * International Mobile Subscriber Identity + */ +typedef struct { + Byte_t length; + union { + struct { + Byte_t digit15:4; + Byte_t digit14:4; + Byte_t digit13:4; + Byte_t digit12:4; + Byte_t digit11:4; + Byte_t digit10:4; + Byte_t digit9:4; + Byte_t digit8:4; + Byte_t digit7:4; + Byte_t digit6:4; + Byte_t digit5:4; + Byte_t digit4:4; + Byte_t digit3:4; + Byte_t digit2:4; + Byte_t digit1:4; +#define EVEN_PARITY 0 +#define ODD_PARITY 1 + Byte_t parity:4; + } num; +#define IMSI_SIZE 8 + Byte_t value[IMSI_SIZE]; + } u; +} imsi_t; + +/* + * Mobile subscriber dialing number + */ +typedef struct { + Byte_t ext:1; + /* Type Of Number */ +#define MSISDN_TON_UNKNOWKN 0b000 +#define MSISDN_TON_INTERNATIONAL 0b001 +#define MSISDN_TON_NATIONAL 0b010 +#define MSISDN_TON_NETWORK 0b011 +#define MSISDN_TON_SUBCRIBER 0b100 +#define MSISDN_TON_ABBREVIATED 0b110 +#define MSISDN_TON_RESERVED 0b111 + Byte_t ton:3; + /* Numbering Plan Identification */ +#define MSISDN_NPI_UNKNOWN 0b0000 +#define MSISDN_NPI_ISDN_TELEPHONY 0b0001 +#define MSISDN_NPI_GENERIC 0b0010 +#define MSISDN_NPI_DATA 0b0011 +#define MSISDN_NPI_TELEX 0b0100 +#define MSISDN_NPI_MARITIME_MOBILE 0b0101 +#define MSISDN_NPI_LAND_MOBILE 0b0110 +#define MSISDN_NPI_ISDN_MOBILE 0b0111 +#define MSISDN_NPI_PRIVATE 0b1110 +#define MSISDN_NPI_RESERVED 0b1111 + Byte_t npi:4; + /* Dialing Number */ + struct { + Byte_t lsb:4; + Byte_t msb:4; +#define MSISDN_DIGIT_SIZE 10 + } digit[MSISDN_DIGIT_SIZE]; +} msisdn_t; + +/* + * International Mobile Equipment Identity + */ +typedef imsi_t imei_t; + +/* + * Public Land Mobile Network identifier + * PLMN = BCD encoding (Mobile Country Code + Mobile Network Code) + */ +typedef struct { + Byte_t MCCdigit2:4; + Byte_t MCCdigit1:4; + Byte_t MNCdigit3:4; + Byte_t MCCdigit3:4; + Byte_t MNCdigit2:4; + Byte_t MNCdigit1:4; +} plmn_t; + +/* + * Location Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + lac_t lac; /* Location Area Code */ +} lai_t; + +/* + * GPRS Routing Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + lac_t lac; /* Location Area Code */ + rac_t rac; /* Routing Area Code */ +} RAI_t; + +/* + * EPS Tracking Area Identification + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + tac_t tac; /* Tracking Area Code */ +} tai_t; + +/* + * EPS Globally Unique MME Identity + */ +typedef struct { + plmn_t plmn; /* <MCC> + <MNC> */ + UInt16_t MMEgid; /* MME group identifier */ + UInt8_t MMEcode; /* MME code */ +} gummei_t; + +/* + * EPS Globally Unique Temporary UE Identity + */ +typedef struct { + gummei_t gummei; /* Globally Unique MME Identity */ + UInt32_t m_tmsi; /* M-Temporary Mobile Subscriber Identity */ +} GUTI_t; + +/* Checks PLMN validity */ +#define PLMN_IS_VALID(plmn) (((plmn).MCCdigit1 & \ + (plmn).MCCdigit2 & \ + (plmn).MCCdigit3) != 0x0F) + +/* Checks TAC validity */ +#define TAC_IS_VALID(tac) (((tac) != 0x0000) && ((tac) != 0xFFF0)) + +/* Checks TAI validity */ +#define TAI_IS_VALID(tai) (PLMN_IS_VALID((tai).plmn) && \ + TAC_IS_VALID((tai).tac)) +/* + * A list of PLMNs + */ +#define PLMN_LIST_T(SIZE) struct {Byte_t n_plmns; plmn_t plmn[SIZE];} + +/* + * A list of TACs + */ +#define TAC_LIST_T(SIZE) struct {Byte_t n_tacs; TAC_t tac[SIZE];} + +/* + * A list of TAIs + */ +#define TAI_LIST_T(SIZE) struct {Byte_t n_tais; tai_t tai[SIZE];} + +/* + * User notification callback, executed whenever a change of data with + * respect of network information (e.g. network registration and/or + * location change, new PLMN becomes available) is notified by the + * EPS Mobility Management sublayer + */ +typedef int (*emm_indication_callback_t) (Stat_t, tac_t, ci_t, AcT_t, const char*, size_t); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __COMMONDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/include/networkDef.h b/openair-cn/NAS/EURECOM-NAS/src/include/networkDef.h new file mode 100644 index 0000000000..3c442d7c5b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/include/networkDef.h @@ -0,0 +1,251 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source networkDef.h + +Version 0.1 + +Date 2012/09/21 + +Product NAS stack + +Subsystem include + +Author Frederic Maurel + +Description Contains network's global definitions + +*****************************************************************************/ +#ifndef __NETWORKDEF_H__ +#define __NETWORKDEF_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * ---------------------- + * Network selection mode + * ---------------------- + */ +#define NET_PLMN_AUTO 0 +#define NET_PLMN_MANUAL 1 + +/* + * --------------------------- + * Network registration status + * --------------------------- + */ + /* not registered, not currently searching an operator to register to */ +#define NET_REG_STATE_OFF 0 + /* registered, home network */ +#define NET_REG_STATE_HN 1 + /* not registered, currently trying to attach or searching an operator + * to register to */ +#define NET_REG_STATE_ON 2 + /* registration denied */ +#define NET_REG_STATE_DENIED 3 + /* unknown (e.g. out of GERAN/UTRAN/E-UTRAN coverage) */ +#define NET_REG_STATE_UNKNOWN 4 + /* registered, roaming */ +#define NET_REG_STATE_ROAMING 5 + /* registered for "SMS only", home network */ +#define NET_REG_STATE_SMS_HN 6 + /* registered, for "SMS only", roaming */ +#define NET_REG_STATE_SMS_ROAMING 7 + /* attached for emergency bearer services only (applicable to UTRAN) */ +#define NET_REG_STATE_EMERGENCY 8 + +/* + * ------------------------------------ + * Network access technology indicators + * ------------------------------------ + */ +#define NET_ACCESS_UNAVAILABLE (-1) /* Not available */ +#define NET_ACCESS_GSM 0 /* GSM */ +#define NET_ACCESS_COMPACT 1 /* GSM Compact */ +#define NET_ACCESS_UTRAN 2 /* UTRAN */ +#define NET_ACCESS_EGPRS 3 /* GSM w/EGPRS */ +#define NET_ACCESS_HSDPA 4 /* UTRAN w/HSDPA */ +#define NET_ACCESS_HSUPA 5 /* UTRAN w/HSUPA */ +#define NET_ACCESS_HSDUPA 6 /* UTRAN w/HSDPA and HSUPA */ +#define NET_ACCESS_EUTRAN 7 /* E-UTRAN */ + +/* + * --------------------------------------- + * Network operator representation formats + * --------------------------------------- + */ +#define NET_FORMAT_LONG 0 /* long format alphanumeric */ +#define NET_FORMAT_SHORT 1 /* short format alphanumeric */ +#define NET_FORMAT_NUM 2 /* numeric format */ + +#define NET_FORMAT_MAX_SIZE NET_FORMAT_LONG_SIZE + +/* + * ----------------------------- + * Network operator availability + * ----------------------------- + */ +#define NET_OPER_UNKNOWN 0 /* unknown operator */ +#define NET_OPER_AVAILABLE 1 /* available operator */ +#define NET_OPER_CURRENT 2 /* currently selected operator */ +#define NET_OPER_FORBIDDEN 3 /* forbidden operator */ + +/* + * -------------------------------------- + * Network connection establishment cause + * -------------------------------------- + */ +#define NET_ESTABLISH_CAUSE_EMERGENCY 0x01 +#define NET_ESTABLISH_CAUSE_HIGH_PRIO 0x02 +#define NET_ESTABLISH_CAUSE_MT_ACCESS 0x03 +#define NET_ESTABLISH_CAUSE_MO_SIGNAL 0x04 +#define NET_ESTABLISH_CAUSE_MO_DATA 0x05 +#define NET_ESTABLISH_CAUSE_V1020 0x06 + +/* + * -------------------------------------- + * Network connection establishment type + * -------------------------------------- + */ +#define NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL 0x10 +#define NET_ESTABLISH_TYPE_EMERGENCY_CALLS 0x20 +#define NET_ESTABLISH_TYPE_ORIGINATING_CALLS 0x30 +#define NET_ESTABLISH_TYPE_TERMINATING_CALLS 0x40 +#define NET_ESTABLISH_TYPE_MO_CS_FALLBACK 0x50 + +/* + * ------------------- + * PDN connection type + * ------------------- + */ +#define NET_PDN_TYPE_IPV4 0 +#define NET_PDN_TYPE_IPV6 1 +#define NET_PDN_TYPE_IPV4V6 2 + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * --------------------- + * PDN connection status + * --------------------- + */ +typedef enum { + /* MT = The Mobile Terminal, NW = The Network */ + NET_PDN_MT_DEFAULT_ACT = 1, /* MT has activated a PDN connection */ + NET_PDN_NW_DEFAULT_DEACT, /* NW has deactivated a PDN connection */ + NET_PDN_MT_DEFAULT_DEACT, /* MT has deactivated a PDN connection */ + NET_PDN_NW_DEDICATED_ACT, /* NW has activated an EPS bearer context */ + NET_PDN_MT_DEDICATED_ACT, /* MT has activated an EPS bearer context */ + NET_PDN_NW_DEDICATED_DEACT, /* NW has deactivated an EPS bearer context */ + NET_PDN_MT_DEDICATED_DEACT, /* MT has deactivated an EPS bearer context */ +} network_pdn_state_t; + +/* + * --------------------------- + * Network operator identifier + * --------------------------- + */ +typedef struct { +#define NET_FORMAT_LONG_SIZE 16 /* Long alphanumeric format */ +#define NET_FORMAT_SHORT_SIZE 8 /* Short alphanumeric format */ +#define NET_FORMAT_NUM_SIZE 6 /* Numeric format (PLMN identifier */ + union { + unsigned char alpha_long[NET_FORMAT_LONG_SIZE+1]; + unsigned char alpha_short[NET_FORMAT_SHORT_SIZE+1]; + unsigned char num[NET_FORMAT_NUM_SIZE+1]; + } id; +} network_plmn_t; + +/* + * ------------------------------- + * EPS bearer level QoS parameters + * ------------------------------- + */ +typedef struct { + int gbrUL; /* Guaranteed Bit Rate for uplink */ + int gbrDL; /* Guaranteed Bit Rate for downlink */ + int mbrUL; /* Maximum Bit Rate for uplink */ + int mbrDL; /* Maximum Bit Rate for downlink */ + int qci; /* QoS Class Identifier */ +} network_qos_t; + +/* + * ----------------------------- + * IPv4 packet filter parameters + * ----------------------------- + */ +typedef struct { + unsigned char protocol; /* Protocol identifier */ + unsigned char tos; /* Type of service */ +#define NET_PACKET_FILTER_IPV4_ADDR_SIZE 4 + unsigned char addr[NET_PACKET_FILTER_IPV4_ADDR_SIZE]; + unsigned char mask[NET_PACKET_FILTER_IPV4_ADDR_SIZE]; +} network_ipv4_data_t; + +/* + * ----------------------------- + * IPv6 packet filter parameters + * ----------------------------- + */ +typedef struct { + unsigned char nh; /* Next header type */ + unsigned char tf; /* Traffic class */ +#define NET_PACKET_FILTER_IPV6_ADDR_SIZE 16 + unsigned char addr[NET_PACKET_FILTER_IPV6_ADDR_SIZE]; + unsigned char mask[NET_PACKET_FILTER_IPV6_ADDR_SIZE]; + unsigned int ipsec; /* IPSec security parameter index */ + unsigned int fl; /* Flow label */ +} network_ipv6_data_t; + +/* + * ------------- + * Packet Filter + * ------------- + */ +typedef struct { + unsigned char id; /* Packet filter identifier */ +#define NET_PACKET_FILTER_DOWNLINK 0x01 +#define NET_PACKET_FILTER_UPLINK 0x02 +#define NET_PACKET_FILTER_BIDIR 0x03 + unsigned char dir; /* Packet filter direction */ + unsigned char precedence; /* Evaluation precedence */ + union { + network_ipv4_data_t ipv4; + network_ipv6_data_t ipv6; + } data; + unsigned short lport; /* Local (UE) port number */ + unsigned short rport; /* Remote (network) port number */ +} network_pkf_t; + +/* + * --------------------- + * Traffic Flow Template + * --------------------- + */ +typedef struct { + int n_pkfs; +#define NET_PACKET_FILTER_MAX 16 + network_pkf_t* pkf[NET_PACKET_FILTER_MAX]; +} network_tft_t; + +/* + * User notification callback, executed whenever a change of status with + * respect of PDN connection or EPS bearer context is notified by the EPS + * Session Management sublayer + */ +typedef int (*esm_indication_callback_t) (int, network_pdn_state_t); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __NETWORKDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/include/securityDef.h b/openair-cn/NAS/EURECOM-NAS/src/include/securityDef.h new file mode 100644 index 0000000000..108ce80bec --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/include/securityDef.h @@ -0,0 +1,85 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source securityDef.h + +Version 0.1 + +Date 2013/05/02 + +Product NAS stack + +Subsystem include + +Author Frederic Maurel + +Description Contains global security definitions + +*****************************************************************************/ +#ifndef __SECURITYDEF_H__ +#define __SECURITYDEF_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Index of the first byte of each fields of the AUTN parameter + */ +#define AUTH_SQN_INDEX 0 +#define AUTH_AMF_INDEX (AUTH_SQN_INDEX + AUTH_SQN_SIZE) +#define AUTH_MAC_INDEX (AUTH_AMF_INDEX + AUTH_AMF_SIZE) + +/* + * Size of the authentication challenge parameters in bytes + */ +#define AUTH_SQN_SIZE 6 /* Sequence number: 48 bits */ +#define AUTH_AK_SIZE 6 /* Anonymity key: 48 bits */ +#define AUTH_AMF_SIZE 2 /* Authentication Management Field: 16 bits */ +#define AUTH_MAC_SIZE 8 /* Message Authentication Code: 64 bits */ +#define AUTH_AUTN_SIZE 16 /* Authentication token: 128 bits + AUTN = (SQN ⊕ AK) || AMF || MAC */ +#define AUTH_MACS_SIZE 8 /* Re-synchronization MAC: 64 bits */ +#define AUTH_AUTS_SIZE 16 /* Re-synchronization AUT: 128 bits */ +#define AUTH_RAND_SIZE 16 /* Random challenge: 128 bits */ +#define AUTH_CK_SIZE 16 /* Ciphering key: 128 bits */ +#define AUTH_IK_SIZE 16 /* Integrity key: 128 bits */ +#define AUTH_RES_SIZE 16 /* Authentication response: 128 bits */ +#define AUTH_SNID_SIZE 3 /* Serving network's identity: 24 bits */ +#define AUTH_KASME_SIZE 32 /* ASME security key: 256 bits */ +#define AUTH_KNAS_INT_SIZE AUTH_KASME_SIZE /* NAS integrity key */ +#define AUTH_KNAS_ENC_SIZE AUTH_KASME_SIZE /* NAS cyphering key */ +#define AUTH_KENB_SIZE AUTH_KASME_SIZE /* eNodeB security key */ + +/* "Separation bit" of AMF field */ +#define AUTH_AMF_SEPARATION_BIT(a) ((a) & 0x80) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * EPS authentication vector + */ +typedef struct { + /* ASME security key */ + char kasme[AUTH_KASME_SIZE + 1]; + /* Random challenge parameter */ + char rand[AUTH_RAND_SIZE + 1]; + /* Authentication token parameter */ + char autn[AUTH_AUTN_SIZE + 1]; + /* Expected Authentication response parameter */ +#define AUTH_XRES_SIZE AUTH_RES_SIZE + char xres[AUTH_XRES_SIZE + 1]; +} auth_vector_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __SECURITYDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/include/userDef.h b/openair-cn/NAS/EURECOM-NAS/src/include/userDef.h new file mode 100644 index 0000000000..3f075212d8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/include/userDef.h @@ -0,0 +1,73 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source userDef.h + +Version 0.1 + +Date 2012/09/21 + +Product NAS stack + +Subsystem include + +Author Frederic Maurel + +Description Contains user's global definitions + +*****************************************************************************/ +#ifndef __USERDEF_H__ +#define __USERDEF_H__ + +#include <stdint.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * The name of the file used as non-volatile memory device to store + * UE data parameters + */ +#define USER_NVRAM_FILENAME ".ue.nvram" + +/* + * The name of the environment variable which defines the directory + * where the UE data file is located + */ +#define USER_NVRAM_DIRNAME "NVRAM_DIR" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * ------------------------------ + * Structure of the UE parameters + * ------------------------------ + */ +typedef struct { + /* International Mobile Equipment Identity */ +#define USER_IMEI_SIZE 15 + char IMEI[USER_IMEI_SIZE+1]; + /* Manufacturer identifier */ +#define USER_MANUFACTURER_SIZE 16 + char manufacturer[USER_MANUFACTURER_SIZE+1]; + /* Model identifier */ +#define USER_MODEL_SIZE 16 + char model[USER_MODEL_SIZE+1]; + /* SIM Personal Identification Number */ +#define USER_PIN_SIZE 4 + char PIN[USER_PIN_SIZE+1]; +} user_nvdata_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __USERDEF_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_network.c b/openair-cn/NAS/EURECOM-NAS/src/nas_network.c new file mode 100644 index 0000000000..e19efd2901 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_network.c @@ -0,0 +1,248 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_network.h + +Version 0.1 + +Date 2012/09/20 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure functions triggered by the network + +*****************************************************************************/ + +#include "nas_network.h" +#include "commonDef.h" +#include "nas_log.h" + +#include "as_message.h" +#include "nas_proc.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: nas_network_initialize() ** + ** ** + ** Description: Initializes network internal data ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_network_initialize(void) +{ + LOG_FUNC_IN; + +#ifdef NAS_MME + /* Initialize the internal NAS processing data */ + nas_proc_initialize(); +#endif + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: nas_network_cleanup() ** + ** ** + ** Description: Performs clean up procedure before the system is shutdown ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_network_cleanup(void) +{ + LOG_FUNC_IN; + + nas_proc_cleanup(); + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: nas_network_process_data() ** + ** ** + ** Description: Process Access Stratum messages received from the network ** + ** and call applicable NAS procedure function. ** + ** ** + ** Inputs: msg_id: AS message identifier ** + ** data: Generic pointer to data structure that has ** + ** to be processed ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok if the message has been success- ** + ** fully processed; RETURNerror otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_network_process_data(int msg_id, const void* data) +{ + LOG_FUNC_IN; + + const as_message_t* msg = (as_message_t*)(data); + int rc = RETURNok; + + /* Sanity check */ + if (msg_id != msg->msgID) { + LOG_TRACE(ERROR, "NET-MAIN - Message identifier 0x%x to process " + "is different from that of the network data (0x%x)", + msg_id, msg->msgID); + LOG_FUNC_RETURN (RETURNerror); + } + + switch (msg_id) + { +#ifdef NAS_UE + case AS_BROADCAST_INFO_IND: + break; + + case AS_CELL_INFO_CNF: + { + /* Received cell information confirm */ + const cell_info_cnf_t* info = &msg->msg.cell_info_cnf; + int cell_found = (info->errCode == AS_SUCCESS); + rc = nas_proc_cell_info(cell_found, info->tac, + info->cellID, info->rat, + info->rsrp, info->rsrq); + break; + } + + case AS_CELL_INFO_IND: + break; + + case AS_PAGING_IND: + break; + + case AS_NAS_ESTABLISH_CNF: + { + /* Received NAS signalling connection establishment confirm */ + const nas_establish_cnf_t* confirm = &msg->msg.nas_establish_cnf; + if ( (confirm->errCode == AS_SUCCESS) || + (confirm->errCode == AS_TERMINATED_NAS) ) { + rc = nas_proc_establish_cnf(confirm->nasMsg.data, + confirm->nasMsg.length); + } + else { + LOG_TRACE(WARNING, "NET-MAIN - " + "Initial NAS message not delivered"); + rc = nas_proc_establish_rej(); + } + break; + } + + case AS_NAS_RELEASE_IND: + /* Received NAS signalling connection releaase indication */ + rc = nas_proc_release_ind(msg->msg.nas_release_ind.cause); + break; + + case AS_UL_INFO_TRANSFER_CNF: + /* Received uplink data transfer confirm */ + if (msg->msg.ul_info_transfer_cnf.errCode != AS_SUCCESS) { + LOG_TRACE(WARNING, "NET-MAIN - " + "Uplink NAS message not delivered"); + rc = nas_proc_ul_transfer_rej(); + } + else { + rc = nas_proc_ul_transfer_cnf(); + } + break; + + case AS_DL_INFO_TRANSFER_IND: + { + const dl_info_transfer_ind_t* info = &msg->msg.dl_info_transfer_ind; + /* Received downlink data transfer indication */ + rc = nas_proc_dl_transfer_ind(info->nasMsg.data, + info->nasMsg.length); + break; + } + + case AS_RAB_ESTABLISH_IND: + break; + + case AS_RAB_RELEASE_IND: + break; +#endif +#ifdef NAS_MME + case AS_NAS_ESTABLISH_IND: + { + /* Received NAS signalling connection establishment indication */ + const nas_establish_ind_t* indication = &msg->msg.nas_establish_ind; + rc = nas_proc_establish_ind(indication->UEid, + indication->tac, + indication->initialNasMsg.data, + indication->initialNasMsg.length); + break; + } + + case AS_DL_INFO_TRANSFER_CNF: + { + const dl_info_transfer_cnf_t* info = &msg->msg.dl_info_transfer_cnf; + /* Received downlink data transfer confirm */ + if (info->errCode != AS_SUCCESS) { + LOG_TRACE(WARNING, "NET-MAIN - " + "Downlink NAS message not delivered"); + rc = nas_proc_dl_transfer_rej(info->UEid); + } + else { + rc = nas_proc_dl_transfer_cnf(info->UEid); + } + break; + } + + case AS_UL_INFO_TRANSFER_IND: + { + const ul_info_transfer_ind_t* info = &msg->msg.ul_info_transfer_ind; + /* Received uplink data transfer indication */ + rc = nas_proc_ul_transfer_ind(info->UEid, + info->nasMsg.data, + info->nasMsg.length); + break; + } + + case AS_RAB_ESTABLISH_CNF: + break; +#endif + + default: + LOG_TRACE(ERROR, "NET-MAIN - Unexpected AS message type: 0x%x", + msg_id); + rc = RETURNerror; + break; + } + + LOG_FUNC_RETURN (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_network.h b/openair-cn/NAS/EURECOM-NAS/src/nas_network.h new file mode 100644 index 0000000000..3534e23be6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_network.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_network.h + +Version 0.1 + +Date 2012/09/20 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure functions triggered by the network + +*****************************************************************************/ +#ifndef __NAS_NETWORK_H__ +#define __NAS_NETWORK_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void nas_network_initialize(void); + +void nas_network_cleanup(void); + +int nas_network_process_data(int command_id, const void* data); + +const void* nas_network_get_data(void); + +#endif /* __NAS_NETWORK_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_parser.c b/openair-cn/NAS/EURECOM-NAS/src/nas_parser.c new file mode 100644 index 0000000000..0ebd77b244 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_parser.c @@ -0,0 +1,338 @@ +/***************************************************************************** + +Source nas_parser.c + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS command line parser + +*****************************************************************************/ + +#include "nas_parser.h" +#include "parser.h" + +#include <stdio.h> // fprintf +#include <stdlib.h> // atoi + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * Identifiers of the NAS command line options + */ +enum +{ +#ifdef NAS_UE + NAS_PARSER_UE_ID, /* User Equipement Identifier */ +#endif // NAS_UE + NAS_PARSER_TRACE_LEVEL, /* Logging trace level */ +#ifdef NAS_UE + NAS_PARSER_USER_HOST, /* User app layer's hostname */ +#endif // NAS_UE + NAS_PARSER_NETWORK_HOST, /* Network layer's hostname */ +#ifdef NAS_UE + NAS_PARSER_USER_PORT, /* User app layer's port number */ +#endif // NAS_UE + NAS_PARSER_NETWORK_PORT, /* Network layer's port number */ +#ifdef NAS_UE + NAS_PARSER_DEVICE_PATH, /* Device pathname */ + NAS_PARSER_DEVICE_ATTR, /* Device attribute parameters */ +#endif // NAS_UE + NAS_PARSER_NB_OPTIONS +}; + +/* ----------------------------------------------------- + * Definition of the internal NAS command line structure + * ----------------------------------------------------- + * The command line is defined with a name (default is "NASprocess" + * but it will be replaced by the command name actually used at + * runtime), a number of options and the list of options. + * An option is defined with a name, an argument following the name, + * the usage displayed by the usage function and a default value. + */ +static parser_command_line_t nasParserCommandLine = { + "NASprocess", /* Command name */ + NAS_PARSER_NB_OPTIONS, /* Number of options */ + { /* Command line options */ +#ifdef NAS_UE + {"-ueid", "<ueid>", "UE identifier\t\t\t", + NAS_PARSER_DEFAULT_UE_ID}, +#endif // NAS_UE + {"-trace", "<mask>", "Logging trace level\t\t", + NAS_PARSER_DEFAULT_TRACE_LEVEL}, +#ifdef NAS_UE + {"-uhost", "<uhost>", "User app layer's hostname\t", + NAS_PARSER_DEFAULT_USER_HOSTNAME}, +#endif // NAS_UE + {"-nhost", "<nhost>", "Network layer's hostname\t", + NAS_PARSER_DEFAULT_NETWORK_HOSTNAME}, +#ifdef NAS_UE + {"-uport", "<uport>", "User app layer's port number\t", + NAS_PARSER_DEFAULT_USER_PORT_NUMBER}, +#endif // NAS_UE + {"-nport", "<nport>", "Network layer's port number\t", + NAS_PARSER_DEFAULT_NETWORK_PORT_NUMBER}, +#ifdef NAS_UE + {"-dev", "<devpath>", "Device pathname\t\t", "NULL"}, + {"-params", "<params>", "Device attribute parameters", "NULL"}, +#endif // NAS_UE + } +}; + +/* + * Converts a string, containing hexadecimal formatted integer, to an integer + */ +static int atohex(const char* a_char); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: nas_parser_print_usage() ** + ** ** + ** Description: Displays the command line options used to run the NAS ** + ** process and the firmware version defined at compilation ** + ** time ** + ** ** + ** Inputs: version: Firmware version ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_parser_print_usage(const char* version) +{ + parser_print_usage(&nasParserCommandLine); + fprintf(stderr, "Version: %s\n", version); +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_options() ** + ** ** + ** Description: Gets the command line options used to run the NAS process ** + ** ** + ** Inputs: argc: Number of options ** + ** argv: Pointer to the list of options ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_parser_get_options(int argc, const char** argv) +{ + return parser_get_options(argc, argv, &nasParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_nb_options() ** + ** ** + ** Description: Returns the number of the command line options used to ** + ** run the NAS process ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Number of command line options ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_parser_get_nb_options(void) +{ + return nasParserCommandLine.nb_options; +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_trace_level() ** + ** ** + ** Description: Returns the value of the logging trace level ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the logging trace level ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_parser_get_trace_level(void) +{ + return atohex( nasParserCommandLine.options[NAS_PARSER_TRACE_LEVEL].pvalue ); +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_network_host() ** + ** ** + ** Description: Returns the value of the network layer hostname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the network layer hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_network_host(void) +{ + return nasParserCommandLine.options[NAS_PARSER_NETWORK_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_network_port() ** + ** ** + ** Description: Returns the value of the network layer port number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the network layer port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_network_port(void) +{ + return nasParserCommandLine.options[NAS_PARSER_NETWORK_PORT].pvalue; +} + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: nas_parser_get_ueid() ** + ** ** + ** Description: Returns the value of the UE identifier option ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the UE identifier option ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_parser_get_ueid(void) +{ + return atoi( nasParserCommandLine.options[NAS_PARSER_UE_ID].pvalue ); +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_user_host() ** + ** ** + ** Description: Returns the value of the user application layer hostname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the user app layer hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_user_host(void) +{ + return nasParserCommandLine.options[NAS_PARSER_USER_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_user_port() ** + ** ** + ** Description: Returns the value of the user application layer port ** + ** number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the user app layer port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_user_port(void) +{ + return nasParserCommandLine.options[NAS_PARSER_USER_PORT].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_device_path() ** + ** ** + ** Description: Returns the value of the device pathname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the device pathname ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_device_path(void) +{ + return nasParserCommandLine.options[NAS_PARSER_DEVICE_PATH].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: nas_parser_get_device_params() ** + ** ** + ** Description: Returns the value of the device attribute parameters ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the device attribute parameters ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* nas_parser_get_device_params(void) +{ + return nasParserCommandLine.options[NAS_PARSER_DEVICE_ATTR].pvalue; +} +#endif // NAS_UE + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +static int atohex(const char* a_char) +{ + int result; + + for (result=0; a_char; a_char++) + { + if (*a_char >= '0' && *a_char <= '9') + { + result = (result << 4) + (*a_char - '0'); + } + else if (*a_char >= 'A' && *a_char <= 'F') + { + result = (result << 4) + (*a_char - 'A' + 10); + } + else if (*a_char >= 'a' && *a_char <= 'f') + { + result = (result << 4) + (*a_char - 'a' + 10); + } + else + { + break; + } + } + return result; +} diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_parser.h b/openair-cn/NAS/EURECOM-NAS/src/nas_parser.h new file mode 100644 index 0000000000..7421889cae --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_parser.h @@ -0,0 +1,73 @@ +/***************************************************************************** + +Source nas_parser.h + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS command line parser + +*****************************************************************************/ +#ifndef __NAS_PARSER_H__ +#define __NAS_PARSER_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* Logging trace level default value */ +#define NAS_PARSER_DEFAULT_TRACE_LEVEL "0" /* No trace */ + +/* Network layer default hostname */ +#define NAS_PARSER_DEFAULT_NETWORK_HOSTNAME "localhost" + +/* Network layer default port number */ +#define NAS_PARSER_DEFAULT_NETWORK_PORT_NUMBER "12000" + +#ifdef NAS_UE +/* User Identifier default value */ +#define NAS_PARSER_DEFAULT_UE_ID "1" + +/* User application layer default hostname */ +#define NAS_PARSER_DEFAULT_USER_HOSTNAME "localhost" + +/* User application layer default port number */ +#define NAS_PARSER_DEFAULT_USER_PORT_NUMBER "10000" +#endif // NAS_UE + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void nas_parser_print_usage(const char* version); +int nas_parser_get_options(int argc, const char** argv); + +int nas_parser_get_nb_options(void); +int nas_parser_get_trace_level(void); +const char* nas_parser_get_network_host(void); +const char* nas_parser_get_network_port(void); + +#ifdef NAS_UE +int nas_parser_get_ueid(void); +const char* nas_parser_get_user_host(void); +const char* nas_parser_get_user_port(void); +const char* nas_parser_get_device_path(void); +const char* nas_parser_get_device_params(void); +#endif // NAS_UE + +#endif /* __NAS_PARSER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_proc.c b/openair-cn/NAS/EURECOM-NAS/src/nas_proc.c new file mode 100644 index 0000000000..1ab93afb1a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_proc.c @@ -0,0 +1,1582 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_proc.c + +Version 0.1 + +Date 2012/09/20 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure call manager + +*****************************************************************************/ + +#include "nas_proc.h" +#include "nas_log.h" + +#include "emm_main.h" +#include "emm_sap.h" + +#include "esm_main.h" +#include "esm_sap.h" + +#include <stdio.h> // sprintf + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#ifdef NAS_UE +/* + * Signal strength/quality value not known or not detectable + */ +#define NAS_PROC_RSRQ_UNKNOWN 255 +#define NAS_PROC_RSRP_UNKNOWN 255 + +/* + * Local NAS data + */ +static struct { + /* EPS capibility status */ + int EPS_capability_status; + /* Reference signal received quality */ + int rsrq; + /* Reference signal received power */ + int rsrp; +} _nas_proc_data; + +static int _nas_proc_activate(int cid, int apply_to_all); +static int _nas_proc_deactivate(int cid, int apply_to_all); +#endif + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: nas_proc_initialize() ** + ** ** + ** Description: ** + ** ** + ** Inputs: emm_cb: Mobility Management indication callback ** + ** esm_cb: Session Management indication callback ** + ** imei: The IMEI read from the UE's non-volatile ** + ** memory ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_proc_data ** + ** ** + ***************************************************************************/ +void nas_proc_initialize(emm_indication_callback_t emm_cb, + esm_indication_callback_t esm_cb, const char* imei) +{ + LOG_FUNC_IN; + + /* Initialize local NAS data */ + _nas_proc_data.EPS_capability_status = FALSE; + _nas_proc_data.rsrq = NAS_PROC_RSRQ_UNKNOWN; + _nas_proc_data.rsrp = NAS_PROC_RSRP_UNKNOWN; + + /* Initialize the EMM procedure manager */ + emm_main_initialize(emm_cb, imei); + + /* Initialize the ESM procedure manager */ + esm_main_initialize(esm_cb); + + LOG_FUNC_OUT; +} +#endif +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: nas_proc_initialize() ** + ** ** + ** Description: ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_proc_initialize(void) +{ + LOG_FUNC_IN; + + /* Initialize the EMM procedure manager */ + emm_main_initialize(); + + /* Initialize the ESM procedure manager */ + esm_main_initialize(); + + LOG_FUNC_OUT; +} +#endif + +/**************************************************************************** + ** ** + ** Name: nas_proc_cleanup() ** + ** ** + ** Description: Performs clean up procedure before the system is shutdown ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_proc_cleanup(void) +{ + LOG_FUNC_IN; + +#ifdef NAS_UE + /* Detach the UE from the EPS network */ + int rc = nas_proc_detach(TRUE); + if (rc != RETURNok) { + LOG_TRACE(ERROR, "NAS-PROC - Failed to detach from the network"); + } +#endif + + /* Perform the EPS Mobility Manager's clean up procedure */ + emm_main_cleanup(); + + /* Perform the EPS Session Manager's clean up procedure */ + esm_main_cleanup(); + + LOG_FUNC_OUT; +} + +/* + * -------------------------------------------------------------------------- + * NAS procedures triggered by the user + * -------------------------------------------------------------------------- + */ +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: nas_proc_enable_s1_mode() ** + ** ** + ** Description: Notify the EPS Mobility Manager that the UE can be ** + ** operated ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_enable_s1_mode(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that EPS capability + * of the UE is enabled + */ + _nas_proc_data.EPS_capability_status = TRUE; + emm_sap.primitive = EMMREG_S1_ENABLED; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_disable_s1_mode() ** + ** ** + ** Description: Notify the EPS Mobility Manager that the S1 mode is no ** + ** longer activated ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_disable_s1_mode(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that EPS capability + * of the UE is disabled + */ + _nas_proc_data.EPS_capability_status = FALSE; + emm_sap.primitive = EMMREG_S1_DISABLED; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_eps() ** + ** ** + ** Description: Get the current value of the EPS capability status ** + ** ** + ** Inputs: None ** + ** Others: _nas_proc_data ** + ** ** + ** Outputs: stat: The current value of the EPS capability ** + ** status ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_eps(int* stat) +{ + LOG_FUNC_IN; + + *stat = _nas_proc_data.EPS_capability_status; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_imsi() ** + ** ** + ** Description: Get the International Mobile Subscriber Identity number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: imsi: The value of the IMSI ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_imsi(char* imsi_str) +{ + LOG_FUNC_IN; + + const imsi_t* imsi = emm_main_get_imsi(); + + if (imsi != NULL) { + int offset = 0; + offset += sprintf(imsi_str + offset, "%u%u%u%u%u", + imsi->u.num.digit1, imsi->u.num.digit2, + imsi->u.num.digit3, imsi->u.num.digit4, + imsi->u.num.digit5); + if (imsi->u.num.digit6 != 0xf) { + offset += sprintf(imsi_str + offset, "%u", imsi->u.num.digit6); + } + offset += sprintf(imsi_str + offset, "%u%u%u%u%u%u%u%u", + imsi->u.num.digit7, imsi->u.num.digit8, + imsi->u.num.digit9, imsi->u.num.digit10, + imsi->u.num.digit11, imsi->u.num.digit12, + imsi->u.num.digit13, imsi->u.num.digit14); + if (imsi->u.num.digit15 != 0xf) { + offset += sprintf(imsi_str + offset, "%u", imsi->u.num.digit15); + } + LOG_FUNC_RETURN (RETURNok); + } + + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_msisdn() ** + ** ** + ** Description: Get the Mobile Subscriber dialing number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: msisdn: The value of the subscriber dialing number ** + ** ton_npi: Type Of Number / Numbering Plan Indicator ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_msisdn(char* msisdn_str, int* ton_npi) +{ + LOG_FUNC_IN; + + const msisdn_t* msisdn = emm_main_get_msisdn(); + + if (msisdn != NULL) + { + union { + struct { + Byte_t ext:1; + Byte_t ton:3; + Byte_t npi:4; + } ext_ton_npi; + Byte_t type; + } converter; + converter.ext_ton_npi.ext = msisdn->ext; + converter.ext_ton_npi.ton = msisdn->ton; + converter.ext_ton_npi.npi = msisdn->npi; + *ton_npi = converter.type; + + sprintf(msisdn_str, "%u%u%u%u%u%u%u%u%u%u%u", + msisdn->digit[0].msb, msisdn->digit[0].lsb, + msisdn->digit[1].msb, msisdn->digit[1].lsb, + msisdn->digit[2].msb, msisdn->digit[2].lsb, + msisdn->digit[3].msb, msisdn->digit[3].lsb, + msisdn->digit[4].msb, msisdn->digit[4].lsb, + msisdn->digit[5].msb); + + LOG_FUNC_RETURN (RETURNok); + } + + LOG_FUNC_RETURN (RETURNerror); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_signal_quality() ** + ** ** + ** Description: Get the signal strength/quality parameters ** + ** ** + ** Inputs: None ** + ** Others: _nas_proc_data ** + ** ** + ** Outputs: rsrq: Reference signal received quality value ** + ** rsrp: Reference signal received power value ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_signal_quality(int* rsrq, int* rsrp) +{ + LOG_FUNC_IN; + + *rsrq = _nas_proc_data.rsrq; + *rsrp = _nas_proc_data.rsrp; + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_register() ** + ** ** + ** Description: Execute the network selection and registration procedure. ** + ** ** + ** Inputs: mode: Network selection mode of operation ** + ** format: Represention format of the operator iden- ** + ** tifier ** + ** oper: Identifier of the network operator to re- ** + ** gister ** + ** AcT: The selected Access Technology ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_register(int mode, int format, const network_plmn_t* oper, int AcT) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + /* + * Set the PLMN selection mode of operation + */ + int index = emm_main_set_plmn_selection_mode(mode, format, oper, AcT); + if ( !(index < 0) ) { + /* + * Notify the EMM procedure call manager that network (re)selection + * procedure has to be executed + */ + emm_sap_t emm_sap; + emm_sap.primitive = EMMREG_REGISTER_REQ; + emm_sap.u.emm_reg.u.regist.index = index; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_deregister() ** + ** ** + ** Description: Execute the network deregistration procedure. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_deregister(void) +{ + LOG_FUNC_IN; + + /* TODO: Force an attempt to deregister from the network */ + LOG_TRACE(ERROR, "NAS-PROC - Network deregistration procedure is " + "not implemented"); + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_reg_data() ** + ** ** + ** Description: Gets network registration data from EMM ** + ** ** + ** Inputs: format: Format of the representation of the net- ** + ** work operator identifier ** + ** Others: None ** + ** ** + ** Outputs: mode: The current network selection mode of ope- ** + ** ration ** + ** oper: The identifier of the selected network ** + ** operator ** + ** AcT: The access technology currently used ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_reg_data(int* mode, int* selected, int format, network_plmn_t* oper, int* AcT) +{ + LOG_FUNC_IN; + + /* Get the PLMN selection mode of operation */ + *mode = emm_main_get_plmn_selection_mode(); + + /* Get the currently selected operator */ + const char* oper_name = emm_main_get_selected_plmn(oper, format); + + if (oper_name != NULL) { + /* An operator is currently selected */ + *selected = TRUE; + /* Get the supported Radio Access Technology */ + *AcT = emm_main_get_plmn_rat(); + } + else { + /* No any operator is selected */ + *selected = FALSE; + *AcT = NET_ACCESS_UNAVAILABLE; + } + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_oper_list() ** + ** ** + ** Description: Gets the list of operators present in the network ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: oper_list: The list of operators ** + ** Return: The size of the list in bytes ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_oper_list(const char** oper_list) +{ + LOG_FUNC_IN; + + int size = emm_main_get_plmn_list(oper_list); + + LOG_FUNC_RETURN (size); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_reg_status() ** + ** ** + ** Description: Get the value of the network registration status which ** + ** shows whether the network has currently indicated the ** + ** registration of the UE ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: stat: The current network registration status ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_reg_status(int* stat) +{ + LOG_FUNC_IN; + + *stat = emm_main_get_plmn_status(); + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_loc_info() ** + ** ** + ** Description: Get the location information when the UE is registered in ** + ** the Network ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: tac: The code of the tracking area the registe- ** + ** red PLMN belongs to ** + ** ci: The identifier of the serving cell ** + ** AcT: The access technology in used ** + ** rac: The GPRS routing area code, if available ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_loc_info(char* tac, char* ci, int* AcT) +{ + LOG_FUNC_IN; + + sprintf(tac, "%.4x", emm_main_get_plmn_tac()); // two byte + sprintf(ci, "%.8x", emm_main_get_plmn_ci()); // four byte + *AcT = emm_main_get_plmn_rat(); // E-UTRAN + + LOG_FUNC_RETURN (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_detach() ** + ** ** + ** Description: Initiates a detach procedure ** + ** ** + ** Inputs: switch_off: TRUE if the detach is due to UE switch-off ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_detach(int switch_off) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc = RETURNok; + + if ( emm_main_is_attached() ) { + /* Initiate an Detach procedure */ + emm_sap.primitive = EMMREG_DETACH_INIT; + emm_sap.u.emm_reg.u.detach.switch_off = switch_off; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_attach() ** + ** ** + ** Description: Initiates an attach procedure ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_attach(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc = RETURNok; + + if ( !emm_main_is_attached() ) { + /* Initiate an Attach procedure */ + emm_sap.primitive = EMMREG_ATTACH_INIT; + emm_sap.u.emm_reg.u.attach.is_emergency = FALSE; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_attach_status() ** + ** ** + ** Description: Gets the current network attachment status ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: TRUE if the UE is currently attached to ** + ** the network ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_attach_status(void) +{ + LOG_FUNC_IN; + + int is_attached = emm_main_is_attached(); + + LOG_FUNC_RETURN (is_attached); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_pdn_range() ** + ** ** + ** Description: Gets the maximum value of a PDN context identifier ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The PDN context identifier maximum value ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_pdn_range(void) +{ + LOG_FUNC_IN; + + int max_pdn_id = esm_main_get_nb_pdns_max(); + + LOG_FUNC_RETURN (max_pdn_id); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_pdn_status() ** + ** ** + ** Description: Gets the activation state of every defined PDN contexts ** + ** ** + ** Inputs: n_pdn_max: Maximum number of PDN contexts ** + ** Others: None ** + ** ** + ** Outputs: cids: List of PDN context identifiers ** + ** states: List of PDN context activation states ** + ** Return: The number of PDN contexts that are cur- ** + ** rently in a defined state ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_pdn_status(int* cids, int* states, int n_pdn_max) +{ + LOG_FUNC_IN; + + int n_defined_pdn = 0; + + /* Get the maximum number of supported PDN contexts */ + int n_pdn = esm_main_get_nb_pdns_max(); + + /* For all PDN contexts */ + for (int cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) { + /* Get the status of this PDN */ + int state = FALSE; + int is_defined = esm_main_get_pdn_status(cid, &state); + if (is_defined != FALSE) { + /* This PDN has been defined */ + *(cids++) = cid; + *(states++) = state; + n_defined_pdn += 1; + } + } + + LOG_FUNC_RETURN (n_defined_pdn); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_pdn_param() ** + ** ** + ** Description: Gets the parameters of every defined PDN contexts ** + ** ** + ** Inputs: n_pdn_max: Maximum number of PDN contexts ** + ** Others: None ** + ** ** + ** Outputs: cids: List of PDN context identifiers ** + ** types: List of PDN types (IPv4, IPv6, IPv4v6) ** + ** apns: List of Access Point Names ** + ** Return: The number of PDN contexts that are cur- ** + ** rently in a defined state ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_pdn_param(int* cids, int* types, const char** apns, + int n_pdn_max) +{ + LOG_FUNC_IN; + + int n_defined_pdn = 0; + + /* Get the maximum number of supported PDN contexts */ + int n_pdn = esm_main_get_nb_pdns_max(); + + /* For all PDN contexts */ + for (int cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) { + int emergency, active; + /* Get PDN connection parameters */ + int rc = esm_main_get_pdn(cid, types, apns, &emergency, &active); + if (rc != RETURNerror) { + /* This PDN has been defined */ + *(cids++) = cid; + types++; + apns++; + n_defined_pdn += 1; + } + } + + LOG_FUNC_RETURN (n_defined_pdn); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_get_pdn_addr() ** + ** ** + ** Description: When the cid parameter value is positive, gets the addres-** + ** s(es) assigned to the specified PDN context. ** + ** When the cid parameter value is negative, gets the addres-** + ** s(es) assigned to each defined PDN context. ** + ** When the cid parameter value is null, gets the list of ** + ** defined PDN contexts. ** + ** ** + ** Inputs: cid: PDN context identifier ** + ** n_pdn_max: Maximum number of PDN contexts ** + ** Others: None ** + ** ** + ** Outputs: cids: List of PDN context identifiers ** + ** addr1: List of IPv4 addresses ** + ** addr2: List of IPv6 addresses ** + ** Return: The number PDN contexts that have at least ** + ** one IP address assigned ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_get_pdn_addr(int cid, int* cids, const char** addr1, + const char** addr2, int n_pdn_max) +{ + LOG_FUNC_IN; + + int rc; + int n_defined_pdn = 0; + + if (cid > 0) { + /* Get addresses assigned to the specified PDN */ + rc = esm_main_get_pdn_addr(cid, addr1, addr2); + if (rc != RETURNerror) { + *cids = cid; + n_defined_pdn = 1; + } + } + else if (cid < 0) { + /* Get the maximum number of supported PDN contexts */ + int n_pdn = esm_main_get_nb_pdns_max(); + + /* For all PDN contexts */ + for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) + { + /* Get PDN connection addresses */ + rc = esm_main_get_pdn_addr(cid, addr1, addr2); + if (rc != RETURNerror) { + /* This PDN has been defined */ + *(cids++) = cid; + addr1++; + addr2++; + n_defined_pdn += 1; + } + } + } + else { + /* Get the list of defined PDN contexts */ + + } + + LOG_FUNC_RETURN (n_defined_pdn); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_set_pdn() ** + ** ** + ** Description: Setup parameters of a specified PDN context ** + ** ** + ** Inputs: cid: Identifier of the PDN context to setup ** + ** type: Type of PDN (IPv4, IPv6,IPv4v6) ** + ** apn: Access Point Name of the external network ** + ** to connect to ** + ** ipv4_addr: IPv4 address allocation (NAS, DHCP) ** + ** emergency: Emergency bearer support indication ** + ** p_cscf: Preference of P-CSCF address discovery ** + ** im_cn_signal: IM CN subsystem-related signalling indica- ** + ** tion parameter ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_set_pdn(int cid, int type, const char* apn, int ipv4_addr, + int emergency, int p_cscf, int im_cn_signal) +{ + LOG_FUNC_IN; + + int rc; + + esm_sap_t esm_sap; + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; + esm_sap.is_standalone = TRUE; + esm_sap.data.pdn_connect.is_defined = FALSE; + esm_sap.data.pdn_connect.cid = cid; + esm_sap.data.pdn_connect.pdn_type = type; + esm_sap.data.pdn_connect.apn = apn; + esm_sap.data.pdn_connect.is_emergency = emergency; + /* + * Notify ESM that a new PDN context has to be defined for + * the specified APN + */ + rc = esm_sap_send(&esm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_reset_pdn() ** + ** ** + ** Description: Reset parameters of a specified PDN context ** + ** ** + ** Inputs: cid: Identifier of the PDN context to setup ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_reset_pdn(int cid) +{ + LOG_FUNC_IN; + + int rc; + + esm_sap_t esm_sap; + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; + esm_sap.is_standalone = TRUE; + esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.data.pdn_connect.cid = cid; + /* + * Notify ESM that the specified PDN context has to be undefined + */ + rc = esm_sap_send(&esm_sap); + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_deactivate_pdn() ** + ** ** + ** Description: Deactivates specified PDN context or all PDN contexts if ** + ** specified cid is negative ** + ** ** + ** Inputs: cid: Identifier of the PDN context to be deac- ** + ** tivate ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_deactivate_pdn(int cid) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if (cid > 0) { + /* Deactivate only the specified PDN context */ + rc = _nas_proc_deactivate(cid, FALSE); + } + else { + /* Do not deactivate the PDN connection established during initial + * network attachment (identifier 1) */ + cid = 2; + /* Deactivate all active PDN contexts */ + while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max()+1)) + { + rc = _nas_proc_deactivate(cid++, TRUE); + } + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_activate_pdn() ** + ** ** + ** Description: Activates specified PDN context or all PDN contexts if ** + ** specified cid is negative ** + ** ** + ** Inputs: cid: Identifier of the PDN context to be act- ** + ** tivate ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_activate_pdn(int cid) +{ + LOG_FUNC_IN; + + int rc = RETURNok; + + if ( !emm_main_is_attached() ) { + /* + * If the UE is not attached to the network, perform EPS attach + * procedure prior to attempt to request any PDN connectivity + */ + LOG_TRACE(WARNING, "NAS-PROC - UE is not attached to the network"); + rc = nas_proc_attach(); + } + else if (emm_main_is_emergency()) { + /* The UE is attached for emergency bearer services; It shall not + * request a PDN connection to any other PDN */ + LOG_TRACE(WARNING,"NAS-PROC - Attached for emergency bearer services"); + rc = RETURNerror; + } + + if (rc != RETURNerror) + { + if (cid > 0) { + /* Activate only the specified PDN context */ + rc = _nas_proc_activate(cid, FALSE); + } + else { + cid = 1; + /* Activate all defined PDN contexts */ + while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max()+1)) + { + rc = _nas_proc_activate(cid++, TRUE); + } + } + } + + LOG_FUNC_RETURN (rc); +} + +/* + * -------------------------------------------------------------------------- + * NAS procedures triggered by the network + * -------------------------------------------------------------------------- + */ + +/**************************************************************************** + ** ** + ** Name: nas_proc_cell_info() ** + ** ** + ** Description: Processes the cell information received from the network ** + ** ** + ** Inputs: found: Indicates whether a suitable cell is found ** + ** for the selected PLMN to camp on ** + ** tac: The code of the tracking area the PLMN ** + ** belongs to ** + ** ci: The identifier of a cell serving this PLMN ** + ** AcT: The access technology supported by the ** + ** serving cell ** + ** rsrq: Reference signal received quality measure- ** + ** ment ** + ** rsrp: Reference signal received power measure- ** + ** ment ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _nas_proc_data ** + ** ** + ***************************************************************************/ +int nas_proc_cell_info(int found, tac_t tac, ci_t ci, AcT_t AcT, + UInt8_t rsrq, UInt8_t rsrp) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* Store LTE signal strength/quality measurement data */ + _nas_proc_data.rsrq = rsrq; + _nas_proc_data.rsrp = rsrp; + + /* + * Notify the EMM procedure call manager that cell information + * have been received from the Access-Stratum sublayer + */ + emm_sap.primitive = EMMAS_CELL_INFO_RES; + emm_sap.u.emm_as.u.cell_info.found = found; + emm_sap.u.emm_as.u.cell_info.plmnIDs.n_plmns = 0; + emm_sap.u.emm_as.u.cell_info.rat = AcT; + emm_sap.u.emm_as.u.cell_info.tac = tac; + emm_sap.u.emm_as.u.cell_info.cellID = ci; + + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_establish_cnf() ** + ** ** + ** Description: Processes the NAS signalling connection establishment ** + ** confirm message received from the network ** + ** ** + ** Inputs: data: The initial NAS message transfered within ** + ** the message ** + ** len: The length of the initial NAS message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_establish_cnf(const Byte_t* data, UInt32_t len) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that NAS signalling + * connection establishment confirm message has been received + * from the Access-Stratum sublayer + */ + emm_sap.primitive = EMMAS_ESTABLISH_CNF; + emm_sap.u.emm_as.u.establish.NASmsg.length = len; + emm_sap.u.emm_as.u.establish.NASmsg.value = (uint8_t*)data; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_establish_rej() ** + ** ** + ** Description: Processes the NAS signalling connection establishment ** + ** confirm message received from the network while initial ** + ** NAS message has not been delivered to the NAS sublayer on ** + ** the receiver side. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_establish_rej(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that transmission + * failure of initial NAS message indication has been received + * from lower layers + */ + emm_sap.primitive = EMMAS_ESTABLISH_REJ; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_release_ind() ** + ** ** + ** Description: Processes the NAS signalling connection release indica- ** + ** tion message received from the network ** + ** ** + ** Inputs: cause: The release cause ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_release_ind(int cause) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that the NAS signalling + * connection has been terminated by the network + */ + emm_sap.primitive = EMMAS_RELEASE_IND; + emm_sap.u.emm_as.u.release.cause = cause; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_ul_transfer_cnf() ** + ** ** + ** Description: Processes the uplink data transfer confirm message recei- ** + ** ved from the network while NAS message has been success- ** + ** fully delivered to the NAS sublayer on the receiver side. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_ul_transfer_cnf(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that uplink NAS message + * has been successfully delivered to the NAS sublayer on the + * receiver side + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = 0; + emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.NASmsg.length = 0; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_ul_transfer_rej() ** + ** ** + ** Description: Processes the uplink data transfer confirm message recei- ** + ** ved from the network while NAS message has not been deli- ** + ** vered to the NAS sublayer on the receiver side. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_ul_transfer_rej(void) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that transmission + * failure of uplink NAS message indication has been received + * from lower layers + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = 0; + emm_sap.u.emm_as.u.data.delivered = FALSE; + emm_sap.u.emm_as.u.data.NASmsg.length = 0; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_dl_transfer_ind() ** + ** ** + ** Description: Processes downlink data transfer indication message re- ** + ** ceived from the network ** + ** ** + ** Inputs: data: The transfered NAS message ** + ** len: The length of the NAS message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_dl_transfer_ind(const Byte_t* data, UInt32_t len) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (len > 0) { + emm_sap_t emm_sap; + /* + * Notify the EMM procedure call manager that data transfer + * indication has been received from the Access-Stratum sublayer + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = 0; + emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.NASmsg.length = len; + emm_sap.u.emm_as.u.data.NASmsg.value = (uint8_t*)data; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_UE + +#ifdef NAS_MME +/**************************************************************************** + ** ** + ** Name: nas_proc_establish_ind() ** + ** ** + ** Description: Processes the NAS signalling connection establishment ** + ** indication message received from the network ** + ** ** + ** Inputs: ueid: UE identifier ** + ** tac: The code of the tracking area the initia- ** + ** ting UE belongs to ** + ** data: The initial NAS message transfered within ** + ** the message ** + ** len: The length of the initial NAS message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_establish_ind(UInt32_t ueid, tac_t tac, + const Byte_t* data, UInt32_t len) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (len > 0) { + emm_sap_t emm_sap; + /* + * Notify the EMM procedure call manager that NAS signalling + * connection establishment indication message has been received + * from the Access-Stratum sublayer + */ + emm_sap.primitive = EMMAS_ESTABLISH_REQ; + emm_sap.u.emm_as.u.establish.ueid = ueid; + emm_sap.u.emm_as.u.establish.NASmsg.length = len; + emm_sap.u.emm_as.u.establish.NASmsg.value = (uint8_t*)data; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_dl_transfer_cnf() ** + ** ** + ** Description: Processes the downlink data transfer confirm message re- ** + ** ceived from the network while NAS message has been succes-** + ** sfully delivered to the NAS sublayer on the receiver side.** + ** ** + ** Inputs: ueid: UE identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_dl_transfer_cnf(UInt32_t ueid) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that downlink NAS message + * has been successfully delivered to the NAS sublayer on the + * receiver side + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = ueid; + emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.NASmsg.length = 0; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_dl_transfer_rej() ** + ** ** + ** Description: Processes the downlink data transfer confirm message re- ** + ** ceived from the network while NAS message has not been ** + ** delivered to the NAS sublayer on the receiver side. ** + ** ** + ** Inputs: ueid: UE identifier ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_dl_transfer_rej(UInt32_t ueid) +{ + LOG_FUNC_IN; + + emm_sap_t emm_sap; + int rc; + + /* + * Notify the EMM procedure call manager that transmission + * failure of downlink NAS message indication has been received + * from lower layers + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = ueid; + emm_sap.u.emm_as.u.data.delivered = FALSE; + emm_sap.u.emm_as.u.data.NASmsg.length = 0; + rc = emm_sap_send(&emm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: nas_proc_ul_transfer_ind() ** + ** ** + ** Description: Processes uplink data transfer indication message recei- ** + ** ved from the network ** + ** ** + ** Inputs: ueid: UE identifier ** + ** data: The transfered NAS message ** + ** len: The length of the NAS message ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_proc_ul_transfer_ind(UInt32_t ueid, const Byte_t* data, UInt32_t len) +{ + LOG_FUNC_IN; + + int rc = RETURNerror; + + if (len > 0) { + emm_sap_t emm_sap; + /* + * Notify the EMM procedure call manager that data transfer + * indication has been received from the Access-Stratum sublayer + */ + emm_sap.primitive = EMMAS_DATA_IND; + emm_sap.u.emm_as.u.data.ueid = ueid; + emm_sap.u.emm_as.u.data.delivered = TRUE; + emm_sap.u.emm_as.u.data.NASmsg.length = len; + emm_sap.u.emm_as.u.data.NASmsg.value = (uint8_t*)data; + rc = emm_sap_send(&emm_sap); + } + + LOG_FUNC_RETURN (rc); +} +#endif // NAS_MME + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +#ifdef NAS_UE +/**************************************************************************** + ** ** + ** Name: _nas_proc_activate() ** + ** ** + ** Description: Initiates a PDN connectivity procedure ** + ** ** + ** Inputs: cid: Identifier of the PDN context used to es- ** + ** tablished connectivity to specified PDN ** + ** apply_to_all: TRUE if the PDN connectivity procedure is ** + ** initiated to establish connectivity to all ** + ** defined PDNs ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_proc_activate(int cid, int apply_to_all) +{ + LOG_FUNC_IN; + + int rc; + int active = FALSE; + + esm_sap_t esm_sap; + + /* Get PDN context parameters */ + rc = esm_main_get_pdn(cid, &esm_sap.data.pdn_connect.pdn_type, + &esm_sap.data.pdn_connect.apn, + &esm_sap.data.pdn_connect.is_emergency, &active); + if (rc != RETURNok) { + /* No any context is defined for the specified PDN */ + if (apply_to_all) { + /* Go ahead to activate next PDN context */ + LOG_FUNC_RETURN (RETURNok); + } + /* Return an error */ + LOG_FUNC_RETURN (RETURNerror); + } + + if (active) { + /* The PDN context is already active */ + LOG_TRACE(WARNING, "NAS-PROC - PDN connection %d is active", cid); + LOG_FUNC_RETURN (RETURNok); + } + if (esm_sap.data.pdn_connect.is_emergency) { + if (esm_main_has_emergency()) { + /* There is already a PDN connection for emergency + * bearer services established; the UE shall not + * request an additional PDN connection for emer- + * gency bearer services */ + LOG_TRACE(WARNING, "NAS-PROC - PDN connection for emergency " + "bearer services is already established (cid=%d)", cid); + LOG_FUNC_RETURN (RETURNerror); + } + } + /* + * Notify ESM that a default EPS bearer has to be established + * for the specified PDN + */ + esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; + esm_sap.is_standalone = TRUE; + esm_sap.data.pdn_connect.is_defined = TRUE; + esm_sap.data.pdn_connect.cid = cid; + rc = esm_sap_send(&esm_sap); + + LOG_FUNC_RETURN (rc); +} + +/**************************************************************************** + ** ** + ** Name: _nas_proc_deactivate() ** + ** ** + ** Description: Initiates a PDN disconnect procedure ** + ** ** + ** Inputs: cid: Identifier of the PDN context ** + ** apply_to_all: TRUE if the PDN disconnect procedure is ** + ** initiated to request disconnection from ** + ** all active PDNs ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_proc_deactivate(int cid, int apply_to_all) +{ + LOG_FUNC_IN; + + int rc; + int pdn_type; + const char* apn; + int emergency = FALSE; + int active = FALSE; + + /* Get PDN context parameters */ + rc = esm_main_get_pdn(cid, &pdn_type, &apn, &emergency, &active); + if (rc != RETURNok) { + /* No any context is defined for the specified PDN */ + if (apply_to_all) { + /* Go ahead to deactivate next PDN connection */ + LOG_FUNC_RETURN (RETURNok); + } + LOG_FUNC_RETURN (RETURNerror); + } + + if (!active) { + /* The PDN connection is already inactive */ + LOG_TRACE(WARNING, "NAS-PROC - PDN connection %d is not active", cid); + LOG_FUNC_RETURN (RETURNok); + } + + if (esm_main_get_nb_pdns() > 1) { + /* + * Notify ESM that all EPS bearers towards the specified PDN + * has to be released + */ + esm_sap_t esm_sap; + esm_sap.primitive = ESM_PDN_DISCONNECT_REQ; + esm_sap.data.pdn_disconnect.cid = cid; + rc = esm_sap_send(&esm_sap); + } + else { + /* For EPS, if an attempt is made to disconnect the last PDN + * connection, then the MT responds with an error */ + LOG_TRACE(WARNING,"NAS-PROC - " + "Attempt to disconnect from the last PDN is not allowed"); + rc = RETURNerror; + } + + LOG_FUNC_RETURN (rc); +} + +#endif // NAS_UE + diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_proc.h b/openair-cn/NAS/EURECOM-NAS/src/nas_proc.h new file mode 100644 index 0000000000..34548a6fae --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_proc.h @@ -0,0 +1,116 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_proc.h + +Version 0.1 + +Date 2012/09/20 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure call manager + +*****************************************************************************/ +#ifndef __NAS_PROC_H__ +#define __NAS_PROC_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#ifdef NAS_UE +void nas_proc_initialize(emm_indication_callback_t emm_cb, esm_indication_callback_t esm_cb, const char* imei); +#endif +#ifdef NAS_MME +void nas_proc_initialize(void); +#endif + +void nas_proc_cleanup(void); + +/* + * -------------------------------------------------------------------------- + * NAS procedures triggered by the user + * -------------------------------------------------------------------------- + */ + +#ifdef NAS_UE +int nas_proc_enable_s1_mode(void); +int nas_proc_disable_s1_mode(void); +int nas_proc_get_eps(int* stat); + +int nas_proc_get_imsi(char* imsi_str); +int nas_proc_get_msisdn(char* msisdn_str, int* ton_npi); + +int nas_proc_get_signal_quality(int* rsrq, int* rsrp); + +int nas_proc_register(int mode, int format, const network_plmn_t* oper, int AcT); +int nas_proc_deregister(void); +int nas_proc_get_reg_data(int* mode, int* selected, int format, network_plmn_t* oper, int* AcT); +int nas_proc_get_oper_list(const char** oper_list); + +int nas_proc_get_reg_status(int* stat); +int nas_proc_get_loc_info(char* tac, char* ci, int* AcT); + +int nas_proc_detach(int switch_off); +int nas_proc_attach(void); +int nas_proc_get_attach_status(void); + +int nas_proc_reset_pdn(int cid); +int nas_proc_set_pdn(int cid, int type, const char* apn, int ipv4_addr, int emergency, int p_cscf, int im_cn_signal); +int nas_proc_get_pdn_range(void); +int nas_proc_get_pdn_status(int* cids, int* states, int n_pdn_max); +int nas_proc_get_pdn_param(int* cids, int* types, const char** apns, int n_pdn_max); +int nas_proc_get_pdn_addr(int cid, int* cids, const char** addr1, const char** addr2, int n_addr_max); +int nas_proc_deactivate_pdn(int cid); +int nas_proc_activate_pdn(int cid); +#endif + +/* + * -------------------------------------------------------------------------- + * NAS procedures triggered by the network + * -------------------------------------------------------------------------- + */ + +#ifdef NAS_UE +int nas_proc_cell_info(int found, tac_t tac, ci_t ci, AcT_t rat, UInt8_t rsrp, UInt8_t rsrq); + +int nas_proc_establish_cnf(const Byte_t* data, UInt32_t len); +int nas_proc_establish_rej(void); + +int nas_proc_release_ind(int cause); + +int nas_proc_ul_transfer_cnf(void); +int nas_proc_ul_transfer_rej(void); +int nas_proc_dl_transfer_ind(const Byte_t* data, UInt32_t len); +#endif + +#ifdef NAS_MME +int nas_proc_establish_ind(UInt32_t ueid, tac_t tac, const Byte_t* data, UInt32_t len); + +int nas_proc_dl_transfer_cnf(UInt32_t ueid); +int nas_proc_dl_transfer_rej(UInt32_t ueid); +int nas_proc_ul_transfer_ind(UInt32_t ueid, const Byte_t* data, UInt32_t len); +#endif + +#endif /* __NAS_PROC_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_user.c b/openair-cn/NAS/EURECOM-NAS/src/nas_user.c new file mode 100644 index 0000000000..75507fbe4d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_user.c @@ -0,0 +1,2482 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_user.c + +Version 0.1 + +Date 2012/03/09 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure functions triggered by the user + +*****************************************************************************/ + +#ifdef NAS_UE + +#include "nas_user.h" +#include "userDef.h" +#include "nas_log.h" +#include "memory.h" + +#include "at_command.h" +#include "at_response.h" +#include "at_error.h" +#include "user_indication.h" +#include "nas_proc.h" + +#include <string.h> // memset, strncpy, strncmp +#include <stdlib.h> // free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * --------------------------------------------------------------------- + * Functions executed upon receiving AT command from the user + * --------------------------------------------------------------------- + */ +static int _nas_user_proc_cgsn (const at_command_t* data); +static int _nas_user_proc_cgmi (const at_command_t* data); +static int _nas_user_proc_cgmm (const at_command_t* data); +static int _nas_user_proc_cgmr (const at_command_t* data); +static int _nas_user_proc_cimi (const at_command_t* data); +static int _nas_user_proc_cfun (const at_command_t* data); +static int _nas_user_proc_cpin (const at_command_t* data); +static int _nas_user_proc_csq (const at_command_t* data); +static int _nas_user_proc_cesq (const at_command_t* data); +static int _nas_user_proc_cops (const at_command_t* data); +static int _nas_user_proc_cgatt (const at_command_t* data); +static int _nas_user_proc_creg (const at_command_t* data); +static int _nas_user_proc_cgreg (const at_command_t* data); +static int _nas_user_proc_cereg (const at_command_t* data); +static int _nas_user_proc_cgdcont (const at_command_t* data); +static int _nas_user_proc_cgact (const at_command_t* data); +static int _nas_user_proc_cmee (const at_command_t* data); +static int _nas_user_proc_clck (const at_command_t* data); +static int _nas_user_proc_cgpaddr (const at_command_t* data); +static int _nas_user_proc_cnum (const at_command_t* data); +static int _nas_user_proc_clac (const at_command_t* data); + +/* NAS procedures applicable to AT commands */ +typedef int (*_nas_user_procedure_t) (const at_command_t*); + +static _nas_user_procedure_t _nas_user_procedure[AT_COMMAND_ID_MAX] = { + NULL, + _nas_user_proc_cgsn, /* CGSN */ + _nas_user_proc_cgmi, /* CGMI */ + _nas_user_proc_cgmm, /* CGMM */ + _nas_user_proc_cgmr, /* CGMR */ + _nas_user_proc_cimi, /* CIMI */ + _nas_user_proc_cfun, /* CFUN */ + _nas_user_proc_cpin, /* CPIN */ + _nas_user_proc_csq, /* CSQ */ + _nas_user_proc_cesq, /* CESQ */ + _nas_user_proc_clac, /* CLAC */ + _nas_user_proc_cmee, /* CMEE */ + _nas_user_proc_cnum, /* CNUM */ + _nas_user_proc_clck, /* CLCK */ + _nas_user_proc_cops, /* COPS */ + _nas_user_proc_creg, /* CREG */ + _nas_user_proc_cgatt, /* CGATT */ + _nas_user_proc_cgreg, /* CGREG */ + _nas_user_proc_cereg, /* CEREG */ + _nas_user_proc_cgdcont, /* CGDCONT */ + _nas_user_proc_cgact, /* CGACT */ + _nas_user_proc_cgpaddr, /* CGPADDR */ +}; + +/* + * Internal representation of data structure returned to the user + * as the result of NAS procedure function call + */ +static at_response_t _nas_user_data = {}; + +/* + * --------------------------------------------------------------------- + * Local UE context + * --------------------------------------------------------------------- + */ +/* + * MT SIM pending status (see ETSI TS 127 007 V10.6.0, Note 2) + * Commands which interact with MT that are accepted when MT is pending SIM PIN, + * SIM PUK, or PH-SIM are: +CGMI, +CGMM, +CGMR, +CGSN, D112; (emergency call), + * +CPAS, +CFUN, +CPIN, +CPINR, +CDIS (read and test command only), and +CIND + * (read and test command only). +*/ +typedef enum { + NAS_USER_READY, /* MT is not pending for any password */ + NAS_USER_SIM_PIN, /* MT is waiting SIM PIN to be given */ + NAS_USER_SIM_PUK, /* MT is waiting SIM PUK to be given */ + NAS_USER_PH_SIM_PIN /* MT is waiting phone-to-SIM card + * password to be given */ +} nas_user_sim_status; +static const char* _nas_user_sim_status_str[] = { + "READY", + "SIM PIN", + "SIM PUK", + "PH-SIM PIN" +}; + +/* + * The local UE context + */ +static struct +{ + /* Firmware version number */ + const char* version; + /* SIM pending status */ + nas_user_sim_status sim_status; + /* Level of functionality */ + int fun; +} _nas_user_context; + +/* + * --------------------------------------------------------------------- + * UE parameters stored in the UE's non-volatile memory device + * --------------------------------------------------------------------- + */ +static user_nvdata_t _nas_user_nvdata; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: nas_user_initialize() ** + ** ** + ** Description: Initializes user internal data ** + ** ** + ** Inputs: emm_cb: Mobility Management indication callback ** + ** esm_cb: Session Management indication callback ** + ** version: Firmware version ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_user_nvdata, _nas_user_context ** + ** ** + ***************************************************************************/ +void nas_user_initialize(emm_indication_callback_t emm_cb, + esm_indication_callback_t esm_cb, const char* version) +{ + LOG_FUNC_IN; + + /* Get UE's data pathname */ + char* path = memory_get_path(USER_NVRAM_DIRNAME, USER_NVRAM_FILENAME); + if (path == NULL) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get UE's data pathname"); + } + + /* Get UE data stored in the non-volatile memory device */ + else { + int rc = memory_read(path, &_nas_user_nvdata, sizeof(user_nvdata_t)); + if (rc != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to read %s", path); + } + free(path); + } + + _nas_user_context.version = version; + _nas_user_context.sim_status = NAS_USER_SIM_PIN; + _nas_user_context.fun = AT_CFUN_FUN_DEFAULT; + + /* Initialize the internal NAS processing data */ + nas_proc_initialize(emm_cb, esm_cb, _nas_user_nvdata.IMEI); + + LOG_FUNC_OUT; +} + +/**************************************************************************** + ** ** + ** Name: nas_user_process_data() ** + ** ** + ** Description: Executes AT command operations received from the user and ** + ** calls applicable NAS procedure function. ** + ** ** + ** Inputs: data: Generic pointer to data structure that has ** + ** to be processed ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok if the command has been success- ** + ** fully executed; RETURNerror otherwise ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +int nas_user_process_data(const void* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNerror; + + if (data) { + const at_command_t* user_data = (at_command_t*)(data); + _nas_user_procedure_t nas_procedure; + + LOG_TRACE(INFO, "USR-MAIN - Process %s AT command %d", + (user_data->type == AT_COMMAND_ACT) ? "action" : + (user_data->type == AT_COMMAND_SET) ? "set parameter" : + (user_data->type == AT_COMMAND_GET) ? "get parameter" : + (user_data->type == AT_COMMAND_TST) ? "test parameter" + : "unknown type", user_data->id); + + /* Call NAS procedure applicable to the AT command */ + nas_procedure = _nas_user_procedure[user_data->id]; + if (nas_procedure != NULL) { + ret_code = (*nas_procedure)(user_data); + } + else { + /* AT command related to result format only */ + _nas_user_data.id = user_data->id; + _nas_user_data.type = user_data->type; + _nas_user_data.mask = user_data->mask; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + ret_code = RETURNok; + } + } + else { + LOG_TRACE(ERROR, "USR-MAIN - Data to be processed is null"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_get_data() ** + ** ** + ** Description: Get a generic pointer to the internal representation of ** + ** the data structure returned as the result of NAS proce- ** + ** dure function call. ** + ** Casting to the proper type is necessary before its usage. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: A generic pointer to the data structure ** + ** Others: None ** + ** ** + ***************************************************************************/ +const void* nas_user_get_data(void) +{ + LOG_FUNC_IN; + LOG_FUNC_RETURN ((void*) &_nas_user_data); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgsn() ** + ** ** + ** Description: Executes the AT CGSN command operations: ** + ** The AT CGSN command returns information text intended to ** + ** permit the user to identify the individual Mobile ** + ** Equipment to which it is connected to. ** + ** Typically, the text will consist of a single line contai- ** + ** ning the IMEI. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_nvdata ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgsn(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgsn_resp_t * cgsn = &_nas_user_data.response.cgsn; + memset(cgsn, 0, sizeof(at_cgsn_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGSN_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + /* Get the Product Serial Number Identification (IMEI) */ + strncpy(cgsn->sn, _nas_user_nvdata.IMEI, + AT_RESPONSE_INFO_TEXT_SIZE); + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGSN command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgmi() ** + ** ** + ** Description: Executes the AT CGMI command operations: ** + ** The AT CGMI command returns information text intended to ** + ** permit the user to identify the manufacturer of the Mobi- ** + ** le Equipment to which it is connected to. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_nvdata ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgmi(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgmi_resp_t * cgmi = &_nas_user_data.response.cgmi; + memset(cgmi, 0, sizeof(at_cgmi_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGMI_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + /* Get the Manufacturer identifier */ + strncpy(cgmi->manufacturer, _nas_user_nvdata.manufacturer, + AT_RESPONSE_INFO_TEXT_SIZE); + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGMI command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgmm() ** + ** ** + ** Description: Executes the AT CGMM command operations: ** + ** The AT CGMM command returns information text intended to ** + ** permit the user to identify specific model of the Mobile ** + ** Equipment to which it is connected to. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_nvdata ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgmm(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgmm_resp_t * cgmm = &_nas_user_data.response.cgmm; + memset(cgmm, 0, sizeof(at_cgmm_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGMM_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + /* Get the Model identifier */ + strncpy(cgmm->model, _nas_user_nvdata.model, + AT_RESPONSE_INFO_TEXT_SIZE); + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGMM command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgmr() ** + ** ** + ** Description: Executes the AT CGMR command operations: ** + ** The AT CGMR command returns information text intended to ** + ** permit the user to identify the version, revision level ** + ** or date, or other pertinent information of the Mobile ** + ** Equipment to which it is connected to. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgmr(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgmr_resp_t * cgmr = &_nas_user_data.response.cgmr; + memset(cgmr, 0, sizeof(at_cgmr_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGMR_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + /* Get the revision identifier */ + strncpy(cgmr->revision, _nas_user_context.version, + AT_RESPONSE_INFO_TEXT_SIZE); + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGMR command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cimi() ** + ** ** + ** Description: Executes the AT CIMI command operations: ** + ** The AT CIMI command returns information text intended to ** + ** permit the user to identify the individual SIM card or ** + ** active application in the UICC (GSM or USIM) which is ** + ** attached to the Mobile Equipment to which it is connected ** + ** to. ** + ** Typically, the text will consist of a single line contai- ** + ** ning the IMSI. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_nvdata ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cimi(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cimi_resp_t * cimi = &_nas_user_data.response.cimi; + memset(cimi, 0, sizeof(at_cimi_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CIMI_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* Get the International Mobile Subscriber Identity (IMSI) */ + ret_code = nas_proc_get_imsi(cimi->IMSI); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get IMSI number"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CIMI command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cfun() ** + ** ** + ** Description: Executes the AT CFUN command operations: ** + ** The AT CFUN command is used to set the Mobile Equipment ** + ** to different power consumption states. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cfun(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cfun_resp_t * cfun = &_nas_user_data.response.cfun; + memset(cfun, 0, sizeof(at_cfun_resp_t)); + + int fun = AT_CFUN_FUN_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CFUN_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + /* + * Set command selects the level of functionality in the MT + */ + if (data->mask & AT_CFUN_RST_MASK) + { + if (data->command.cfun.rst == AT_CFUN_RST) { + /* TODO: Reset the MT before setting it to <fun> power level */ + } + else if (data->command.cfun.rst != AT_CFUN_NORST) { + /* The value of the reset parameter is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <rst> parameter is not valid" + " (%d)", data->command.cfun.rst); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + } + + if (data->mask & AT_CFUN_FUN_MASK) + { + if ( (data->command.cfun.fun < AT_CFUN_MIN) || + (data->command.cfun.fun > AT_CFUN_MAX) ) { + /* The value of the functionality level parameter + * is not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <fun> parameter is not valid" + " (%d)", data->command.cfun.fun); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected parameter value */ + fun = data->command.cfun.fun; + } + + switch (fun) + { + case AT_CFUN_MIN: + /* TODO: Shutdown ??? */ + break; + + case AT_CFUN_FULL: + /* Notify the NAS procedure call manager that the UE is + * operational */ + ret_code = nas_proc_enable_s1_mode(); + break; + + default: + /* TODO: Disable the radio ??? */ + break; + } + + if (ret_code != RETURNerror) { + /* Update the functionality level */ + _nas_user_context.fun = fun; + } + break; + + case AT_COMMAND_GET: + /* Get the MT's functionality level */ + cfun->fun = _nas_user_context.fun; + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CFUN command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cpin() ** + ** ** + ** Description: Executes the AT CPIN command operations: ** + ** The AT CPIN command is used to enter the Mobile Equipment ** + ** passwords which are needed before any other functionality ** + ** can be operated. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_context, _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cpin(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cpin_resp_t * cpin = &_nas_user_data.response.cpin; + memset(cpin, 0, sizeof(at_cpin_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CPIN_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + /* + * Set command sends to the MT a password which is necessary + * before it can be operated + */ + if (_nas_user_context.sim_status == NAS_USER_SIM_PIN) + { + /* The MT is waiting for PIN password; check the PIN code */ + if (strncmp(_nas_user_nvdata.PIN, + data->command.cpin.pin, USER_PIN_SIZE) != 0) { + /* The PIN code is NOT matching; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - PIN code is not correct " + "(%s)", data->command.cpin.pin); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PASSWD; + ret_code = RETURNerror; + } + else { + /* The PIN code is matching; update the user's PIN + * pending status */ + _nas_user_context.sim_status = NAS_USER_READY; + } + } + else + { + /* The MT is NOT waiting for PIN password; + * return an error message */ + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_ALLOWED; + ret_code = RETURNerror; + } + + break; + + case AT_COMMAND_GET: + /* + * Read command returns an alphanumeric string indicating + * whether some password is required or not. + */ + strncpy(cpin->code, + _nas_user_sim_status_str[_nas_user_context.sim_status], + AT_CPIN_RESP_SIZE); + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + /* Other types of AT CPIN command are not valid */ + LOG_TRACE(ERROR, "USR-MAIN - AT+CPIN command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_csq() ** + ** ** + ** Description: Executes the AT CSQ command operations: ** + ** The AT CSQ command returns received signal strength ** + ** indication and channel bit error rate from the Mobile ** + ** Equipment. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_csq(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_csq_resp_t * csq = &_nas_user_data.response.csq; + memset(csq, 0, sizeof(at_csq_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CSQ_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * Execution command returns received signal strength indication + * and channel bit error rate <ber> from the MT + */ + csq->rssi = AT_CESQ_RSSI_UNKNOWN; + csq->ber = AT_CESQ_BER_UNKNOWN; + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CSQ command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cesq() ** + ** ** + ** Description: Executes the AT CESQ command operations: ** + ** The AT CESQ command returns received signal quality para- ** + ** meters. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cesq(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cesq_resp_t * cesq = &_nas_user_data.response.cesq; + memset(cesq, 0, sizeof(at_cesq_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CESQ_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * Execution command returns received signal quality parameters + */ + cesq->rssi = AT_CESQ_RSSI_UNKNOWN; + cesq->ber = AT_CESQ_BER_UNKNOWN; + cesq->rscp = AT_CESQ_RSCP_UNKNOWN; + cesq->ecno = AT_CESQ_ECNO_UNKNOWN; + ret_code = nas_proc_get_signal_quality(&cesq->rsrq, &cesq->rsrp); + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CESQ command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cops() ** + ** ** + ** Description: Executes the AT COPS command operations: ** + ** The AT COPS command forces an attempt to select and ** + ** register the GSM/UMTS/EPS network operator using the ** + ** SIM/USIM card installed in the currently selected card ** + ** slot. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cops(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cops_resp_t * cops = &_nas_user_data.response.cops; + memset(cops, 0, sizeof(at_cops_resp_t)); + + static int read_format = AT_COPS_FORMAT_DEFAULT; + + int mode = AT_COPS_MODE_DEFAULT; + int format = AT_COPS_FORMAT_DEFAULT; + int AcT = AT_COPS_ACT_DEFAULT; + char oper_buffer[NET_FORMAT_MAX_SIZE], *oper = oper_buffer; + memset(oper, 0, NET_FORMAT_MAX_SIZE); + + int oper_is_selected; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_NO_PARAM; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * Set command forces an attempt to select and register the + * GSM/UMTS/EPS network operator using the SIM/USIM card + * installed in the currently selected card slot. + */ + if (data->mask & AT_COPS_MODE_MASK) + { + mode = data->command.cops.mode; + switch (mode) + { + case AT_COPS_AUTO: + /* + * Register in automatic mode + */ + break; + + case AT_COPS_MANUAL: + /* + * Register in manual mode + */ + + /** break is intentionaly missing */ + + case AT_COPS_MANAUTO: + /* + * Register in manual/automatic mode + */ + + /* <oper> field shall be present */ + if ( !(data->mask & AT_COPS_OPER_MASK) ) { + LOG_TRACE(ERROR, "USR-MAIN - <oper> parameter is not present"); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + + /* <format> field shall be present */ + if ( !(data->mask & AT_COPS_FORMAT_MASK) ) { + LOG_TRACE(ERROR, "USR-MAIN - <format> parameter is not present"); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + + /* Set the operator's representation format */ + if ( (data->command.cops.format < AT_COPS_FORMAT_MIN) || + (data->command.cops.format > AT_COPS_FORMAT_MAX) ) { + /* The value of <format> field is not valid */ + LOG_TRACE(ERROR, "USR-MAIN - <format> parameter is not valid (%d)", data->command.cops.format); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + read_format = format = data->command.cops.format; + + /* Set the access technology */ + if (data->mask & AT_COPS_ACT_MASK) + { + if ( (data->command.cops.AcT < AT_COPS_ACT_MIN) || + (data->command.cops.AcT > AT_COPS_ACT_MAX) ) { + /* The value of <AcT> field is not valid */ + LOG_TRACE(ERROR, "USR-MAIN - <AcT> parameter is not valid (%d)", data->command.cops.AcT); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + AcT = data->command.cops.AcT; + } + + break; + + case AT_COPS_DEREG: + /* + * Deregister from network + */ + /* Nothing to do there */ + break; + + case AT_COPS_FORMAT: + /* + * Set only <format> for read command +COPS? + */ + if (data->mask & AT_COPS_FORMAT_MASK) + { + if ( (data->command.cops.format < AT_COPS_FORMAT_MIN) || + (data->command.cops.format > AT_COPS_FORMAT_MAX) ) { + /* The value of <format> field is not valid */ + LOG_TRACE(ERROR, "USR-MAIN - <format> parameter is not valid (%d)", data->command.cops.format); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected representation format */ + read_format = data->command.cops.format; + } + else { + /* Format is not present; set to default */ + read_format = AT_COPS_FORMAT_DEFAULT; + } + + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - <mode> parameter is not supported (%d)", mode); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + } + + /* + * Performs network registration + */ + if (ret_code != RETURNerror) + { + if (mode == AT_COPS_DEREG) { + /* Force an attempt to deregister from the network */ + ret_code = nas_proc_deregister(); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Network deregistration failed"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + break; + } + } + else if (mode != AT_COPS_FORMAT) { + /* Force an attempt to automatically/manualy select + * and register the GSM/UMTS/EPS network operator */ + ret_code = nas_proc_register(mode, format, + &data->command.cops.plmn, AcT); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Network registration failed (<mode>=%d)", mode); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + break; + } + } + } + + break; + + case AT_COMMAND_GET: + /* + * Read command returns the current mode, the currently selected + * network operator and the current Access Technology. + */ + + /* Get the current network registration data */ + ret_code = nas_proc_get_reg_data(&mode, + &oper_is_selected, read_format, + &cops->get.plmn, &cops->get.AcT); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get registration data (<mode>=%d)", mode); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + break; + } + + /* Set the network selection operating mode */ + if (mode == NET_PLMN_AUTO) { + cops->get.mode = AT_COPS_AUTO; + } + else if (mode == NET_PLMN_MANUAL) { + cops->get.mode = AT_COPS_MANUAL; + } + else { + cops->get.mode = AT_COPS_MANAUTO; + } + + /* Set optional parameter bitmask */ + if (oper_is_selected) { + cops->get.format = read_format; + _nas_user_data.mask |= (AT_COPS_RESP_FORMAT_MASK | + AT_COPS_RESP_OPER_MASK); + + if (cops->get.AcT != NET_ACCESS_UNAVAILABLE) { + _nas_user_data.mask |= AT_COPS_RESP_ACT_MASK; + } + } + + break; + + case AT_COMMAND_TST: + /* + * Test command returns a set of parameters, each representing + * an operator present in the network. + */ + cops->tst.size = nas_proc_get_oper_list(&cops->tst.data); + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+COPS command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgatt() ** + ** ** + ** Description: Executes the AT CGATT command operations: ** + ** The AT CGATT command is used to attach the MT to, ** + ** or detach the MT from, the EPS service. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgatt(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgatt_resp_t * cgatt = &_nas_user_data.response.cgatt; + memset(cgatt, 0, sizeof(at_cgatt_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGATT_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The execution command is used to attach the MT to, or detach the + * MT from, the EPS service + */ + if (data->mask & AT_CGATT_STATE_MASK) + { + if ( (data->command.cgatt.state < AT_CGATT_STATE_MIN) || + (data->command.cgatt.state > AT_CGATT_STATE_MAX) ) { + /* The value of the EPS attachment code is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <state> parameter is not valid (%d)", data->command.cgatt.state); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* + * Perform EPS service attach/detach + */ + ret_code = RETURNerror; + if (data->command.cgatt.state == AT_CGATT_ATTACHED) { + ret_code = nas_proc_attach(); + } + else if (data->command.cgatt.state == AT_CGATT_DETACHED) { + ret_code = nas_proc_detach(FALSE); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to attach/detach " + "to/from EPS service (<state>=%d)", + data->command.cgatt.state); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + } + break; + + case AT_COMMAND_GET: + /* + * Read command returns the current EPS service state. + */ + if (nas_proc_get_attach_status() != TRUE) { + cgatt->state = AT_CGATT_DETACHED; + } + else { + cgatt->state = AT_CGATT_ATTACHED; + } + break; + + case AT_COMMAND_TST: + /* + * Test command is used for requesting information on the supported + * EPS service states + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGATT command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_creg() ** + ** ** + ** Description: Executes the AT CREG command operations: ** + ** The AT CREG command returns the Mobile Equipment's ** + ** circuit mode network registration status and optionnally ** + ** location information in GERA/UTRA/E-UTRA Network. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_creg(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_creg_resp_t * creg = &_nas_user_data.response.creg; + memset(creg, 0, sizeof(at_creg_resp_t)); + + static int n = AT_CREG_N_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_NO_PARAM; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The set command controls the presentation of an unsolicited + * result code when there is a change in the MT's circuit mode + * network registration status, or when there is a change of the + * network cell in GERAN/UTRAN/E-UTRAN. + */ + if (data->mask & AT_CREG_N_MASK) + { + if ( (data->command.creg.n < AT_CREG_N_MIN) || + (data->command.creg.n > AT_CREG_N_MAX) ) { + /* The value of the unsolicited result code is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <n> parameter is not valid" + " (%d)", data->command.creg.n); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected parameter value */ + n = data->command.creg.n; + } + else { + /* The numeric parameter is not present; set to default */ + n = AT_CREG_N_DEFAULT; + } + + /* Disable/Enable network logging */ + switch (n) + { + case AT_CREG_OFF: + /* Disable logging of network registration status */ + ret_code = user_ind_deregister(USER_IND_REG); + if (ret_code != RETURNerror) { + /* Disable logging of location information */ + ret_code = user_ind_deregister(USER_IND_LOC); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to disable logging of network notification"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_CREG_BOTH: + /* Location Area Code (lac) is not available */ + case AT_CREG_ON: + /* Enable logging of the MT's circuit mode network + * registration status in GERAN/UTRAN/E_UTRAN */ + ret_code = user_ind_register(USER_IND_REG, AT_CREG, NULL); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to enable logging of registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_GET: + /* + * The read command returns the status of result code presentation, + * and indication of whether the network has currently indicated + * the registration of the MT, and available location information + * elements when the MT is registered in the network. + */ + creg->n = n; + switch (n) + { + case AT_CREG_BOTH: + /* Location Area Code (lac) is not available */ + case AT_CREG_OFF: + case AT_CREG_ON: + /* Get network registration status */ + ret_code = nas_proc_get_reg_status(&creg->stat); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_TST: + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CREG command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgreg() ** + ** ** + ** Description: Executes the AT CGREG command operations: ** + ** The AT CGREG command returns the Mobile Equipment's GPRS ** + ** network registration status and optionnally location ** + ** information in GERA/UTRA Network. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgreg(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgreg_resp_t * cgreg = &_nas_user_data.response.cgreg; + memset(cgreg, 0, sizeof(at_cgreg_resp_t)); + + static int n = AT_CGREG_N_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_NO_PARAM; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The set command controls the presentation of an unsolicited + * result code when there is a change in the MT's GPRS network + * registration status, or when there is a change of the network + * cell in GERAN/UTRAN. + */ + if (data->mask & AT_CGREG_N_MASK) + { + if ( (data->command.cgreg.n < AT_CGREG_N_MIN) || + (data->command.cgreg.n > AT_CGREG_N_MAX) ) { + /* The value of the unsolicited result code is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <n> parameter is not valid" + " (%d)", data->command.cgreg.n); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected parameter value */ + n = data->command.cgreg.n; + } + else { + /* The numeric parameter is not present; set to default */ + n = AT_CGREG_N_DEFAULT; + } + + /* Disable/Enable network logging */ + switch (n) + { + case AT_CGREG_OFF: + /* Disable logging of network registration status */ + ret_code = user_ind_deregister(USER_IND_REG); + if (ret_code != RETURNerror) { + /* Disable logging of location information */ + ret_code = user_ind_deregister(USER_IND_LOC); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to disable logging of network notification"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_CGREG_BOTH: + /* Location Area Code (lac) is not available */ + case AT_CGREG_ON: + /* Enable logging of the MT's GPRS network registration + * status in GERAN/UTRAN/E_UTRAN */ + ret_code = user_ind_register(USER_IND_REG, AT_CGREG, NULL); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to enable logging of registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_GET: + /* + * The read command returns the status of result code presentation, + * and indication of whether the network has currently indicated + * the registration of the MT, and available location information + * elements when the MT is registered in the network. + */ + cgreg->n = n; + switch (n) + { + case AT_CGREG_BOTH: + /* Location Area Code (lac) is not available */ + case AT_CGREG_OFF: + case AT_CGREG_ON: + /* Get network registration status */ + ret_code = nas_proc_get_reg_status(&cgreg->stat); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_TST: + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGREG command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cereg() ** + ** ** + ** Description: Executes the AT CEREG command operations: ** + ** The AT CEREG command returns the Mobile Equipment's EPS ** + ** services registration status and optionnally location ** + ** information in E-UTRA Network. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cereg(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cereg_resp_t * cereg = &_nas_user_data.response.cereg; + memset(cereg, 0, sizeof(at_cereg_resp_t)); + + static int n = AT_CEREG_N_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_NO_PARAM; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The set command controls the presentation of an unsolicited + * result code when there is a change in the MT's EPS network + * registration status, or when there is a change of the network + * cell in E-UTRAN. + */ + if (data->mask & AT_CEREG_N_MASK) + { + if ( (data->command.cereg.n < AT_CEREG_N_MIN) || + (data->command.cereg.n > AT_CEREG_N_MAX) ) { + /* The value of the unsolicited result code is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <n> parameter is not valid" + " (%d)", data->command.cereg.n); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected parameter value */ + n = data->command.cereg.n; + } + else { + /* The numeric parameter is not present; set to default */ + n = AT_CEREG_N_DEFAULT; + } + + /* Disable/Enable network logging */ + switch (n) + { + case AT_CEREG_OFF: + /* Disable logging of network registration status */ + ret_code = user_ind_deregister(USER_IND_REG); + if (ret_code != RETURNerror) { + /* Disable logging of location information */ + ret_code = user_ind_deregister(USER_IND_LOC); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to disable logging of network notification"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_CEREG_BOTH: + /* Enable logging of the location information in E-UTRAN */ + ret_code = user_ind_register(USER_IND_LOC, AT_CEREG, NULL); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to enable logging of location information"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_CEREG_ON: + /* Enable logging of the MT's EPS network registration + * status in E-UTRAN */ + ret_code = user_ind_register(USER_IND_REG, AT_CEREG, NULL); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to enable logging of registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_GET: + /* + * The read command returns the status of result code presentation, + * and indication of whether the network has currently indicated + * the registration of the MT, and available location information + * elements when the MT is registered in the network. + */ + cereg->n = n; + switch (n) + { + case AT_CEREG_BOTH: + /* Get EPS location information */ + ret_code = nas_proc_get_loc_info(cereg->tac, cereg->ci, + &cereg->AcT); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get location information"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + break; + } + + if (cereg->tac[0] != 0) { + _nas_user_data.mask |= (AT_CEREG_RESP_TAC_MASK | + AT_CEREG_RESP_CI_MASK); + if (cereg->AcT != NET_ACCESS_UNAVAILABLE) { + _nas_user_data.mask |= (AT_CEREG_RESP_ACT_MASK); + } + } + + /** break is intentionaly missing */ + + case AT_CEREG_OFF: + case AT_CEREG_ON: + /* Get network registration status */ + ret_code = nas_proc_get_reg_status(&cereg->stat); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get registration status"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + default: + break; + } + + break; + + case AT_COMMAND_TST: + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CEREG command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgdcont() ** + ** ** + ** Description: Executes the AT CGDCONT command operations: ** + ** The AT CGDCONT command specifies PDP context parameter ** + ** values for a PDP context identified by the local context ** + ** identification parameter (cid). ** + ** ** + ** There is a 1 to 1 mapping between EPS bearer context and ** + ** PDP context. Therefore a PDP context used for UMTS/GPRS ** + ** designates a PDN connection and its associated EPS de- ** + ** fault bearer and traffic flows in EPS. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgdcont(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgdcont_get_t * cgdcont = &_nas_user_data.response.cgdcont.get; + memset(cgdcont, 0, sizeof(at_cgdcont_resp_t)); + + int cid = AT_CGDCONT_CID_DEFAULT; + int pdn_type = NET_PDN_TYPE_IPV4; + const char* apn = NULL; + int ipv4_addr_allocation = AT_CGDCONT_IPV4_DEFAULT; + int emergency = AT_CGDCONT_EBS_DEFAULT; + int p_cscf = AT_CGDCONT_PCSCF_DEFAULT; + int im_cn_signalling = AT_CGDCONT_IM_CM_DEFAULT; + int reset_pdn = TRUE; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_NO_PARAM; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * Set command specifies PDN connection and its default + * EPS bearer context parameter values + */ + if (data->mask & AT_CGDCONT_CID_MASK) + { + if (data->command.cgdcont.cid < AT_CGDCONT_CID_MIN) { + /* The value of the PDP context identifier is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <cid> parameter is not valid" + " (%d)", data->command.cgdcont.cid); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + cid = data->command.cgdcont.cid; + } + if (data->mask & AT_CGDCONT_PDP_TYPE_MASK) + { + if (strcmp(data->command.cgdcont.PDP_type, "IP") == 0) { + pdn_type = NET_PDN_TYPE_IPV4; + } + else if (strcmp(data->command.cgdcont.PDP_type, "IPV6") == 0) { + pdn_type = NET_PDN_TYPE_IPV6; + } + else if (strcmp(data->command.cgdcont.PDP_type,"IPV4V6") == 0) { + pdn_type = NET_PDN_TYPE_IPV4V6; + } + else { + /* The value of the PDP type is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <PDN_type> parameter is not " + "valid (%s)", data->command.cgdcont.PDP_type); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + reset_pdn = FALSE; + } + if (data->mask & AT_CGDCONT_APN_MASK) + { + apn = data->command.cgdcont.APN; + } + if (data->mask & AT_CGDCONT_D_COMP_MASK) + { + if ( (data->command.cgdcont.d_comp < AT_CGDCONT_D_COMP_MIN) || + (data->command.cgdcont.d_comp > AT_CGDCONT_D_COMP_MAX) ) { + /* The value of the PDP data compression parameter is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <d_comp> parameter is not " + "valid (%d)", data->command.cgdcont.d_comp); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Not supported: Applicable for SNDCP only */ + } + if (data->mask & AT_CGDCONT_H_COMP_MASK) + { + if ( (data->command.cgdcont.h_comp < AT_CGDCONT_H_COMP_MIN) || + (data->command.cgdcont.h_comp > AT_CGDCONT_H_COMP_MAX) ) { + /* The value of the PDP header compression parameter is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <h_comp> parameter is not " + "valid (%d)", data->command.cgdcont.h_comp); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Not supported */ + } + if (data->mask & AT_CGDCONT_IPV4ADDRALLOC_MASK) + { + if ( (data->command.cgdcont.IPv4AddrAlloc < AT_CGDCONT_IPV4_MIN) || (data->command.cgdcont.IPv4AddrAlloc > AT_CGDCONT_IPV4_MAX) ) { + /* The value of the IPv4 address allocation parameter is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <IPv4AddrAlloc> parameter " + "is not valid (%d)", + data->command.cgdcont.IPv4AddrAlloc); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + ipv4_addr_allocation = data->command.cgdcont.IPv4AddrAlloc; + } + if (data->mask & AT_CGDCONT_EMERGECY_INDICATION_MASK) + { + if ( (data->command.cgdcont.emergency_indication < AT_CGDCONT_EBS_MIN) || (data->command.cgdcont.emergency_indication > AT_CGDCONT_EBS_MAX) ) { + /* The value of the emergency indication parameter is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <emergency indication> " + "parameter is not valid (%d)", + data->command.cgdcont.emergency_indication); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + emergency = data->command.cgdcont.emergency_indication; + } + if (data->mask & AT_CGDCONT_P_CSCF_DISCOVERY_MASK) + { + if ( (data->command.cgdcont.P_CSCF_discovery < AT_CGDCONT_PCSCF_MIN) || (data->command.cgdcont.P_CSCF_discovery > AT_CGDCONT_PCSCF_MAX) ) { + /* The value of the P-CSCF address discovery parameter is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <P-CSCF_discovery> " + "parameter is not valid (%d)", + data->command.cgdcont.P_CSCF_discovery); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + p_cscf = data->command.cgdcont.P_CSCF_discovery; + } + if (data->mask & AT_CGDCONT_IM_CN_SIGNALLING_FLAG_IND_MASK) + { + if ( (data->command.cgdcont.IM_CN_Signalling_Flag_Ind < AT_CGDCONT_IM_CM_MIN) || (data->command.cgdcont.IM_CN_Signalling_Flag_Ind > AT_CGDCONT_IM_CM_MAX) ) { + /* The value of the IM CN subsystem-related signalling + * support indication is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <IM_CN_Signalling_Flag_Ind> " + "parameter is not valid (%d)", + data->command.cgdcont.IM_CN_Signalling_Flag_Ind); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + im_cn_signalling = data->command.cgdcont.IM_CN_Signalling_Flag_Ind; + } + /* + * Setup PDN context + */ + if (reset_pdn) { + /* A special form of the set command, +CGDCONT=<cid> causes + * the values for context number <cid> to become undefined */ + ret_code = nas_proc_reset_pdn(cid); + } + else { + /* Define a new PDN connection */ + ret_code = nas_proc_set_pdn(cid, pdn_type, apn, + ipv4_addr_allocation, emergency, + p_cscf, im_cn_signalling); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to setup PDN connection " + "(<cid>=%d)", data->command.cgdcont.cid); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + + break; + + case AT_COMMAND_GET: + /* + * Read command returns the current settings for each + * defined PDN connection/default EPS bearer context + */ + cgdcont->n_pdns = nas_proc_get_pdn_param(cgdcont->cid, + cgdcont->PDP_type, + cgdcont->APN, + AT_CGDCONT_RESP_SIZE); + if (cgdcont->n_pdns == 0) { + LOG_TRACE(ERROR, "USR-MAIN - No any PDN context is defined"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + { + /* Get the maximum value of a PDN context identifier */ + int cid_max = nas_proc_get_pdn_range(); + if (cid_max > AT_CGDCONT_RESP_SIZE) { + /* The range is defined by the user interface */ + _nas_user_data.response.cgdcont.tst.n_cid = + AT_CGDCONT_RESP_SIZE; + } + else { + /* The range is defined by the ESM sublayer application */ + _nas_user_data.response.cgdcont.tst.n_cid = cid_max; + } + } + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGDCONT command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgact() ** + ** ** + ** Description: Executes the AT CGACT command operations: ** + ** The AT CGACT command is used to activate or deactivate ** + ** the specified PDP context(s) or PDN/EPS bearer context(s) ** + ** for E-UTRAN ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgact(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgact_resp_t * cgact = &_nas_user_data.response.cgact; + memset(cgact, 0, sizeof(at_cgact_resp_t)); + + int cid = -1; + int state = AT_CGACT_STATE_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGACT_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The execution command is used to activate or deactivate + * the specified PDN/EPS bearer context(s). + */ + if (data->mask & AT_CGACT_STATE_MASK) + { + if ( (data->command.cgact.state < AT_CGACT_STATE_MIN) || + (data->command.cgact.state > AT_CGACT_STATE_MAX) ) { + /* The value of the PDP context activation status is + * not valid; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <state> parameter is " + "not valid (%d)", data->command.cgact.state); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + state = data->command.cgact.state; + } + if (data->mask & AT_CGACT_CID_MASK) + { + if (data->command.cgact.cid < AT_CGACT_CID_MIN) { + /* The value of the PDP context identifier is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <cid> parameter is " + "not valid (%d)", data->command.cgact.cid); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + cid = data->command.cgact.cid; + } + /* + * Activate/Deactivate PDN context + */ + ret_code = RETURNerror; + if (state == AT_CGACT_DEACTIVATED) { + ret_code = nas_proc_deactivate_pdn(cid); + } + else if (state == AT_CGACT_ACTIVATED) { + ret_code = nas_proc_activate_pdn(cid); + } + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to %s PDN context " + "(<state>=%d,<cid>=%d)", + (state != AT_CGACT_ACTIVATED)? "deactivate" : + "activate", state, cid); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + + break; + + case AT_COMMAND_GET: + /* + * The read command returns the current activation states for + * all the defined PDN/EPS bearer contexts + */ + cgact->n_pdns = nas_proc_get_pdn_status(cgact->cid, cgact->state, + AT_CGACT_RESP_SIZE); + if (cgact->n_pdns == 0) { + LOG_TRACE(ERROR, "USR-MAIN - No any PDN context is defined"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* + * The test command is used for requesting information on the + * supported PDN/EPS bearer context activation states. + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGACT command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cmee() ** + ** ** + ** Description: Executes the AT CMEE command operations: ** + ** The AT CMEE command disables or enables the use of final ** + ** result code +CME ERROR: <err> as an indication of an er- ** + ** ror relating to the functionality of the MT. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cmee(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cmee_resp_t * cmee = &_nas_user_data.response.cmee; + memset(cmee, 0, sizeof(at_cmee_resp_t)); + + int n = AT_CMEE_N_DEFAULT; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CMEE_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: /* ATV0, ATV1 response format commands */ + case AT_COMMAND_SET: + /* + * The set command controls the presentation of final result code + * +CME ERROR: <err> as an indication of an error relating to the + * functionality of the MT. + */ + if (data->mask & AT_CMEE_N_MASK) + { + if ( (data->command.cmee.n < AT_CMEE_N_MIN) || + (data->command.cmee.n > AT_CMEE_N_MAX) ) { + /* The value of the numeric parameter is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <n> parameter is not valid" + " (%d)", data->command.cmee.n); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Set to the selected parameter value */ + n = data->command.cmee.n; + } + + /* Disable/Enable final result code logging */ + switch (n) + { + case AT_CMEE_OFF: + /* Disable logging of final result code */ + at_error_set_format(AT_ERROR_OFF); + break; + + case AT_CMEE_NUMERIC: + /* Enable logging of numeric final result code */ + at_error_set_format(AT_ERROR_NUMERIC); + break; + + case AT_CMEE_VERBOSE: + /* Enable logging of verbose final result code */ + at_error_set_format(AT_ERROR_VERBOSE); + break; + + default: + break; + } + + break; + + case AT_COMMAND_GET: + /* + * Read command returns the status of the final result code + * presentation. + */ + n = at_error_get_format(); + cmee->n = ( (n == AT_ERROR_OFF)? AT_CMEE_OFF : + (n == AT_ERROR_NUMERIC)? AT_CMEE_NUMERIC : + (n == AT_ERROR_VERBOSE)? AT_CMEE_VERBOSE : RETURNerror); + if (cmee->n == RETURNerror) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get format of the final result code"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CMEE command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_clck() ** + ** ** + ** Description: Executes the AT CLCK command operations: ** + ** The AT CLCK command locks, unlocks or interrogates a MT ** + ** or a network facility. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_clck(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_clck_resp_t * clck = &_nas_user_data.response.clck; + memset(clck, 0, sizeof(at_clck_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CLCK_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + /* + * Execution command locks, unlocks or returns status of a network + * facility + */ + + /* Check facility parameter */ + if (strncmp(data->command.clck.fac, AT_CLCK_SC, + AT_CLCK_FAC_SIZE) != 0) + { + /* Facilities other than SIM is not supported */ + LOG_TRACE(ERROR, "USR-MAIN - Facility is not supported (%s)", + data->command.clck.fac); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + /* Check password parameter */ + if (data->mask & AT_CLCK_PASSWD_MASK) + { + /* Check the PIN code */ + if (strncmp(_nas_user_nvdata.PIN, + data->command.clck.passwd, USER_PIN_SIZE) != 0) { + /* The PIN code is NOT matching; return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - Password is not correct " + "(%s)", data->command.clck.passwd); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PASSWD; + ret_code = RETURNerror; + break; + } + } + /* Execute the command with specified mode of operation */ + switch (data->command.clck.mode) + { + case AT_CLCK_UNLOCK: + /* unlock facility */ + if ( !(data->mask & AT_CLCK_PASSWD_MASK) ) { + /* unlock requires password */ + LOG_TRACE(ERROR, "USR-MAIN - unlock mode of operation " + "requires a password"); + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + ret_code = RETURNerror; + break; + } + LOG_TRACE(ERROR, "USR-MAIN - unlock mode of operation " + "is not supported"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + + case AT_CLCK_LOCK: + /* lock facility */ + if ( !(data->mask & AT_CLCK_PASSWD_MASK) ) { + /* unlock requires password */ + LOG_TRACE(ERROR, "USR-MAIN - lock mode of operation " + "requires a password"); + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + ret_code = RETURNerror; + break; + } + LOG_TRACE(ERROR, "USR-MAIN - lock mode of operation " + "is not supported"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + + case AT_CLCK_STATUS: + /* Read facility status */ + clck->status = AT_CLCK_RESP_STATUS_NOT_ACTIVE; + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - <mode> parameter is not valid" + " (%d)", data->command.clck.mode); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + break; + + case AT_COMMAND_TST: + /* + * Test command returns values supported as a compound value + */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CLCK command type %d is not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cgpaddr() ** + ** ** + ** Description: Executes the AT CGPADDR command operations: ** + ** The AT CGPADDR command returns a list of PDP addresses ** + ** for the specified context identifiers ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cgpaddr(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cgpaddr_resp_t * cgpaddr = &_nas_user_data.response.cgpaddr; + memset(cgpaddr, 0, sizeof(at_cgpaddr_resp_t)); + + int cid = -1; + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CGPADDR_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_SET: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* + * The execution command returns a list of PDP addresses for + * the specified context identifiers + */ + if (data->mask & AT_CGPADDR_CID_MASK) + { + if (data->command.cgpaddr.cid < AT_CGPADDR_CID_MIN) { + /* The value of the PDP context identifier is not valid; + * return an error message */ + LOG_TRACE(ERROR, "USR-MAIN - <cid> parameter is " + "not valid (%d)", data->command.cgpaddr.cid); + _nas_user_data.cause_code = AT_ERROR_INCORRECT_PARAMETERS; + ret_code = RETURNerror; + break; + } + cid = data->command.cgpaddr.cid; + } + /* + * Get the PDP addresses + */ + cgpaddr->n_pdns = nas_proc_get_pdn_addr(cid, cgpaddr->cid, + cgpaddr->PDP_addr_1, + cgpaddr->PDP_addr_2, + AT_CGPADDR_RESP_SIZE); + if (cgpaddr->n_pdns == 0) { + LOG_TRACE(ERROR, "USR-MAIN - No any PDN context is defined"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* + * The test command returns a list of defined <cid>s. + */ + cgpaddr->n_pdns = nas_proc_get_pdn_addr(cid, cgpaddr->cid, + cgpaddr->PDP_addr_1, + cgpaddr->PDP_addr_2, + AT_CGPADDR_RESP_SIZE); + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CGPADDR command type %d is " + "not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_cnum() ** + ** ** + ** Description: Executes the AT CNUM command operations: ** + ** The AT CNUM command returns the MSISDNs related to the ** + ** subscriber. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_cnum(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_cnum_resp_t * cnum = &_nas_user_data.response.cnum; + memset(cnum, 0, sizeof(at_cnum_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CNUM_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + if (_nas_user_context.sim_status != NAS_USER_READY) { + _nas_user_data.cause_code = AT_ERROR_SIM_PIN_REQUIRED; + LOG_FUNC_RETURN(RETURNerror); + } + /* Get the International Mobile Subscriber Identity (IMSI) */ + ret_code = nas_proc_get_msisdn(cnum->number, &cnum->type); + if (ret_code != RETURNok) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get MS dialing number"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CNUM command type %d is " + "not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +/**************************************************************************** + ** ** + ** Name: nas_user_proc_clac() ** + ** ** + ** Description: Executes the AT CLAC command operations: ** + ** The AT CLAC command returns the list of AT Commands that ** + ** are available for the user. ** + ** ** + ** Inputs: data: Pointer to the AT command data structure ** + ** Others: _nas_user_context ** + ** ** + ** Outputs: None ** + ** Return: RETURNok; RETURNerror; ** + ** Others: _nas_user_data ** + ** ** + ***************************************************************************/ +static int _nas_user_proc_clac(const at_command_t* data) +{ + LOG_FUNC_IN; + + int ret_code = RETURNok; + at_clac_resp_t * clac = &_nas_user_data.response.clac; + memset(clac, 0, sizeof(at_clac_resp_t)); + + _nas_user_data.id = data->id; + _nas_user_data.type = data->type; + _nas_user_data.mask = AT_RESPONSE_CLAC_MASK; + _nas_user_data.cause_code = AT_ERROR_SUCCESS; + + switch (data->type) + { + case AT_COMMAND_ACT: + /* Get the list of supported AT commands */ + clac->n_acs = at_command_get_list(clac->ac, AT_CLAC_RESP_SIZE); + if (clac->n_acs == 0) { + LOG_TRACE(ERROR, "USR-MAIN - Failed to get the list of " + "supported AT commands"); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + } + break; + + case AT_COMMAND_TST: + /* Nothing to do */ + break; + + default: + LOG_TRACE(ERROR, "USR-MAIN - AT+CLAC command type %d is " + "not supported", data->type); + _nas_user_data.cause_code = AT_ERROR_OPERATION_NOT_SUPPORTED; + ret_code = RETURNerror; + break; + } + + LOG_FUNC_RETURN (ret_code); +} + +#endif // NAS_UE diff --git a/openair-cn/NAS/EURECOM-NAS/src/nas_user.h b/openair-cn/NAS/EURECOM-NAS/src/nas_user.h new file mode 100644 index 0000000000..75a8fbc78c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/nas_user.h @@ -0,0 +1,46 @@ +/***************************************************************************** + +Source nas_user.h + +Version 0.1 + +Date 2012/03/09 + +Product NAS stack + +Subsystem NAS main process + +Author Frederic Maurel + +Description NAS procedure functions triggered by the user + +*****************************************************************************/ +#ifndef __NAS_USER_H__ +#define __NAS_USER_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void nas_user_initialize(emm_indication_callback_t emm_cb, esm_indication_callback_t esm_cb, const char* version); + +int nas_user_process_data(const void* data); + +const void* nas_user_get_data(void); + +#endif /* __NAS_USER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/Makefile b/openair-cn/NAS/EURECOM-NAS/src/util/Makefile new file mode 100644 index 0000000000..7e8b49edc9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/Makefile @@ -0,0 +1,101 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +INCLUDES = -I. -I$(INCDIR) + +TARGET = $(LIBUTIL) +TARGETS = $(TARGET).a $(TARGET).so + +all: $(TARGETS) + +%.o: %.c Makefile + @echo Compiling $< + @$(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET).a: $(OBJS) + @$(RM) $@ + @$(AR) $(ARFLAGS) $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +$(TARGET).so: $(OBJS) + @$(LD) -G -o $@ $(OBJS) + @echo Replacing $@ to $(LIBDIR) + @$(RM) $(LIBDIR)/$@ + @$(CP) $@ $(LIBDIR) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +device.o: device.h +device.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +device.o: /usr/include/stdint.h /usr/include/features.h /usr/include/stdio.h +device.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +device.o: /usr/include/stdlib.h /usr/include/alloca.h /usr/include/string.h +device.o: /usr/include/xlocale.h /usr/include/unistd.h /usr/include/getopt.h +device.o: /usr/include/fcntl.h /usr/include/time.h +memory.o: memory.h +memory.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +memory.o: /usr/include/stdint.h /usr/include/features.h /usr/include/stdio.h +memory.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +memory.o: /usr/include/stdlib.h /usr/include/alloca.h /usr/include/string.h +memory.o: /usr/include/xlocale.h +nas_log.o: nas_log.h /usr/include/stdio.h /usr/include/features.h +nas_log.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +nas_timer.o: nas_timer.h +nas_timer.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_timer.o: /usr/include/stdint.h /usr/include/features.h +nas_timer.o: /usr/include/assert.h /usr/include/pthread.h +nas_timer.o: /usr/include/endian.h /usr/include/sched.h /usr/include/time.h +nas_timer.o: /usr/include/signal.h /usr/include/string.h +nas_timer.o: /usr/include/xlocale.h /usr/include/stdlib.h +nas_timer.o: /usr/include/alloca.h +OctetString.o: /usr/include/stdio.h /usr/include/features.h +OctetString.o: /usr/include/libio.h /usr/include/_G_config.h +OctetString.o: /usr/include/wchar.h /usr/include/stdlib.h +OctetString.o: /usr/include/alloca.h /usr/include/string.h +OctetString.o: /usr/include/xlocale.h TLVEncoder.h /usr/include/arpa/inet.h +OctetString.o: /usr/include/netinet/in.h /usr/include/stdint.h +OctetString.o: /usr/include/endian.h TLVDecoder.h nas_log.h OctetString.h +parser.o: parser.h +parser.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +parser.o: /usr/include/stdint.h /usr/include/features.h /usr/include/stdio.h +parser.o: /usr/include/libio.h /usr/include/_G_config.h /usr/include/wchar.h +parser.o: /usr/include/string.h /usr/include/xlocale.h +socket.o: socket.h +socket.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +socket.o: /usr/include/stdint.h /usr/include/features.h /usr/include/stdlib.h +socket.o: /usr/include/alloca.h /usr/include/string.h /usr/include/xlocale.h +socket.o: /usr/include/unistd.h /usr/include/getopt.h /usr/include/errno.h +socket.o: /usr/include/netdb.h /usr/include/netinet/in.h +socket.o: /usr/include/endian.h /usr/include/rpc/netdb.h +stty.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +stty.o: /usr/include/stdint.h /usr/include/features.h /usr/include/termios.h +stty.o: /usr/include/unistd.h /usr/include/getopt.h /usr/include/string.h +stty.o: /usr/include/xlocale.h /usr/include/stdlib.h /usr/include/alloca.h +TLVDecoder.o: /usr/include/stdio.h /usr/include/features.h +TLVDecoder.o: /usr/include/libio.h /usr/include/_G_config.h +TLVDecoder.o: /usr/include/wchar.h /usr/include/stdlib.h +TLVDecoder.o: /usr/include/alloca.h /usr/include/string.h +TLVDecoder.o: /usr/include/xlocale.h TLVDecoder.h /usr/include/arpa/inet.h +TLVDecoder.o: /usr/include/netinet/in.h /usr/include/stdint.h +TLVDecoder.o: /usr/include/endian.h nas_log.h +TLVEncoder.o: /usr/include/stdio.h /usr/include/features.h +TLVEncoder.o: /usr/include/libio.h /usr/include/_G_config.h +TLVEncoder.o: /usr/include/wchar.h /usr/include/stdlib.h +TLVEncoder.o: /usr/include/alloca.h /usr/include/stdint.h TLVEncoder.h +TLVEncoder.o: /usr/include/arpa/inet.h /usr/include/netinet/in.h +TLVEncoder.o: /usr/include/endian.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.c b/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.c new file mode 100644 index 0000000000..0f85d7a488 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.c @@ -0,0 +1,35 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "TLVEncoder.h" +#include "TLVDecoder.h" +#include "OctetString.h" + +int encode_octet_string(OctetString *octetstring, uint8_t *buffer, uint32_t buflen) +{ + CHECK_PDU_POINTER_AND_LENGTH_ENCODER(buffer, octetstring->length, buflen); + memcpy((void*)buffer, (void*)octetstring->value, octetstring->length); + return octetstring->length; +} + +int decode_octet_string(OctetString *octetstring, uint16_t pdulen, uint8_t *buffer, uint32_t buflen) +{ + if (buflen < pdulen) + return -1; + octetstring->length = pdulen; + octetstring->value = malloc(sizeof(uint8_t) * (pdulen+1)); + memcpy((void*)octetstring->value, (void*)buffer, pdulen); + octetstring->value[pdulen] = '\0'; + return octetstring->length; +} + +void dump_octet_string_xml(OctetString *octetstring) +{ + int i; + printf(" <Length>%u</Length>\n <values>", octetstring->length); + for (i = 0; i < octetstring->length; i++) + printf("0x%x ", octetstring->value[i]); + printf("</values>\n"); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.h b/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.h new file mode 100644 index 0000000000..82ef86989c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/OctetString.h @@ -0,0 +1,18 @@ +#include <stdint.h> + +#ifndef OCTET_STRING_H_ +#define OCTET_STRING_H_ + +typedef struct OctetString_tag { + uint32_t length; + uint8_t *value; +} OctetString; + +int encode_octet_string(OctetString *octetstring, uint8_t *buffer, uint32_t len); + +int decode_octet_string(OctetString *octetstring, uint16_t pdulen, uint8_t *buffer, uint32_t buflen); + +void dump_octet_string_xml(OctetString *octetstring); + +#endif /* OCTET_STRING_H_ */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.c b/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.c new file mode 100644 index 0000000000..0d3672271b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "TLVDecoder.h" + +int errorCodeDecoder = 0; + +const char *errorCodeStringDecoder[] = { + "No error", + "Buffer NULL", + "Buffer too short", + "Unexpected IEI", + "Mandatory field not present", + "Wrong message type", + "EXT value doesn't match", + "Protocol not supported", +}; + +void tlv_decode_perror(void) +{ + if (errorCodeDecoder >= 0) + // No error or TLV_DECODE_ERR_OK + return; + printf("TLV decoder error: (%d, %s)\n", errorCodeDecoder, errorCodeStringDecoder[errorCodeDecoder * -1]); +} + + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.h b/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.h new file mode 100644 index 0000000000..05c4bdbeb8 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/TLVDecoder.h @@ -0,0 +1,112 @@ +#ifndef TLV_DECODER_H_ +#define TLV_DECODER_H_ + +#include <arpa/inet.h> // ntohl, ntohs +#include "nas_log.h" + +#ifndef NAS_DEBUG +# define NAS_DEBUG +#endif + +#define DECODE_U8(bUFFER, vALUE, sIZE) \ + vALUE = *(uint8_t*)(bUFFER); \ + sIZE += sizeof(uint8_t) + +#define DECODE_U16(bUFFER, vALUE, sIZE) \ + vALUE = ntohs(*(uint16_t*)(bUFFER)); \ + sIZE += sizeof(uint16_t) + +#define DECODE_U24(bUFFER, vALUE, sIZE) \ + vALUE = ntohl(*(uint32_t*)(bUFFER)) >> 8; \ + sIZE += sizeof(uint8_t) + sizeof(uint16_t) + +#define DECODE_U32(bUFFER, vALUE, sIZE) \ + vALUE = ntohl(*(uint32_t*)(bUFFER)); \ + sIZE += sizeof(uint32_t) + +#if (BYTE_ORDER == LITTLE_ENDIAN) +# define DECODE_LENGTH_U16(bUFFER, vALUE, sIZE) \ + vALUE = ((*(bUFFER)) << 8) | (*((bUFFER) + 1)); \ + sIZE += sizeof(uint16_t) +#else +# define DECODE_LENGTH_U16(bUFFER, vALUE, sIZE) \ + vALUE = (*(bUFFER)) | (*((bUFFER) + 1) << 8); \ + sIZE += sizeof(uint16_t) +#endif + +#define IES_DECODE_U8(bUFFER, dECODED, vALUE) \ + DECODE_U8(bUFFER + dECODED, vALUE, dECODED) + +#define IES_DECODE_U16(bUFFER, dECODED, vALUE) \ + DECODE_U16(bUFFER + dECODED, vALUE, dECODED) + +#define IES_DECODE_U24(bUFFER, dECODED, vALUE) \ + DECODE_U24(bUFFER + dECODED, vALUE, dECODED) + +#define IES_DECODE_U32(bUFFER, dECODED, vALUE) \ + DECODE_U32(bUFFER + dECODED, vALUE, dECODED) + +typedef enum { + TLV_DECODE_ERROR_OK = 0, + TLV_DECODE_UNEXPECTED_IEI = -1, + TLV_DECODE_MANDATORY_FIELD_NOT_PRESENT = -2, + TLV_DECODE_VALUE_DOESNT_MATCH = -3, + /* Fatal errors - received message should not be processed */ + TLV_DECODE_WRONG_MESSAGE_TYPE = -10, + TLV_DECODE_PROTOCOL_NOT_SUPPORTED = -11, + TLV_DECODE_BUFFER_TOO_SHORT = -12, + TLV_DECODE_BUFFER_NULL = -13, + TLV_DECODE_MAC_MISMATCH = -14, +} tlv_decoder_error_code; + +/* Defines error code limit below which received message should be discarded + * because it cannot be further processed */ +#define TLV_DECODE_FATAL_ERROR (TLV_DECODE_VALUE_DOESNT_MATCH) + +extern int errorCodeDecoder; + +void tlv_decode_perror(void); + +#define CHECK_PDU_POINTER_AND_LENGTH_DECODER(bUFFER, mINIMUMlENGTH, lENGTH) \ + if (bUFFER == NULL) \ + { \ + printf("(%s:%d) Got NULL pointer for the payload\n", \ + __FILE__, __LINE__); \ + errorCodeDecoder = TLV_DECODE_BUFFER_NULL; \ + LOG_FUNC_RETURN(TLV_DECODE_BUFFER_NULL); \ + } \ + if (lENGTH < mINIMUMlENGTH) \ + { \ + printf("(%s:%d) Expecting at least %d bytes, got %d\n", \ + __FILE__, __LINE__, mINIMUMlENGTH, lENGTH); \ + errorCodeDecoder = TLV_DECODE_BUFFER_TOO_SHORT; \ + LOG_FUNC_RETURN(TLV_DECODE_BUFFER_TOO_SHORT); \ + } + +#define CHECK_LENGTH_DECODER(bUFFERlENGTH, lENGTH) \ + if (bUFFERlENGTH < lENGTH) \ + { \ + errorCodeDecoder = TLV_DECODE_BUFFER_TOO_SHORT; \ + LOG_FUNC_RETURN(TLV_DECODE_BUFFER_TOO_SHORT); \ + } + +#define CHECK_MESSAGE_TYPE(mESSAGE_tYPE, bUFFER) \ + { \ + if (mESSAGE_tYPE != bUFFER) \ + { \ + errorCodeDecoder = TLV_DECODE_WRONG_MESSAGE_TYPE; \ + LOG_FUNC_RETURN(errorCodeDecoder); \ + } \ + } + +#define CHECK_IEI_DECODER(iEI, bUFFER) \ + if(iEI != bUFFER) \ + { \ + printf("IEI is different than the one expected." \ + "(Got: 0x%x, expecting: 0x%x\n", bUFFER, iEI); \ + errorCodeDecoder = TLV_DECODE_UNEXPECTED_IEI; \ + LOG_FUNC_RETURN(TLV_DECODE_UNEXPECTED_IEI); \ + } + +#endif /* define (TLV_DECODER_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.c b/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.c new file mode 100644 index 0000000000..abaccf664e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.c @@ -0,0 +1,25 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "TLVEncoder.h" + +int errorCodeEncoder = 0; + +const char *errorCodeStringEncoder[] = { + "No error", + "Buffer NULL", + "Buffer too short", + "Octet string too long for IEI", + "Wrong message type", + "Protocol not supported", +}; + +void tlv_encode_perror(void) +{ + if (errorCodeEncoder >= 0) + // No error or TLV_DECODE_ERR_OK + return; + printf("error: (%d, %s)\n", errorCodeEncoder, errorCodeStringEncoder[errorCodeEncoder * -1]); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.h b/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.h new file mode 100644 index 0000000000..b82a0f8fbc --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/TLVEncoder.h @@ -0,0 +1,77 @@ +#ifndef TLV_ENCODER_H_ +#define TLV_ENCODER_H_ + +#include <arpa/inet.h> // htonl, htons + +#define ENCODE_U8(buffer, value, size) \ + *(uint8_t*)(buffer) = value; \ + size += sizeof(uint8_t) + +#define ENCODE_U16(buffer, value, size) \ + *(uint16_t*)(buffer) = htons(value); \ + size += sizeof(uint16_t) + +#define ENCODE_U24(buffer, value, size) \ + *(uint32_t*)(buffer) = htonl(value); \ + size += sizeof(uint8_t) + sizeof(uint16_t) + +#define ENCODE_U32(buffer, value, size) \ + *(uint32_t*)(buffer) = htonl(value); \ + size += sizeof(uint32_t) + +#define IES_ENCODE_U8(buffer, encoded, value) \ + ENCODE_U8(buffer + encoded, value, encoded) + +#define IES_ENCODE_U16(buffer, encoded, value) \ + ENCODE_U16(buffer + encoded, value, encoded) + +#define IES_ENCODE_U24(buffer, encoded, value) \ + ENCODE_U24(buffer + encoded, value, encoded) + +#define IES_ENCODE_U32(buffer, encoded, value) \ + ENCODE_U32(buffer + encoded, value, encoded) + +typedef enum { + TLV_ENCODE_ERROR_OK = 0, + TLV_ENCODE_VALUE_DOESNT_MATCH = -1, + /* Fatal errors - message should not be sent */ + TLV_ENCODE_OCTET_STRING_TOO_LONG_FOR_IEI = -10, + TLV_ENCODE_WRONG_MESSAGE_TYPE = -11, + TLV_ENCODE_PROTOCOL_NOT_SUPPORTED = -12, + TLV_ENCODE_BUFFER_TOO_SHORT = -13, + TLV_ENCODE_BUFFER_NULL = -14, +} tlv_encoder_error_code; + +/* Defines error code limit below which message should be sent because + * it cannot be further processed */ +#define TLV_ENCODE_FATAL_ERROR (TLV_ENCODE_VALUE_DOESNT_MATCH) + +extern int errorCodeEncoder; + +void tlv_encode_perror(void); + +#define CHECK_PDU_POINTER_AND_LENGTH_ENCODER(bUFFER, mINIMUMlENGTH, lENGTH) \ + if (bUFFER == NULL) \ + { \ + printf("Got NULL pointer for the payload\n"); \ + errorCodeEncoder = TLV_ENCODE_BUFFER_NULL; \ + return TLV_ENCODE_BUFFER_NULL; \ + } \ + if (lENGTH < mINIMUMlENGTH) \ + { \ + printf("(%s:%d) Expecting at least %d bytes, got %d\n", \ + __FILE__, __LINE__, mINIMUMlENGTH, lENGTH); \ + errorCodeEncoder = TLV_ENCODE_BUFFER_TOO_SHORT; \ + return TLV_ENCODE_BUFFER_TOO_SHORT; \ + } + +#define CHECK_PDU_POINTER_ENCODER(bUFFER) \ + if (bUFFER == NULL) \ + { \ + printf("Got NULL pointer for the payload\n"); \ + errorCodeEncoder = TLV_ENCODE_BUFFER_NULL; \ + return TLV_ENCODE_BUFFER_NULL; \ + } + +#endif /* define (TLV_ENCODER_H_) */ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/device.c b/openair-cn/NAS/EURECOM-NAS/src/util/device.c new file mode 100644 index 0000000000..db3ca37518 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/device.c @@ -0,0 +1,233 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source device.c + +Version 0.1 + +Date 2012/11/29 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Implements Linux/UNIX I/O device handlers + +*****************************************************************************/ + +#include "device.h" +#include "commonDef.h" + +#include <stdio.h> // fflush +#include <stdlib.h> // malloc, free +#include <string.h> // strncpy +#include <unistd.h> // read, write, close + +#include <sys/stat.h> +#include <fcntl.h> // open + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/* Function used to configure TTY I/O terminal attributes */ +extern int stty_set(int fd, const char *params); + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* ------------------------ + * Identifier of the device + * ------------------------ + * A device is defined with a pathname and attribute parameters. + * A file descriptor is created to handle the setup of the device + * attributes. + */ +struct device_id_s { +#define DEVICE_PATHNAME_SIZE 32 + char pathname[DEVICE_PATHNAME_SIZE+1]; /* device pathname */ + int fd; /* device file descriptor */ +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: device_open() ** + ** ** + ** Description: Open a device to get a file descriptor for use with read ** + ** and write I/O operations ** + ** ** + ** Inputs: devpath: Device path name ** + ** params: Device parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: A pointer to the device identifier alloca- ** + ** ted for I/O operations. NULL if the device ** + ** has not been successfully opened. ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* device_open(int type, const char* devpath, const char* params) +{ + int fd; + + /* Parameters sanity check */ + if (devpath == NULL) { + return NULL; + } + if (type != DEVICE) { + return NULL; + } + + /* Open the device for I/O operations */ + fd = open(devpath, O_RDWR); + if (fd < 0) { + return NULL; + } + + /* The device has been successfully opened */ + device_id_t * devid = (device_id_t *)malloc(sizeof(struct device_id_s)); + if (devid != NULL) { + strncpy(devid->pathname, devpath, DEVICE_PATHNAME_SIZE); + devid->fd = fd; + if (params != NULL) { + /* Set TTY parameters */ + if (stty_set(fd, params) != RETURNok) { + device_close(devid); + devid = NULL; + } + } + } + return devid; +} + +/**************************************************************************** + ** ** + ** Name: device_close() ** + ** ** + ** Description: Close the specified device and frees memory space alloca- ** + ** ted to handle access to the device ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: id: The identifier of the device ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void device_close(void* id) +{ + if (id) { + close( ((device_id_t*)id)->fd ); + free(id); + } +} + +/**************************************************************************** + ** ** + ** Name: device_read() ** + ** ** + ** Description: Read data from the given I/O device into the input buffer ** + ** of specified length ** + ** ** + ** Inputs: id: The identifier of the device ** + ** len: The number of bytes to read ** + ** Others: None ** + ** ** + ** Outputs: buffer: The input buffer ** + ** Return: The number of bytes read when success; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +ssize_t device_read(void* id, char* buffer, size_t len) +{ + const device_id_t* devid = (device_id_t*)(id); +#if 0 + ssize_t rbytes = read(devid->fd, buffer, len); + if (rbytes < 0) { + return RETURNerror; + } +#endif + + //#if 0 + ssize_t rbytes = 0; + do { + ssize_t size = read(devid->fd, buffer + rbytes, len - rbytes); + if (size < 0) { + return RETURNerror; + } + rbytes += size; + } while ( (buffer[rbytes-1] != '\r') && (buffer[rbytes-1] != '\n') + && (buffer[rbytes-1] != '\0') ); + //#endif + + return rbytes; +} + +/**************************************************************************** + ** ** + ** Name: device_write() ** + ** ** + ** Description: Write data to the given I/O device from the output buffer ** + ** of specified length ** + ** ** + ** Inputs: id: The identifier of the device ** + ** buffer: The output buffer ** + ** len: The number of bytes to write ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes written when success; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +ssize_t device_write(const void* id, const char* buffer, size_t len) +{ + const device_id_t* devid = (device_id_t*)(id); + ssize_t sbytes = write(devid->fd, buffer, len); + fflush(NULL); + + if (sbytes != len) { + return RETURNerror; + } + return sbytes; +} + +/**************************************************************************** + ** ** + ** Name: device_get_fd() ** + ** ** + ** Description: Get the value of the file descriptor created to handle ** + ** the device with the given identifier ** + ** ** + ** Inputs: id: The identifier of the device ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The file descriptor of the device ** + ** Others: None ** + ** ** + ***************************************************************************/ +int device_get_fd(const void* id) +{ + if (id) { + return ((device_id_t*)id)->fd; + } + return RETURNerror; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/device.h b/openair-cn/NAS/EURECOM-NAS/src/util/device.h new file mode 100644 index 0000000000..458fb3ab3f --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/device.h @@ -0,0 +1,55 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source device.h + +Version 0.1 + +Date 2012/11/29 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Implements Linux/UNIX I/O device handlers + +*****************************************************************************/ +#ifndef __DEVICE_H__ +#define __DEVICE_H__ + +#include <sys/types.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* Type of the connection endpoint */ +#define DEVICE 3 + +/* Hidden structure that handles device data */ +typedef struct device_id_s device_id_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void* device_open(int type, const char* devname, const char* params); +int device_get_fd(const void* id); + +ssize_t device_read(void* id, char* buffer, size_t length); +ssize_t device_write(const void* id, const char* buffer, size_t length); + +void device_close(void* id); + +#endif /* __DEVICE_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/memory.c b/openair-cn/NAS/EURECOM-NAS/src/util/memory.c new file mode 100644 index 0000000000..5d434be03a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/memory.c @@ -0,0 +1,152 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source memory.c + +Version 0.1 + +Date 2012/10/09 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Memory access utilities + +*****************************************************************************/ + +#include "memory.h" +#include "commonDef.h" + +#include <stdio.h> // fopen, fread, fclose +#include <stdlib.h> // getenv, malloc, free +#include <string.h> // strlen + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: memory_get_path() ** + ** ** + ** Description: Gets the absolute path of the file where non-volatile ** + ** data are located ** + ** ** + ** Inputs: dirname: The directory where data file is located ** + ** filename: The name of the data file ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The absolute path of the non-volatile data ** + ** file. The returned value is a dynamically ** + ** allocated octet string that needs to be ** + ** freed after usage. ** + ** Others: None ** + ** ** + ***************************************************************************/ +char* memory_get_path(const char* dirname, const char* filename) +{ + /* Get non-volatile data directory */ + const char* path = getenv(dirname); + if (path == NULL) { + path = getenv(DEFAULT_NAS_PATH); + } + + /* Append non-volatile data file name */ + size_t size = strlen(path) + strlen(filename) + 1; + char* data_filename = (char*)malloc(size+1); + if (data_filename != NULL) { + if (size != sprintf(data_filename, "%s/%s", path, filename)) { + free(data_filename); + return NULL; + } + } + + return data_filename; +} + +/**************************************************************************** + ** ** + ** Name: memory_read() ** + ** ** + ** Description: Reads data from a non-volatile data file ** + ** ** + ** Inputs: datafile: The absolute path to the data file ** + ** size: The size of the data to read ** + ** Others: None ** + ** ** + ** Outputs: data: Pointer to the data read ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int memory_read(const char* datafile, void* data, size_t size) +{ + int rc = RETURNerror; + + /* Open the data file for reading operation */ + FILE* fp = fopen(datafile, "rb"); + if (fp != NULL) { + /* Read data */ + size_t n = fread(data, size, 1, fp); + if (n == 1) { + rc = RETURNok; + } + /* Close the data file */ + fclose(fp); + } + + return (rc); +} + +/**************************************************************************** + ** ** + ** Name: memory_write() ** + ** ** + ** Description: Writes data to a non-volatile data file ** + ** ** + ** Inputs: datafile: The absolute path to the data file ** + ** data: Pointer to the data to write ** + ** size: The size of the data to write ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int memory_write(const char* datafile, const void* data, size_t size) +{ + int rc = RETURNerror; + + /* Open the data file for writing operation */ + FILE* fp = fopen(datafile, "wb"); + if (fp != NULL) { + /* Write data */ + size_t n = fwrite(data, size, 1, fp); + if (n == 1) { + rc = RETURNok; + } + /* Close the data file */ + fclose(fp); + } + + return (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/memory.h b/openair-cn/NAS/EURECOM-NAS/src/util/memory.h new file mode 100644 index 0000000000..1491150141 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/memory.h @@ -0,0 +1,47 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source memory.h + +Version 0.1 + +Date 2012/10/09 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Memory access utilities + +*****************************************************************************/ +#ifndef __MEMORY_H__ +#define __MEMORY_H__ + +#include <stddef.h> // size_t + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +char* memory_get_path(const char* dirname, const char* filename); + +int memory_read(const char* datafile, void* data, size_t size); + +int memory_write(const char* datafile, const void* data, size_t size); + +#endif /* __MEMORY_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.c b/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.c new file mode 100644 index 0000000000..18dd0ef1f7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.c @@ -0,0 +1,242 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source log.c + +Version 0.1 + +Date 2012/02/28 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Usefull logging functions + +*****************************************************************************/ + +#include "nas_log.h" + +#include <stdio.h> // stderr, sprintf, fprintf, vfprintf +#include <stdarg.h> // va_list, va_start, va_end + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/* ANSI escape codes for colored display */ +#define LOG_BLACK "\033[30m" +#define LOG_RED "\033[31m" +#define LOG_GREEN "\033[32m" +#define LOG_YELLOW "\033[33m" +#define LOG_BLUE "\033[34m" +#define LOG_MAGENTA "\033[35m" +#define LOG_CYAN "\033[36m" +#define LOG_WHITE "\033[37m" +#define LOG_END "\033[0m" +#define LOG_AUTO LOG_END + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* ------------------------ + * Internal logging context + * ------------------------ + * Internal logging context consists on: + * - The file name and the line number from where the data have been + * logged. These information are gathered into a string that will + * be displayed as a prefix of the logging trace with the format + * filename[line] + * - The severity level filter + * - The indentation level to convey FUNC logging traces + * - The data definition of each logging trace level: name and mask + * (the mask is used against the severity level filter to enable + * or disable specific logging traces) + */ +typedef struct +{ +#define LOG_PREFIX_SIZE 96 + char prefix[LOG_PREFIX_SIZE]; + unsigned char filter; + int indent; + const struct { + char* name; + unsigned char mask; + char* color; + } level[]; +} log_context_t; + +/* + * Definition of the logging context + */ +static log_context_t _log_context = { + "", /* prefix */ + 0x00, /* filter */ + 0, /* indent */ + { + { "DEBUG", LOG_DEBUG, LOG_GREEN }, /* DEBUG */ + { "INFO", LOG_INFO, LOG_AUTO }, /* INFO */ + { "WARNING", LOG_WARNING, LOG_BLUE }, /* WARNING */ + { "ERROR", LOG_ERROR, LOG_RED }, /* ERROR */ + { "", LOG_FUNC, LOG_AUTO }, /* FUNC_IN */ + { "", LOG_FUNC, LOG_AUTO }, /* FUNC_OUT */ + } /* level[] */ +}; + +/* Maximum number of bytes into a line of dump logging data */ +#define LOG_DUMP_LINE_SIZE 16 + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: log_init() ** + ** ** + ** Description: Initializes internal logging data ** + ** ** + ** Inputs: filter: Value of the severity level that will be ** + ** used as a filter to enable or disable ** + ** specific logging traces ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void nas_log_init(char filter) +{ + _log_context.filter = filter; +} + +/**************************************************************************** + ** ** + ** Name: log_data() ** + ** ** + ** Description: Defines internal logging data ** + ** ** + ** Inputs: filename: Name of the file from where the data have ** + ** been logged ** + ** line: Number of the line in the file ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void log_data(const char* filename, int line) +{ + snprintf(_log_context.prefix, LOG_PREFIX_SIZE, "%s[%d]", filename, line); +} + +/**************************************************************************** + ** ** + ** Name: log_trace() ** + ** ** + ** Description: Displays logging data ** + ** ** + ** Inputs: severity: Severity level of the logging data ** + ** data: Formated logging data to display ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void log_trace(log_severity_t severity, const char* data, ...) +{ + int i; + + /* Sanity check */ + if (severity > LOG_SEVERITY_MAX) return; + + /* Display only authorized logging traces */ + if (_log_context.level[severity].mask & _log_context.filter) + { + va_list argp; + + /* + * First, display internal logging data (logging trace prefix: file + * name and line number from where the data have been logged) and + * the severity level. + */ + fprintf(stderr, "%s%-60.58s%-10s", _log_context.level[severity].color, + _log_context.prefix, _log_context.level[severity].name); + { + /* Next, perform indentation for FUNC logging trace */ + if (severity == FUNC_OUT) { + _log_context.indent--; + } + for (i=0; i<_log_context.indent; i++) { + fprintf(stderr, "\t"); + } + if (severity == FUNC_IN) { + _log_context.indent++; + } + } + + /* Finally, display logging data */ + va_start(argp, data); + vfprintf(stderr, data, argp); + + /* Terminate with line feed character */ + fprintf(stderr, "%s\n", LOG_END); + + va_end(argp); + } +} + +/**************************************************************************** + ** ** + ** Name: log_dump() ** + ** ** + ** Description: Dump logging data ** + ** ** + ** Inputs: data: Logging data to dump ** + ** len: Number of bytes to be dumped ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void log_dump(const char* data, int len) +{ + int i; + /* Display only authorized logging traces */ + if ( (len > 0) && (LOG_HEX & _log_context.filter) ) + { + int bytes = 0; + + fprintf(stderr, "\n\t"); + + for (i=0; i < len; i++) + { + fprintf(stderr, "%.2hx ", (const unsigned char) data[i]); + + /* Add new line when the number of displayed bytes exceeds + * the line's size */ + if ( ++bytes > (LOG_DUMP_LINE_SIZE - 1) ) { + bytes = 0; + fprintf(stderr, "\n\t"); + } + } + + if (bytes % LOG_DUMP_LINE_SIZE) { + fprintf(stderr, "\n"); + } + + fprintf(stderr, "\n"); + fflush(stderr); + } +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.h b/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.h new file mode 100644 index 0000000000..fba5a8a38a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/nas_log.h @@ -0,0 +1,93 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source log.h + +Version 0.1 + +Date 2012/02/28 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Usefull logging functions + +*****************************************************************************/ +#ifndef __NAS_LOG_H__ +#define __NAS_LOG_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* ----------------------- + * Logging severity levels + * ----------------------- + * OFF : Disables logging trace utilities. + * DEBUG : Only used for debug purpose. Should be removed from the code. + * INFO : Informational trace + * WARNING : The program displays the warning message and doesn't stop. + * ERROR : The program displays the error message and usually exits or + * runs appropriate procedure. + * FUNC : Prints trace when entering/leaving to/from function. Usefull + * to display the function's calling tree information at runtime. + * ON : Enables logging traces excepted FUNC. + * ALL : Turns on ALL logging traces. + */ +#define LOG_OFF 0x00 /* No trace */ +#define LOG_DEBUG 0x01 /* Debug trace */ +#define LOG_INFO 0x02 /* Informational trace */ +#define LOG_WARNING 0x04 /* Warning trace */ +#define LOG_ERROR 0x08 /* Error trace */ +#define LOG_FUNC 0x10 /* Entering/Leaving function trace */ +#define LOG_HEX 0x20 /* Dump trace */ + +#define LOG_ON 0x0F /* All traces excepted FUNC and HEX */ +#define LOG_ALL 0xFF /* All traces */ + +/* Logging severity type */ +typedef enum +{ + DEBUG, + INFO, + WARNING, + ERROR, + FUNC_IN, + FUNC_OUT, + LOG_SEVERITY_MAX +} log_severity_t; + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#define LOG_TRACE log_data(__FILE__, __LINE__); log_trace +#define LOG_DUMP(a, b) log_dump((a),(b)); + +#define LOG_FUNC_IN LOG_TRACE(FUNC_IN, "Entering %s()", __FUNCTION__) +#define LOG_FUNC_OUT LOG_TRACE(FUNC_OUT, "Leaving %s()", __FUNCTION__) +#define LOG_FUNC_RETURN(rETURNcODE) \ +do { \ + LOG_TRACE(FUNC_OUT, "Leaving %s(rc = %ld)", __FUNCTION__, \ + (long) rETURNcODE); \ + return (rETURNcODE); \ +} while(0) + +void nas_log_init(char filter); +void log_data(const char* filename, int line); +void log_trace(log_severity_t severity, const char* data, ...); +void log_dump(const char* data, int len); + +#endif /* __NAS_LOG_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.c b/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.c new file mode 100644 index 0000000000..5b18e3d3b9 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.c @@ -0,0 +1,729 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source timer.c + +Version 0.1 + +Date 2012/10/09 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Timer utilities + +*****************************************************************************/ + +#if defined(NAS_MME) && defined(EPC_BUILD) +# include "TIMER/timer.h" +#endif +#include "nas_timer.h" +#include "commonDef.h" + +#include <assert.h> +#include <pthread.h> +#include <signal.h> + +#include <string.h> // memset +#include <time.h> // clock_gettime +#include <sys/time.h> // setitimer +#include <stdlib.h> // malloc, free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Structure of an interval timer entry + * ------------------------------------ + * The callback function is scheduled to be executed upon expiration of + * the timer that has been previously setup to the initial interval time + * value when the timer entry was allocated. + */ +typedef struct { + struct timeval itv; /* Initial interval timer value */ + struct timeval tv; /* Interval timer value */ + nas_timer_callback_t cb; /* Callback executed at timer expiration */ + void* args; /* Callback argument parameters */ + pthread_t pid; /* Thread identifier of the callback */ +} nas_timer_entry_t; + +/* Structure of a timer queue - list of active interval timer entries + * ------------------------------------------------------------------ + * At any time, the first entry of the queue is always associated to the + * first timer that will come to expire. Upon timer expiration, the first + * entry is removed from the queue and freed. + */ +typedef struct _nas_timer_queue_t { + int id; /* Identifier of the current timer entry */ + nas_timer_entry_t* entry; /* The current timer entry */ + struct _nas_timer_queue_t* prev;/* The previous timer entry in the queue */ + struct _nas_timer_queue_t* next;/* The next timer entry in the queue */ +} timer_queue_t; + +/* Structure of a timer database + * ----------------------------- + * The timer database is managed to provide unique identifier to timer at + * startup and to maintain an ordered queue of active timer entries. + */ +typedef struct { + int timer_id; /* Identifier of the first available timer entry */ +#define TIMER_DATABASE_SIZE 256 + timer_queue_t tq[TIMER_DATABASE_SIZE]; + timer_queue_t* head;/* Pointer to the first timer entry to be fired */ + pthread_mutex_t mutex; +} nas_timer_database_t; + +/* + * The timer database + */ +static nas_timer_database_t _nas_timer_db = {0, {}, NULL, PTHREAD_MUTEX_INITIALIZER}; + +/* + * The handler executed whenever the system timer expires + */ +static void _nas_timer_handler(int signal); + +/* + * ----------------------------------------------------------------------------- + * Functions used to manage the timer database + * ----------------------------------------------------------------------------- + */ +static void _nas_timer_db_init(void); + +static int _nas_timer_db_get_id(void); +static int _nas_timer_db_is_active(int id); +static nas_timer_entry_t* _nas_timer_db_create_entry(long sec, nas_timer_callback_t cb, void* args); +static void _nas_timer_db_delete_entry(int id); + +static void _nas_timer_db_insert_entry(int id, nas_timer_entry_t* te); +static int _nas_timer_db_insert(timer_queue_t* entry); + +static nas_timer_entry_t* _nas_timer_db_remove_entry(int id); +static int _nas_timer_db_remove(timer_queue_t* entry); + +/* + * ----------------------------------------------------------------------------- + * Operator functions for timeval structures + * ----------------------------------------------------------------------------- + */ +static int _nas_timer_cmp(const struct timeval* a, const struct timeval* b); +static void _nas_timer_add(const struct timeval* a, const struct timeval* b, struct timeval* result); +static int _nas_timer_sub(const struct timeval* a, const struct timeval* b, struct timeval* result); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: timer_init() ** + ** ** + ** Description: Initializes internal data used to manage timers ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +int nas_timer_init(void) +{ + /* Initialize the timer database */ + _nas_timer_db_init(); + + /* Setup the timer database handler */ + struct sigaction act; + + (void) memset (&act, 0, sizeof (act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + act.sa_handler = _nas_timer_handler; + if ( sigaction (SIGALRM, &act, 0) < 0 ) { + return (RETURNerror); + } + return (RETURNok); +} + +/**************************************************************************** + ** ** + ** Name: timer_start() ** + ** ** + ** Description: Schedules the execution of the given callback function ** + ** upon expiration of the specified time interval ** + ** ** + ** Inputs: sec: The value of the time interval in seconds ** + ** cb: Function executed upon timer expiration ** + ** args: Callback argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The timer identifier when successfully ** + ** started; NAS_TIMER_INACTIVE_ID otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_timer_start(long sec, nas_timer_callback_t cb, void* args) +{ + /* Do not start null timer */ + if (sec == 0) { + return (NAS_TIMER_INACTIVE_ID); + } + + /* Get an identifier for the new timer entry */ + int id = _nas_timer_db_get_id(); + if (id < 0) { + /* No available timer entry found */ + return (NAS_TIMER_INACTIVE_ID); + } + + /* Create a new timer entry */ + nas_timer_entry_t* te = _nas_timer_db_create_entry(sec, cb, args); + if (te == NULL) { + return (NAS_TIMER_INACTIVE_ID); + } + + /* Insert the new entry into the timer queue */ + _nas_timer_db_insert_entry(id, te); + return (id); +} + +/**************************************************************************** + ** ** + ** Name: timer_stop() ** + ** ** + ** Description: Stop the timer with the specified identifier ** + ** ** + ** Inputs: id: The identifier of the timer to be stopped ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: NAS_TIMER_INACTIVE_ID when successfully stop- ** + ** ped; The timer identifier otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_timer_stop(int id) +{ + /* Check if the timer entry is active */ + if (_nas_timer_db_is_active(id)) { + /* Remove the entry from the timer queue */ + (void) _nas_timer_db_remove_entry(id); + /* Delete the timer entry */ + _nas_timer_db_delete_entry(id); + return (NAS_TIMER_INACTIVE_ID); + } + return (id); +} + +/**************************************************************************** + ** ** + ** Name: timer_restart() ** + ** ** + ** Description: Restart the timer with the specified identifier. The ti- ** + ** mer is scheduled to expire after the same period of time ** + ** and will execute the callback function that has been set ** + ** when it was started. ** + ** ** + ** Inputs: id: The identifier of the timer to be started ** + ** again ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The timer identifier when successfully ** + ** re-started; NAS_TIMER_INACTIVE_ID otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +int nas_timer_restart(int id) +{ + /* Check if the timer entry is active */ + if (_nas_timer_db_is_active(id)) { + /* Remove the entry from the timer queue */ + nas_timer_entry_t* te = _nas_timer_db_remove_entry(id); + /* Initialize its interval timer value */ + te->tv = te->itv; + /* Insert again the entry into the timer queue */ + _nas_timer_db_insert_entry(id, te); + return (id); + } + return (NAS_TIMER_INACTIVE_ID); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _nas_timer_handler() ** + ** ** + ** Description: The timer handler is executed whenever the system deli- ** + ** vers signal SIGALARM. It starts execution of the callback ** + ** function of the first entry within the queue of active ** + ** timer entries. The entry is not removed from the queue of ** + ** active timer entries and shall be explicitly removed when ** + ** the timer expires. ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static void _nas_timer_handler(int signal) +{ + /* At least one timer has been started */ + assert( (_nas_timer_db.head != NULL) && (_nas_timer_db.head->entry != NULL) ); + + /* Get the timer entry for which the system timer expired */ + nas_timer_entry_t* te = _nas_timer_db.head->entry; + + /* Execute the callback function */ + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); + int rc = pthread_create (&te->pid, &attr, te->cb, te->args); + pthread_attr_destroy(&attr); + + /* Wait for the thread to terminate before releasing the timer entry */ + if (rc == 0) { + void* result = NULL; + (void) pthread_join(te->pid, &result); + /* TODO: Check returned result ??? */ + if (result) free(result); + } +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to manage the timer database + * ----------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_init() ** + ** ** + ** Description: Initializes the timer database ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static void _nas_timer_db_init(void) +{ + for (int i = 0; i < TIMER_DATABASE_SIZE; i++) { + _nas_timer_db.tq[i].id = NAS_TIMER_INACTIVE_ID; + } +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_get_id() ** + ** ** + ** Description: Gets the identifier of the first available timer entry in ** + ** the queue of active timer entries ** + ** ** + ** Inputs: None ** + ** Others: _nas_timer_db ** + ** ** + ** Outputs: None ** + ** Return: The identifier of the first available ** + ** timer entry if the queue of active timers ** + ** is not full; -1 otherwise. ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static int _nas_timer_db_get_id(void) +{ + int i; + /* Search from the current timer entry to the last timer entry */ + for (i = _nas_timer_db.timer_id; i < TIMER_DATABASE_SIZE; i++) { + if (_nas_timer_db.tq[i].id < 0 ) { + _nas_timer_db.timer_id = i+1; + return i; + } + } + /* Search from the first timer entry to the current timer entry */ + for (i = 0; i < _nas_timer_db.timer_id; i++) { + if (_nas_timer_db.tq[i].id < 0 ) { + _nas_timer_db.timer_id = i+1; + return i; + } + } + /* No available timer entry found */ + return (-1); +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_is_active() ** + ** ** + ** Description: Checks whether the entry with the given identifier is ** + ** active within the queue of active timer entries ** + ** ** + ** Inputs: id: Identifier of the timer entry to check ** + ** Others: _nas_timer_db ** + ** ** + ** Outputs: None ** + ** Return: TRUE if the timer entry is active; FALSE ** + ** if it is not an active timer entry. ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_timer_db_is_active(int id) +{ + return ( (id != NAS_TIMER_INACTIVE_ID) && + (_nas_timer_db.tq[id].id != NAS_TIMER_INACTIVE_ID) ); +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_create_entry() ** + ** ** + ** Description: Creates a new timer entry ** + ** ** + ** Inputs: sec: Time interval value ** + ** cb: Function executed upon timer expiration ** + ** args: Callback argument parameters ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: A pointer to the new timer entry if ** + ** successfully allocated; NULL otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static nas_timer_entry_t* _nas_timer_db_create_entry( + long sec, nas_timer_callback_t cb, + void* args) +{ + nas_timer_entry_t* te = (nas_timer_entry_t*)malloc(sizeof(nas_timer_entry_t)); + if (te != NULL) { + te->itv.tv_sec = sec; + te->itv.tv_usec = 0; + te->tv = te->itv; + te->cb = cb; + te->args = args; + } + return (te); +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_delete_entry() ** + ** ** + ** Description: Deletes the entry with the given identifier from the ti- ** + ** mer database. ** + ** ** + ** Inputs: id: Identifier of the entry to be deleted ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static void _nas_timer_db_delete_entry(int id) +{ + /* The identifier of the timer is valid within the timer queue */ + assert(_nas_timer_db.tq[id].id == id); + + /* Delete the timer entry from the queue */ + _nas_timer_db.tq[id].id = NAS_TIMER_INACTIVE_ID; + free(_nas_timer_db.tq[id].entry); + _nas_timer_db.tq[id].entry = NULL; +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_insert_entry() ** + ** ** + ** Description: Inserts the entry with the given identifier into the ** + ** queue of active timer entries and restarts the system ** + ** timer if the new entry is the next entry for which the ** + ** timer should be scheduled to expire. ** + ** ** + ** Inputs: id: Identifier of the new entry ** + ** te: Pointer to the entry to be inserted ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: None ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static void _nas_timer_db_insert_entry(int id, nas_timer_entry_t* te) +{ + /* Enqueue the new timer entry */ + _nas_timer_db.tq[id].id = id; + _nas_timer_db.tq[id].entry = te; + + /* Save its interval timer value */ + struct itimerval it; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + it.it_value = te->tv; + + /* Update its interval timer value */ + struct timespec ts; + struct timeval current_time; + clock_gettime(CLOCK_MONOTONIC, &ts); + current_time.tv_sec = ts.tv_sec; + current_time.tv_usec = ts.tv_nsec/1000; + /* tv = tv + time() */ + _nas_timer_add(&te->tv, ¤t_time, &te->tv); + + /* Insert the new timer entry into the list of active entries */ + pthread_mutex_lock(&_nas_timer_db.mutex); + int restart = _nas_timer_db_insert(&_nas_timer_db.tq[id]); + pthread_mutex_unlock(&_nas_timer_db.mutex); + + if (restart) { + /* The new entry is the first entry of the list; + * restart the system timer */ + setitimer(ITIMER_REAL, &it, 0); + } +} + +static int _nas_timer_db_insert(timer_queue_t* entry) +{ + timer_queue_t *prev, *next; /* previous and next entry in the list */ + /* + * Search the list of timer entries for the first entry with an interval + * timer value greater than the interval timer value of the new timer entry + */ + for (prev = NULL, next = _nas_timer_db.head; next != NULL; next = next->next) { + if (_nas_timer_cmp(&next->entry->tv, &entry->entry->tv) > 0) { + break; + } + prev = next; + } + /* Insert the new entry in the list of active timer entries */ + /* prev <-- entry --> next */ + entry->prev = prev; + entry->next = next; + /* Update the pointer from the previous entry */ + if (entry->next != NULL) { + /* prev <-- entry <--> next */ + entry->next->prev = entry; + } + /* Update the pointer from the next entry */ + if (entry->prev != NULL) { + /* prev <--> entry <--> next */ + entry->prev->next = entry; + } + else { + /* The new entry is the first entry of the list */ + _nas_timer_db.head = entry; + return TRUE; + } + /* The new entry is NOT the first entry of the list */ + return FALSE; +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_db_remove_entry() ** + ** ** + ** Description: Removes the entry with the given identifier from the ** + ** queue of active timer entries and restarts the system ** + ** timer if the entry was the next entry for which the timer ** + ** was scheduled to expire. ** + ** ** + ** Inputs: id: Identifier of the entry to be removed ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: A pointer to the removed entry ** + ** Others: _nas_timer_db ** + ** ** + ***************************************************************************/ +static nas_timer_entry_t* _nas_timer_db_remove_entry(int id) +{ + /* The identifier of the timer is valid within the timer queue */ + assert(_nas_timer_db.tq[id].id == id); + + /* Remove the timer entry from the list of active entries */ + pthread_mutex_lock(&_nas_timer_db.mutex); + int restart = _nas_timer_db_remove(&_nas_timer_db.tq[id]); + pthread_mutex_unlock(&_nas_timer_db.mutex); + + if (restart) { + int rc; + /* The entry was the first entry of the list; + * the system timer needs to be restarted */ + struct itimerval it; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + struct timeval time; + time.tv_sec = ts.tv_sec; + time.tv_usec = ts.tv_nsec/1000; + /* tv = tv - time() */ + rc = _nas_timer_sub(&_nas_timer_db.head->entry->tv, &time, &it.it_value); + if (rc < 0) { + /* The system timer should has already expired */ + _nas_timer_handler(SIGALRM); + } + else { + /* Restart the system timer */ + setitimer(ITIMER_REAL, &it, 0); + } + } + + /* Return a pointer to the removed entry */ + return (_nas_timer_db.tq[id].entry); +} + +static int _nas_timer_db_remove(timer_queue_t* entry) +{ + /* Update the pointer from the previous entry */ + /* prev ---> entry ---> next */ + /* prev <--- entry <--- next */ + if (entry->next != NULL) { + /* prev ---> entry ---> next */ + /* prev <-------------- next */ + entry->next->prev = entry->prev; + } + /* Update the pointer from the next entry */ + if (entry->prev != NULL) { + /* prev --------------> next */ + /* prev <-------------- next */ + entry->prev->next = entry->next; + } + else { + /* The entry was the first entry of the list */ + _nas_timer_db.head = entry->next; + if (_nas_timer_db.head != NULL) { + /* Other timers are scheduled to expire */ + return TRUE; + } + /* No more timer is scheduled to expire; stop the system timer */ + struct itimerval it; + it.it_interval.tv_sec = it.it_interval.tv_usec = 0; + it.it_value.tv_sec = it.it_value.tv_usec = 0; + setitimer(ITIMER_REAL, &it, 0); + return FALSE; + } + /* The entry was NOT the first entry of the list */ + return FALSE; +} + +/* + * ----------------------------------------------------------------------------- + * Operator functions for timeval structures + * ----------------------------------------------------------------------------- + */ +/**************************************************************************** + ** ** + ** Name: _nas_timer_cmp() ** + ** ** + ** Description: Performs timeval comparaison ** + ** ** + ** Inputs: a: The first timeval structure ** + ** b: The second timeval structure ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: -1 if a < b; 1 if a > b; 0 if a == b ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_timer_cmp(const struct timeval* a, const struct timeval* b) +{ + if (a->tv_sec < b->tv_sec) + return -1; + else if (a->tv_sec > b->tv_sec) + return 1; + else if (a->tv_usec < b->tv_usec) + return -1; + else if (a->tv_usec > b->tv_usec) + return 1; + return 0; +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_add() ** + ** ** + ** Description: Performs timeval addition ** + ** ** + ** Inputs: a: The first timeval structure ** + ** b: The second timeval structure ** + ** Others: None ** + ** ** + ** Outputs: result: result = timeval(a + b) ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +static void _nas_timer_add(const struct timeval* a, const struct timeval* b, + struct timeval* result) +{ + result->tv_sec = a->tv_sec + b->tv_sec; + result->tv_usec = a->tv_usec + b->tv_usec; + if (result->tv_usec > 1000000) { + result->tv_sec++; + result->tv_usec -= 1000000; + } +} + +/**************************************************************************** + ** ** + ** Name: _nas_timer_sub() ** + ** ** + ** Description: Performs timeval substraction ** + ** ** + ** Inputs: a: The first timeval structure ** + ** b: The second timeval structure ** + ** Others: None ** + ** ** + ** Outputs: result: a >= b, result = timeval(a - b) ** + ** Return: -1 if a < b; 0 otherwise ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _nas_timer_sub(const struct timeval* a, const struct timeval* b, + struct timeval* result) +{ + if (_nas_timer_cmp(a,b) > 0 ) { + result->tv_sec = a->tv_sec - b->tv_sec; + result->tv_usec = a->tv_usec - b->tv_usec; + if (result->tv_usec < 0) { + result->tv_sec--; + result->tv_usec += 1000000; + } + return 0; + } + return -1; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.h b/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.h new file mode 100644 index 0000000000..6ff227a80c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/nas_timer.h @@ -0,0 +1,66 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source timer.h + +Version 0.1 + +Date 2012/11/22 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Timer utilities + +*****************************************************************************/ +#ifndef __NAS_TIMER_H__ +#define __NAS_TIMER_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Timer identifier returned when in inactive state (timer is stopped or has + * failed to be started) + */ +#define NAS_TIMER_INACTIVE_ID (-1) + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* Timer structure */ +struct nas_timer_t { + int id; /* The timer identifier */ + long sec; /* The timer interval value in seconds */ +}; + +/* Type of the callback executed when the timer expired */ +typedef void* (*nas_timer_callback_t)(void*); + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#if defined(NAS_MME) && defined(EPC_BUILD) +# define nas_timer_init +# define nas_timer_start +# define nas_timer_stop +# define nas_timer_restart +#else +int nas_timer_init(void); +int nas_timer_start(long sec, nas_timer_callback_t cb, void* args); +int nas_timer_stop(int id); +int nas_timer_restart(int id); +#endif + +#endif /* __NAS_TIMER_H__ */ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/parser.c b/openair-cn/NAS/EURECOM-NAS/src/util/parser.c new file mode 100644 index 0000000000..3d8180360c --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/parser.c @@ -0,0 +1,158 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source parser.c + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Usefull command line parser + +*****************************************************************************/ + +#include "parser.h" +#include "commonDef.h" + +#include <stdio.h> // fprintf +#include <string.h> // strcmp, strncpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: parser_print_usage() ** + ** ** + ** Description: Displays command line usage ** + ** ** + ** Inputs: command_line: Pointer to the command line structure ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void parser_print_usage(const parser_command_line_t* command_line) +{ + fprintf(stderr, "Usage: %s", command_line->name); + for (int i=0; i < command_line->nb_options; i++) { + fprintf(stderr, " [%s %s]", + command_line->options[i].name, + command_line->options[i].argument); + } + fprintf(stderr, "\n"); + for (int i=0; i < command_line->nb_options; i++) { + fprintf(stderr, "\t%s\t%s\t(%s)\n", + command_line->options[i].argument, + command_line->options[i].usage, + command_line->options[i].value); + } +} + +/**************************************************************************** + ** ** + ** Name: parser_get_options() ** + ** ** + ** Description: Parses the command line options ** + ** ** + ** Inputs: argc: Number of command line options ** + ** argv: Pointer to the command line ** + ** command_line: Pointer to the command line structure ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** command_line: Pointer to the command line structure ** + ** Others: None ** + ** ** + ***************************************************************************/ +int parser_get_options(int argc, const char** argv, + parser_command_line_t* command_line) +{ + int argument_not_found, option_not_found = 1; + int option_length; + + /* Initialize command line structure */ + strncpy(command_line->name, argv[0], PARSER_COMMAND_NAME_SIZE); + for (int i=0; i < command_line->nb_options; i++) { + if ( strcmp(command_line->options[i].value, "NULL") ) { + command_line->options[i].pvalue = command_line->options[i].value; + } + } + + /* No command line options */ + if (argc == 1) { + return RETURNok; + } + + /* Parse the command line looking for options */ + while (*++argv && **argv == '-') + { + argument_not_found = 1; + option_not_found = 1; + for (int i=0; i < command_line->nb_options; i++) + { + if ( !strcmp(command_line->options[i].name, *argv) ) + { + option_not_found = 0; + if (argv[1] && *argv[1] != '-') { + argument_not_found = 0; + option_length = (int) strlen(*++argv); + if (option_length >= PARSER_OPTION_VALUE_SIZE) { + fprintf(stderr, "%s: option name too long (%d), should be less than %d characters\n", + *argv, option_length, + PARSER_OPTION_VALUE_SIZE); + return RETURNerror; + } + strcpy(command_line->options[i].value, *argv); + if (command_line->options[i].pvalue == NULL) { + command_line->options[i].pvalue = + command_line->options[i].value; + } + } + break; + } + } + if (option_not_found) { + if ( strcmp(*argv, "-?") && strcmp(*argv, "-h") && + strcmp(*argv, "-help") && strcmp(*argv, "--help") ) + { + fprintf(stderr, "%s: illegal option %s\n", + command_line->name, *argv); + return RETURNerror; + } + } + else if (argument_not_found) { + fprintf(stderr, "%s: option %s requires an argument\n", + command_line->name, *argv); + return RETURNerror; + } + } + + if (option_not_found) + { + return RETURNerror; + } + + return RETURNok; +} +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/parser.h b/openair-cn/NAS/EURECOM-NAS/src/util/parser.h new file mode 100644 index 0000000000..bf30453099 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/parser.h @@ -0,0 +1,73 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source parser.h + +Version 0.1 + +Date 2012/02/27 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Usefull command line parser + +*****************************************************************************/ +#ifndef __PARSER_H__ +#define __PARSER_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* ----------- + * Option type + * ----------- + * An option is defined with a name, an argument following the option's + * name, the usage message and a value + */ +typedef struct +{ + const char* name; /* Option name */ + const char* argument; /* Argument following the option */ + const char* usage; /* Option and Argument usage */ +#define PARSER_OPTION_VALUE_SIZE 32 + char value[PARSER_OPTION_VALUE_SIZE]; /* Option value */ + char* pvalue; +} parser_option_t; + +/* ----------------- + * Command line type + * ----------------- + * An command line is defined with a name, the number of options and the + * list of command's options + */ +typedef struct +{ +#define PARSER_COMMAND_NAME_SIZE 32 + char name[PARSER_COMMAND_NAME_SIZE]; /* Command name */ + const int nb_options; /* Number of options */ + parser_option_t options[]; /* Command line options */ +} parser_command_line_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void parser_print_usage(const parser_command_line_t* commamd_line); +int parser_get_options(int argc, const char** argv, + parser_command_line_t* commamd_line); + +#endif /* __PARSER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/socket.c b/openair-cn/NAS/EURECOM-NAS/src/util/socket.c new file mode 100644 index 0000000000..12941ea8b5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/socket.c @@ -0,0 +1,425 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + + Source socket.c + + Version 0.1 + + Date 2012/02/28 + + Product NAS stack + + Subsystem Utilities + + Author Frederic Maurel + + Description Implements socket handlers + + *****************************************************************************/ + +#include "socket.h" +#include "commonDef.h" + +#include <stdlib.h> // malloc, free, atoi +#include <string.h> // memset +#include <unistd.h> // close +#include <errno.h> // EINTR +#include <sys/types.h> +#include <sys/socket.h> // socket, setsockopt, connect, bind, recv, send +#include <netdb.h> // getaddrinfo +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* ------------------------------------- + * Identifier of network socket endpoint + * ------------------------------------- + * A network socket endpoint is defined with a type (client or server), + * a port number, and the name and address of the remote host it should + * be connected to. A socket file descriptor is created to handle the + * setup of the communication channel with the remote peer. + */ +struct socket_id_s +{ + int type; /* connection type (client/server) */ + int port; /* port number */ +#define SOCKET_HOSTNAME_SIZE 32 + char rhost[SOCKET_HOSTNAME_SIZE]; /* remote hostname */ + struct sockaddr_storage addr; /* remote address */ + int fd; /* socket file descriptor */ +}; + +/* Set socket option at the sockets API level (SOL_SOCKET) */ +static int _socket_set_option(int sfd); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: socket_udp_open() ** + ** ** + ** Description: Initializes a communication endpoint for any IPv4 and ** + ** IPv6 protocol used by a local host to send/receive UDP ** + ** datagrams to/from a remote host in "connected" mode of ** + ** operation. ** + ** ** + ** Inputs: type: Type of the connection (client/server) ** + ** host: For client application, the remote host- ** + ** name, or numerical IPv4 or IPv6 network ** + ** address to connect to. NULL for server ** + ** application. ** + ** port: The port number ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: A pointer to the local endpoint identifier ** + ** that has been allocated for communication ** + ** with the remote peer. NULL if the setup of ** + ** the communication endpoint failed. ** + ** Others: None ** + ** ** + ***************************************************************************/ +void* socket_udp_open(int type, const char* host, const char* port) +{ + struct addrinfo socket_info; /* endpoint information */ + struct addrinfo *socket_addr, *sp; /* endpoint address */ + int sfd; /* socket file descriptor */ + + /* + * Parameters sanity check + * ----------------------- + * The local connection endpoint shall be of type CLIENT or SERVER + */ + if (host == NULL) + { + type = SOCKET_SERVER; + } + else + if (type != SOCKET_CLIENT && type != SOCKET_SERVER) + { + return NULL; + } + + /* + * Initialize the endpoint address information + * ------------------------------------------- + * The AI_PASSIVE flag allows "wildcard address" when hostname is not + * provided (NULL). The wildcard address is used by applications (ty- + * pically servers) that intend to accept connections on any of the + * hosts's network addresses. If the hostname is not NULL, then the + * AI_PASSIVE flag is ignored. + * When the AI_V4MAPPED flag is set, and AF_INET6 is specified, and no + * matching IPv6 addresses could be found, then IPv4-mapped IPv6 addresses + * are returned by getaddrinfo in the list pointed to by result. + */ + memset (&socket_info, 0, sizeof(struct addrinfo)); + socket_info.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + socket_info.ai_flags = AI_NUMERICSERV; /* numeric port number */ + if (type != SOCKET_CLIENT) + { + /* Setup socket address options at the server side */ + socket_info.ai_family = AF_INET6; /* Accept either IPv4 or IPv6 + * connections */ + socket_info.ai_flags |= AI_PASSIVE; /* Use "wildcard address" */ + socket_info.ai_flags |= AI_V4MAPPED; /* IPv4-mapped IPv6 address */ + } + else + { + /* Setup socket address options at the client side */ + socket_info.ai_family = AF_UNSPEC; /* Any address family */ + } + + /* + * getaddrinfo() returns a linked list of address structures: + * - The network host may be multi-homed, accessible over multiple + * protocols (e.g. both AF_INET and AF_INET6); + * - The same service (port number) may be available from multiple + * socket types (one SOCK_STREAM address and another SOCK_DGRAM address); + */ + int rc = getaddrinfo (host, port, &socket_info, &socket_addr); + if (rc != 0) + { + if (rc != EAI_SYSTEM) + { + errno = rc; + } + return NULL; + } + + /* + * Try each address until we successfully connect + */ + for (sp = socket_addr; sp != NULL; sp = sp->ai_next) + { + /* Create the socket endpoint for communication */ + sfd = socket (sp->ai_family, sp->ai_socktype, sp->ai_protocol); + if (sfd < 0) + { + continue; + } + + /* + * Initiate a communication channel at the CLIENT side + */ + if (type == SOCKET_CLIENT) + { + /* Connect the socket to the remote server's address */ + if (connect (sfd, sp->ai_addr, sp->ai_addrlen) != -1) + { + break; /* Connection succeed */ + } + } + + /* + * Initiate a communication channel at the SERVER side + */ + else + if (type == SOCKET_SERVER) + { + /* Set socket options */ + if (_socket_set_option (sfd) != RETURNok) + { + continue; + } + /* Bind the socket to the local server's address */ + if (bind (sfd, sp->ai_addr, sp->ai_addrlen) != -1) + { + break; /* Bind succeed */ + } + } + + close (sfd); + } + + /* Free the memory that was dynamically allocated for the linked list */ + freeaddrinfo (socket_addr); + + if (sp == NULL) + { + /* Connect or bind failed */ + return NULL; + } + + /* The connection endpoint has been successfully setup */ + socket_id_t * sid = (socket_id_t *) malloc (sizeof(struct socket_id_s)); + if (sid != NULL) + { + sid->type = type; + sid->port = atoi (port); + sid->fd = sfd; + } + return sid; +} + +/**************************************************************************** + ** ** + ** Name: socket_close() ** + ** ** + ** Description: Cleanup the specified communication endpoint: Close the ** + ** socket file descriptor and frees all the memory space ** + ** allocated to handle the communication channel towards the ** + ** remote peer ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: id: The identifier of the connection endpoint ** + ** Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void socket_close(void* id) +{ + if (id) + { + close (((socket_id_t*) id)->fd); + free (id); + } +} + +/**************************************************************************** + ** ** + ** Name: socket_recv() ** + ** ** + ** Description: Receives data from a given communication endpoint to a ** + ** receive buffer of specified length ** + ** ** + ** Inputs: id: The identifier of the connection endpoint ** + ** length: Length of the receive buffer ** + ** Others: None ** + ** ** + ** Outputs: id: The identifier of the connection endpoint ** + ** buffer: The receive buffer ** + ** Return: The number of bytes received when success; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +ssize_t socket_recv(void* id, char* buffer, size_t length) +{ + socket_id_t* sid = (socket_id_t*) (id); + ssize_t rbytes = -1; + + if (sid->type == SOCKET_CLIENT) + { + /* Receive data from the connected socket */ + rbytes = recv (sid->fd, buffer, length, 0); + } + else + if (sid->type == SOCKET_SERVER) + { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); + + /* Receive data from the socket and retreive the remote host address */ + rbytes = recvfrom (sid->fd, buffer, length, 0, (struct sockaddr *) &addr, &addrlen); + sid->addr = addr; + } + + if (errno == EINTR) + { + /* A signal was caught */ + return 0; + } + else + if (rbytes < 0) + { + /* Receive failed */ + return RETURNerror; + } + return rbytes; +} + +/**************************************************************************** + ** ** + ** Name: socket_send() ** + ** ** + ** Description: Sends data to a given communication endpoint from a send ** + ** buffer of specified length ** + ** ** + ** Inputs: id: The identifier of the connection endpoint ** + ** buffer: The send buffer ** + ** length: Length of the send buffer ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The number of bytes sent when success; ** + ** RETURNerror otherwise. ** + ** Others: None ** + ** ** + ***************************************************************************/ +ssize_t socket_send(const void* id, const char* buffer, size_t length) +{ + const socket_id_t* sid = (socket_id_t*) (id); + ssize_t sbytes = -1; + + if (sid->type == SOCKET_CLIENT) + { + /* Send data to the connected socket */ + sbytes = send (sid->fd, buffer, length, 0); + } + else + if (sid->type == SOCKET_SERVER) + { + /* Send data to the socket using the remote host address */ + sbytes = sendto (sid->fd, buffer, length, 0, (struct sockaddr *) &sid->addr, (socklen_t) sizeof(sid->addr)); + } + + if (errno == EINTR) + { + /* A signal was caught */ + return 0; + } + else + if (sbytes != length) + { + /* Send failed */ + return RETURNerror; + } + return sbytes; +} + +/**************************************************************************** + ** ** + ** Name: socket_get_fd() ** + ** ** + ** Description: Get the value of the socket file descriptor created for ** + ** the given connection endpoint ** + ** ** + ** Inputs: id: The identifier of the connection endpoint ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: The file descriptor of the socket created ** + ** for this connection endpoint ** + ** Others: None ** + ** ** + ***************************************************************************/ +int socket_get_fd(const void* id) +{ + if (id) + { + return ((socket_id_t*) id)->fd; + } + return RETURNerror; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _socket_set_option() ** + ** ** + ** Description: Set socket option at the sockets API level (SOL_SOCKET) ** + ** ** + ** Inputs: sfd: Socket file descriptor ** + ** Others: None ** + ** ** + ** Outputs: None ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _socket_set_option(int sfd) +{ + int optval; + + /* SO_REUSEADDR socket option: + * --------------------------- + * Allows the server to bind a socket to this port, unless + * there is an active listening socket already bound to the + * port. This is useful when recovering from a crash and the + * socket was not properly closed. The server can be restarted + * and it will simply open another socket on the same port and + * continue listening. + */ + optval = TRUE; + if (setsockopt (sfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) + { + return RETURNerror; + } + /* IPV6_V6ONLY socket option + * ------------------------- + * When option is set to TRUE, the socket is restricted to sending and + * receiving IPv6 packets only. + * When option is set to FALSE, the socket can be used to send and receive + * packets to and from an IPv6 address or an IPv4-mapped IPv6 address. + */ + optval = FALSE; + if (setsockopt (sfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0) + { + return RETURNerror; + } + + return RETURNok; +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/socket.h b/openair-cn/NAS/EURECOM-NAS/src/util/socket.h new file mode 100644 index 0000000000..c3da17a4bb --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/socket.h @@ -0,0 +1,56 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source socket.h + +Version 0.1 + +Date 2012/02/28 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Implements TCP socket handlers + +*****************************************************************************/ +#ifndef __SOCKET_H__ +#define __SOCKET_H__ + +#include <sys/types.h> + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* Type of the connection endpoint */ +#define SOCKET_CLIENT 1 +#define SOCKET_SERVER 2 + +/* Hidden structure that handles the connection endpoint data */ +typedef struct socket_id_s socket_id_t; + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void* socket_udp_open(int type, const char* host, const char* port); +int socket_get_fd(const void* id); + +ssize_t socket_recv(void* id, char* buffer, size_t length); +ssize_t socket_send(const void* id, const char* buffer, size_t length); + +void socket_close(void* id); + +#endif /* __SOCKET_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/stty.c b/openair-cn/NAS/EURECOM-NAS/src/util/stty.c new file mode 100644 index 0000000000..a1051bcb73 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/stty.c @@ -0,0 +1,309 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source stty.c + +Version 0.1 + +Date 2012/11/29 + +Product NAS stack + +Subsystem Utilities + +Author Frederic Maurel + +Description Terminal I/O device control setup + +*****************************************************************************/ + +#include "commonDef.h" + +#include <termios.h> // tcgetattr, tcsetattr +#include <unistd.h> +#include <string.h> // strdup, strtok, strcmp +#include <stdlib.h> // free + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Terminal I/O setting flags */ +#define CFLG 0 /* control modes */ +#define IFLG 1 /* input modes */ +#define OFLG 2 /* output modes */ +#define LFLG 3 /* local modes */ +#define RFLG 4 /* control chars */ +#define BFLG 5 /* baud speed modes */ + +/* Terminal I/O setting parameters */ +typedef struct sttyset_s { + char *name; + int which; + int mask; + int value; +} sttyset_t; + +/* Table of terminal I/O parameters */ +static sttyset_t stty_params[] = { + { "0", BFLG, 0, B0 }, + { "50", BFLG, 0, B50 }, + { "75", BFLG, 0, B75 }, + { "110", BFLG, 0, B110 }, + { "134", BFLG, 0, B134 }, + { "150", BFLG, 0, B150 }, + { "200", BFLG, 0, B200 }, + { "300", BFLG, 0, B300 }, + { "600", BFLG, 0, B600 }, + { "1200", BFLG, 0, B1200 }, + { "1800", BFLG, 0, B1800 }, + { "2400", BFLG, 0, B2400 }, + { "4800", BFLG, 0, B4800 }, + { "9600", BFLG, 0, B9600 }, + { "19200", BFLG, 0, B19200 }, + { "38400", BFLG, 0, B38400 }, +#ifdef B57600 + { "57600", BFLG, 0, B57600 }, +#endif +#ifdef B115200 + { "115200", BFLG, 0, B115200 }, +#endif +#ifdef B230400 + { "230400", BFLG, 0, B230400 }, +#endif + { "cs7", CFLG, CSIZE, CS7 }, + { "cs8", CFLG, CSIZE, CS8 }, + { "cstopb", CFLG, CSTOPB, CSTOPB }, + { "cread", CFLG, CREAD, CREAD }, + { "parenb", CFLG, PARENB, PARENB }, + { "parodd", CFLG, PARODD, PARODD }, + { "hubcl", CFLG, HUPCL, HUPCL }, + { "clocal", CFLG, CLOCAL, CLOCAL }, +#ifdef CRTSCTS + { "crtscts",CFLG, CRTSCTS, CRTSCTS }, +#endif +#ifdef ORTSFL + { "ortsfl", CFLG, ORTSFL, ORTSFL }, +#endif +#ifdef CTSFLOW + { "ctsflow",CFLG, CTSFLOW, CTSFLOW }, +#endif +#ifdef RTSFLOW + { "rtsflow",CFLG, RTSFLOW, RTSFLOW }, +#endif + { "ignbrk", IFLG, IGNBRK, IGNBRK }, + { "brkint", IFLG, BRKINT, BRKINT }, + { "ignpar", IFLG, IGNPAR, IGNPAR }, + { "parmrk", IFLG, PARMRK, PARMRK }, + { "inpck", IFLG, INPCK, INPCK }, + { "istrip", IFLG, ISTRIP, ISTRIP }, + { "inlcr", IFLG, INLCR, INLCR }, + { "igncr", IFLG, IGNCR, IGNCR }, + { "icrnl", IFLG, ICRNL, ICRNL }, +#ifdef IUCLC // Missing on OSX, FreeBSD + { "iuclc", IFLG, IUCLC, IUCLC }, +#endif + { "ixon", IFLG, IXON, IXON }, + { "ixany", IFLG, IXANY, IXANY }, + { "ixoff", IFLG, IXOFF, IXOFF }, +#ifdef IMAXBEL + { "imaxbel",IFLG, IMAXBEL, IMAXBEL }, +#endif + { "opost", OFLG, OPOST, OPOST }, +#ifdef ILCUC // Missing on OSX, FreeBSD + { "olcuc", OFLG, OLCUC, OLCUC }, +#endif + { "onlcr", OFLG, ONLCR, ONLCR }, + { "ocrnl", OFLG, OCRNL, OCRNL }, + { "onocr", OFLG, ONOCR, ONOCR }, + { "onlret", OFLG, ONLRET, ONLRET }, + { "ofil", OFLG, OFILL, OFILL }, + { "ofdel", OFLG, OFDEL, OFDEL }, + { "nl0", OFLG, NLDLY, NL0 }, + { "nl1", OFLG, NLDLY, NL1 }, + { "cr0", OFLG, CRDLY, CR0 }, + { "cr1", OFLG, CRDLY, CR1 }, + { "cr2", OFLG, CRDLY, CR2 }, + { "cr3", OFLG, CRDLY, CR3 }, + { "tab0", OFLG, TABDLY, TAB0 }, + { "tab1", OFLG, TABDLY, TAB1 }, + { "tab2", OFLG, TABDLY, TAB2 }, + { "tab3", OFLG, TABDLY, TAB3 }, + { "bs0", OFLG, BSDLY, BS0 }, + { "bs1", OFLG, BSDLY, BS1 }, + { "vt0", OFLG, VTDLY, VT0 }, + { "vt1", OFLG, VTDLY, VT1 }, + { "ff0", OFLG, FFDLY, FF0 }, + { "ff1", OFLG, FFDLY, FF1 }, + { "isig", LFLG, ISIG, ISIG }, + { "icanon", LFLG, ICANON, ICANON }, +#ifdef XCASE // Missing on OSX, FreeBSD + { "xcase", LFLG, XCASE, XCASE }, +#endif + { "echo", LFLG, ECHO, ECHO }, + { "echoe", LFLG, ECHOE, ECHOE }, + { "echok", LFLG, ECHOK, ECHOK }, + { "echonl", LFLG, ECHONL, ECHONL }, + { "noflsh", LFLG, NOFLSH, NOFLSH }, + { "tostop", LFLG, TOSTOP, TOSTOP }, +#ifdef ECHOCTL + { "echoctl",LFLG, ECHOCTL, ECHOCTL }, +#endif +#ifdef ECHOPRT + { "echoprt",LFLG, ECHOPRT, ECHOPRT }, +#endif +#ifdef ECHOKE + { "echoke", LFLG, ECHOKE, ECHOKE }, +#endif +#ifdef FLUSHO + { "flusho", LFLG, FLUSHO, FLUSHO }, +#endif +#ifdef PENDIN + { "pendin", LFLG, PENDIN, PENDIN }, +#endif + { "iexten", LFLG, IEXTEN, IEXTEN }, +#ifdef TOSTOP + { "tostop", LFLG, TOSTOP, TOSTOP }, +#endif + { "raw", RFLG, 0, 0 }, + { NULL, 0, 0, 0 } +}; + +static int _stty_set_this(struct termios *term, const sttyset_t *p, int turnon); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: stty_set() ** + ** ** + ** Description: Set the parameters associated with the terminal referred ** + ** by the given descriptor ** + ** ** + ** Inputs: p: The TTY parameters ** + ** turnon: Indicate whether the parameter should be ** + ** turned on (TRUE) or turned off (FALSE) ** + ** Others: None ** + ** ** + ** Outputs: term: The termios structure to fill ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +int stty_set(int fd, const char *params) +{ + int rc = RETURNok; + + register char *p; + register char *s; + struct termios term; + register int i; + int mode; + + /* Get current tty attributes */ + if ( tcgetattr(fd, &term) < 0 ) { + return RETURNerror; + } + + s = strdup(params); + p = strtok(s," \t\n"); + while (p && (rc != RETURNerror)) { + mode = 1; + if ( *p == '-' ) { + mode = 0; + p++; + } + for ( i=0; stty_params[i].name; i++ ) { + if ( !strcmp(p, stty_params[i].name) ) { + rc = _stty_set_this(&term, &stty_params[i], mode); + break; + } + } + p = strtok(NULL," \t\n"); + } + free(s); + + /* Apply new tty settings immediatly */ + if (rc != RETURNerror) { + if ( tcsetattr(fd, TCSANOW, &term) < 0 ) { + rc = RETURNerror; + } + } + return (rc); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: _stty_set_this() ** + ** ** + ** Description: Fills the termios structure with the given TTY parameters ** + ** ** + ** Inputs: p: The TTY parameters ** + ** turnon: Indicate whether the parameter should be ** + ** turned on (TRUE) or turned off (FALSE) ** + ** Others: None ** + ** ** + ** Outputs: term: The termios structure to fill ** + ** Return: RETURNok, RETURNerror ** + ** Others: None ** + ** ** + ***************************************************************************/ +static int _stty_set_this(struct termios *term, const sttyset_t *p, int turnon) +{ + int rc = RETURNok; + + switch ( p->which ) + { + case CFLG: + term->c_cflag &= ~(p->mask); + if ( turnon ) + term->c_cflag |= p->value; + break; + case IFLG: + term->c_iflag &= ~(p->mask); + if ( turnon ) + term->c_iflag |= p->value; + break; + case OFLG: + term->c_oflag &= ~(p->mask); + if ( turnon ) + term->c_oflag |= p->value; + break; + case LFLG: + term->c_lflag &= ~(p->mask); + if ( turnon ) + term->c_lflag |= p->value; + break; + case RFLG: + term->c_iflag = 0; + term->c_oflag = 0; + term->c_lflag = 0; + term->c_cc[VMIN] = 1; + term->c_cc[VTIME] = 0; + break; + case BFLG: + if (cfsetispeed(term, p->value) < 0) { + rc = RETURNerror; + } + else if (cfsetospeed(term, p->value) < 0) { + rc = RETURNerror; + } + break; + default: + rc = RETURNerror; + } + + return (rc); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/tst/Makefile b/openair-cn/NAS/EURECOM-NAS/src/util/tst/Makefile new file mode 100644 index 0000000000..b055e2c7b4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/tst/Makefile @@ -0,0 +1,35 @@ +ifndef PROJDIR +PROJDIR = $(PWD)/../../.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +LIBS = -lutil +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) + +LIBSUTIL = $(LIBDIR)/$(LIBUTIL).a $(LIBDIR)/$(LIBUTIL).so + +TIMER_OBJ = timer.o + +TIMER_TARGET = timer + +TARGETS = $(TIMER_TARGET) + +all: $(TARGETS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(TIMER_TARGET): $(TIMER_OBJ) $(LIBSUTIL) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(OBJS) $(TARGETS) *.bak *~ + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +timer.o: $(UTILDIR)/timer.h $(INCDIR)/commonDef.h diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer.c b/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer.c new file mode 100644 index 0000000000..1387e33597 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer.c @@ -0,0 +1,218 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source timer.c + +Version 0.1 + +Date 2012/11/27 + +Product Test + +Subsystem Timer utility main test + +Author Frederic Maurel + +Description Tests the timer utility functions + +*****************************************************************************/ + +#include "nas_timer.h" +#include "commonDef.h" + +#include <pthread.h> +#include <stdio.h> // printf +#include <stdlib.h> // exit +#include <time.h> // clock_gettime +#include <poll.h> // poll + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#define TIMER_1S 1 /* 1 second */ +#define TIMER_2S 2 /* 2 seconds */ +#define TIMER_3S 3 /* 3 seconds */ +#define TIMER_4S 4 /* 4 seconds */ + +typedef struct { + unsigned int id; + unsigned int sec; + struct timespec start; +} _timer_t; + +static void* _timer_callback(void* args); +static void* _timer_callback_joinable(void* args); + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; + +static unsigned int _nb_timers = 0; +static int _start(_timer_t* timer, unsigned int sec); +static int _stop(_timer_t* timer); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int main (int argc, const char* argv[]) +{ + int rc; + _timer_t timer1, timer2, timer3, timer4; + +#define NB_TIMERS_MAX 10 + _timer_t timer[NB_TIMERS_MAX]; + + /* Initialize timer utility */ + rc = timer_init(); + if (rc == RETURNerror) { + printf("ERROR: timer_init() failed\n"); + exit (EXIT_FAILURE); + } + + /* Start NB_TIMERS_MAX timers to expire at time interval of 1s */ + for (int i=0; i < NB_TIMERS_MAX; i++) { + if (_start(&timer[i], i) != RETURNok) { + printf("ERROR: timer_start(i=%u) failed\n", i); + } + } + + /* Start timer 1 to expire in 1s */ + if (_start(&timer1, TIMER_1S) != RETURNok) { + printf("ERROR: timer_start() failed\n"); + } + + /* Start timer 2 to expire in 3s */ + if (_start(&timer2, TIMER_3S) != RETURNok) { + printf("ERROR: timer_start() failed\n"); + } + + /* Start timer 3 to expire in 2s */ + if (_start(&timer3, TIMER_2S) != RETURNok) { + printf("ERROR: timer_start() failed\n"); + } + + /* Stop timer 1 */ + if (_stop(&timer1) != RETURNok) { + printf("ERROR: timer_stop(id=%u) failed\n", timer3.id); + } + + /* Wait for the first timer to expire */ + poll(0, 0, -1); + + /* Start timer 4 to expire in 4s */ + if (_start(&timer4, TIMER_4S) != RETURNok) { + printf("ERROR: timer_start() failed\n"); + } + + /* Wait for all timers to expire */ + while (_nb_timers > 0) { + poll(0, 0, 10000); + } + + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +static int _timespec_sub(struct timespec* a, struct timespec* b, struct timespec* result) +{ + if (a->tv_sec < b->tv_sec) return -1; + else if (a->tv_nsec < b->tv_nsec) return -1; + + result->tv_sec = a->tv_sec - b->tv_sec; + result->tv_nsec = a->tv_nsec - b->tv_nsec; + if (result->tv_nsec < 0) { + result->tv_sec--; + result->tv_nsec += 1000000000; + } + return 0; +} + +static void* _timer_callback(void* args) +{ + _timer_t* timer = (_timer_t*) args; + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + + if (_timespec_sub(&ts, &timer->start, &ts) < 0) { + printf("ERROR:_timespec_sub() failed: %ld.%.9ld > %ld.%.9ld\n", + timer->start.tv_sec, timer->start.tv_nsec, + ts.tv_sec, ts.tv_nsec); + } + else { + printf("%s\t: Timer %u expired after %ld.%.9ld seconds (%u s)\n", + __FUNCTION__, timer->id, ts.tv_sec, ts.tv_nsec, timer->sec); + timer->id = timer_stop(timer->id); + pthread_mutex_lock(&_mutex); + _nb_timers -= 1; + pthread_mutex_unlock(&_mutex); + } + + return NULL; +} + +static void* _timer_callback_joinable(void* args) +{ + _timer_t* timer = (_timer_t*) args; + struct timespec ts; + int* rc = (int*)malloc(sizeof(int)); + + clock_gettime(CLOCK_MONOTONIC, &ts); + + if (_timespec_sub(&ts, &timer->start, &ts) < 0) { + printf("ERROR:_timespec_sub() failed: %ld.%.9ld > %ld.%.9ld\n", + timer->start.tv_sec, timer->start.tv_nsec, + ts.tv_sec, ts.tv_nsec); + *rc = RETURNerror; + } + else { + printf("%s\t: Timer %u expired after %ld.%.9ld seconds (%u s)\n", + __FUNCTION__, timer->id, ts.tv_sec, ts.tv_nsec, timer->sec); + timer->id = timer_stop(timer->id); + pthread_mutex_lock(&_mutex); + _nb_timers -= 1; + pthread_mutex_unlock(&_mutex); + *rc = timer->id; + } + + return rc; +} + +static int _start(_timer_t* timer, unsigned int sec) +{ + int rc = RETURNerror; + + timer->sec = sec; + clock_gettime(CLOCK_MONOTONIC, &timer->start); + timer->id = timer_start(timer->sec, _timer_callback_joinable, + (void*) timer); + if (timer->id != TIMER_INACTIVE_ID) { + printf("Timer id=%u scheduled to expire in %u seconds\n", + timer->id, timer->sec); + _nb_timers += 1; + rc = RETURNok; + } + return (rc); +} + +static int _stop(_timer_t* timer) +{ + int rc = RETURNerror; + + printf("Stop timer id=%u\n", timer->id); + timer->id = timer_stop(timer->id); + if (timer->id == TIMER_INACTIVE_ID) { + _nb_timers -= 1; + rc = RETURNok; + } + return (rc); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer_debug.txt b/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer_debug.txt new file mode 100644 index 0000000000..14e6912f7e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/src/util/tst/timer_debug.txt @@ -0,0 +1,101 @@ +Attach.c[168] DEBUG Start timer T3410 (id=-1, time=15) +_timer_db_insert_entry: DEBUG - Restart system timer for id=0, time=15.000000 +timer_start: DEBUG - Timer id=0 started +Attach.c[171] DEBUG Timer T3410 (id=0) started + +Attach.c[173] DEBUG Stop T3402 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[175] DEBUG Timer T3402 (id=-1) stopped + +Attach.c[176] DEBUG Stop T3411 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[178] DEBUG Timer T3411 (id=-1) stopped + +-------------------------------------------------------------------------------- + +Attach.c[219] WARNING T3410 timer expired, attach counter = 0 + +Attach.c[226] DEBUG Start timer T3411 (id=-1, time=10) +timer_start: DEBUG - Timer id=1 started +Attach.c[229] DEBUG Timer T3411 (id=1, time=10) started + +_timer_db_remove_entry: DEBUG - Remove entry id=0 +_timer_db_remove: DEBUG - Remove timer id=0 +_timer_db_remove_entry: DEBUG - Restart system timer for id=1, time=9.999921 + +-------------------------------------------------------------------------------- + +Attach.c[288] WARNING T3411 timer expired + +Attach.c[168] DEBUG Start timer T3410 (id=0, time=15) +timer_start: DEBUG - Timer id=2 started +Attach.c[171] DEBUG Timer T3410 (id=2) started + +Attach.c[173] DEBUG Stop T3402 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[175] DEBUG Timer T3402 (id=-1) stopped + +Attach.c[176] DEBUG Stop T3411 (id=1) +timer_stop: DEBUG - Stop timer id=1 + +_timer_db_remove_entry: DEBUG - Remove entry id=1 +_timer_db_remove: DEBUG - Remove timer id=1 +_timer_db_remove_entry: DEBUG - Restart system timer for id=2, time=14.988820 + +Attach.c[178] DEBUG Timer T3411 (id=1) stopped + +_timer_db_remove_entry: DEBUG - Remove entry id=2 +_timer_db_remove: DEBUG - Remove timer id=2 +_timer_db_remove: DEBUG - Stop system timer + + +-------------------------------------------------------------------------------- + +Attach.c[168] DEBUG Start timer T3410 (id=-1, time=15) +_timer_db_insert_entry: DEBUG - Restart system timer for id=0, time=15.000000 +timer_start: DEBUG - Timer id=0 started +Attach.c[171] DEBUG Timer T3410 (id=0) started + +Attach.c[173] DEBUG Stop T3402 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[175] DEBUG Timer T3402 (id=-1) stopped + +Attach.c[176] DEBUG Stop T3411 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[178] DEBUG Timer T3411 (id=-1) stopped + +-------------------------------------------------------------------------------- + +Attach.c[219] WARNING T3410 timer expired, attach counter = 0 +Attach.c[226] DEBUG Start timer T3411 (id=-1, time=10) +timer_start: DEBUG - Timer id=1 started +Attach.c[229] DEBUG Timer T3411 (id=1, time=10) started + +timer_stop: DEBUG - Stop timer id=0 +_timer_db_remove_entry: DEBUG - Remove entry id=0 +_timer_db_remove: DEBUG - Remove timer id=0 +_timer_db_remove_entry: DEBUG - Restart system timer for id=1, time=9.999934 + +-------------------------------------------------------------------------------- + +Attach.c[288] WARNING T3411 timer expired + +Attach.c[168] DEBUG Start timer T3410 (id=0, time=15) +timer_start: DEBUG - Timer id=2 started +Attach.c[171] DEBUG Timer T3410 (id=2) started + +Attach.c[173] DEBUG Stop T3402 (id=-1) +timer_stop: DEBUG - Stop timer id=-1 +Attach.c[175] DEBUG Timer T3402 (id=-1) stopped + +Attach.c[176] DEBUG Stop T3411 (id=1) +timer_stop: DEBUG - Stop timer id=1 + +timer_stop: DEBUG - Stop timer id=1 +_timer_db_remove_entry: DEBUG - Remove entry id=1 +_timer_db_remove: DEBUG - Remove timer id=1 +_timer_db_remove_entry: DEBUG - Restart system timer for id=2, time=14.999969 +Attach.c[178] DEBUG Timer T3411 (id=1) stopped + +UEprocess: timer.c:519: _timer_db_remove_entry: Assertion `_timer_db.tq[id].id == id' failed. +Aborted diff --git a/openair-cn/NAS/EURECOM-NAS/tools/Makefile b/openair-cn/NAS/EURECOM-NAS/tools/Makefile new file mode 100644 index 0000000000..22ceff99df --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tools/Makefile @@ -0,0 +1,75 @@ +export PROCESS = UE + +ifndef PROJDIR +PROJDIR = $(PWD)/.. +endif + +include $(PROJDIR)/Makerules +include $(PROJDIR)/Makefile.inc + +export LD_RUN_PATH = $(LIBDIR):$(LIBPROCESS) + +LIBS = -lapi -lutil -lEMMmsg -lESMmsg -lies -lrt +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(USIMAPIDIR) -I$(EMMDIR) + +LIBSUTIL = $(LIBDIR)/$(LIBUTIL).a $(LIBDIR)/$(LIBUTIL).so + +USIM_OBJ = usim_data.o +UE_OBJ = ue_data.o + +USIM_TARGET = usim_data +UE_TARGET = ue_data + +TARGETS = $(USIM_TARGET) $(UE_TARGET) + +all: $(TARGETS) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(USIM_TARGET): $(USIM_OBJ) $(LIBSUTIL) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + @echo Replacing $@ to $(BINDIR) + @$(RM) $(BINDIR)/$@ + @$(CP) $@ $(BINDIR) + +$(UE_TARGET): $(UE_OBJ) $(LIBSUTIL) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + @echo Replacing $@ to $(BINDIR) + @$(RM) $(BINDIR)/$@ + @$(CP) $@ $(BINDIR) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGETS) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/userDef.h +ue_data.o: /usr/include/stdint.h /usr/include/features.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/memory.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/emmData.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/securityDef.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +ue_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_timer.h +ue_data.o: /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h +ue_data.o: /usr/include/wchar.h /usr/include/stdlib.h /usr/include/alloca.h +ue_data.o: /usr/include/string.h /usr/include/xlocale.h +usim_data.o: network.h +usim_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +usim_data.o: /usr/include/stdint.h /usr/include/features.h +usim_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +usim_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/usim/usim_api.h +usim_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +usim_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/memory.h +usim_data.o: /usr/include/stdio.h /usr/include/libio.h +usim_data.o: /usr/include/_G_config.h /usr/include/wchar.h +usim_data.o: /usr/include/stdlib.h /usr/include/alloca.h +usim_data.o: /usr/include/string.h /usr/include/xlocale.h diff --git a/openair-cn/NAS/EURECOM-NAS/tools/network.h b/openair-cn/NAS/EURECOM-NAS/tools/network.h new file mode 100644 index 0000000000..5667e29fd7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tools/network.h @@ -0,0 +1,92 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network.h + +Version 0.1 + +Date 2013/03/26 + +Product USIM data generator + +Subsystem PLMN network operators + +Author Frederic Maurel + +Description Defines a list of PLMN network operators + +*****************************************************************************/ +#ifndef __NETWORK_H__ +#define __NETWORK_H__ + +#include "commonDef.h" +#include "networkDef.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +#define SFR_PLMN_1 {0,2,0x0f,8,0,1} // 20810 +#define SFR_PLMN_2 {0,2,0x0f,8,1,1} // 20811 +#define SFR_PLMN_3 {0,2,0x0f,8,3,1} // 20813 +#define VDF_PLMN_1 {2,2,0x0f,2,0,1} // 22210 +#define VDF_PLMN_2 {1,2,0x0f,4,0x0f,1} // 2141 +#define VDF_PLMN_3 {1,2,0x0f,4,0x0f,6} // 2146 +#define VDF_PLMN_4 {6,2,0x0f,2,0x0f,2} // 2622 +#define VDF_PLMN_5 {6,2,0x0f,2,0x0f,4} // 2624 + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/* + * PLMN network operator record index + */ +enum { + SFR1=0, + SFR2, + SFR3, + VDF1, + VDF2, + VDF3, + VDF4, + VDF5 +}; + +/* + * PLMN network operator record + */ +typedef struct { + unsigned int num; + plmn_t plmn; + char fullname[NET_FORMAT_LONG_SIZE + 1]; + char shortname[NET_FORMAT_SHORT_SIZE + 1]; + tac_t tac_start; + tac_t tac_end; +} network_record_t; + + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/* + * The list of PLMN network operator records + */ +network_record_t network_records[] = { + {20810, SFR_PLMN_1, "SFR France", "SFR", 0x0000, 0xfffe}, + {20811, SFR_PLMN_2, "SFR France", "SFR", 0x0000, 0xfffe}, + {20813, SFR_PLMN_3, "SFR France", "SFR", 0x0000, 0xfffe}, + {22210, VDF_PLMN_1, "Vodafone Italia", "VODAFONE", 0x0000, 0xfffe}, + {2141, VDF_PLMN_2, "Vodafone Spain", "VODAFONE", 0x0000, 0xfffe}, + {2146, VDF_PLMN_3, "Vodafone Spain", "VODAFONE", 0x0000, 0xfffe}, + {2622, VDF_PLMN_4, "Vodafone Germ", "VODAFONE", 0x0000, 0xfffe}, + {2624, VDF_PLMN_5, "Vodafone Germ", "VODAFONE", 0x0000, 0xfffe}, +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +#endif /* __NETWORK_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tools/ue_data.c b/openair-cn/NAS/EURECOM-NAS/tools/ue_data.c new file mode 100644 index 0000000000..d595d7f4d5 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tools/ue_data.c @@ -0,0 +1,355 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source ue_data.c + +Version 0.1 + +Date 2012/11/02 + +Product UE data generator + +Subsystem UE data generator main process + +Author Frederic Maurel + +Description Implements the utility used to generate data stored in the + UE's non-volatile memory device + +*****************************************************************************/ + +#include "userDef.h" +#include "memory.h" + +#include "emmData.h" + +#include <stdio.h> // perror, printf, fprintf, snprintf +#include <stdlib.h> // exit, free +#include <string.h> // memset, strncpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#define USER_IMEI "35611302209414" +#define USER_MANUFACTURER "EURECOM" +#define USER_MODEL "LTE Android PC" +//#define USER_MANUFACTURER "SAGEM" +//#define USER_MODEL "my225x" +#define USER_PIN "0000" + +#define PRINT_PLMN_DIGIT(d) if ((d) != 0xf) printf("%u", (d)) + +#define PRINT_PLMN(plmn) \ + PRINT_PLMN_DIGIT((plmn).MCCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit3); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit3) + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static void _display_usage(const char* command); + +static void _gen_user_data(user_nvdata_t* data); +static void _gen_emm_data(emm_nvdata_t* data); + +static int _luhn(const char* cc); +static void _display_ue_data(const user_nvdata_t* data); +static void _display_emm_data(const emm_nvdata_t* data); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int main (int argc, const char* argv[]) +{ + int rc; + char* path; + user_nvdata_t user_data; + emm_nvdata_t emm_data; + + unsigned char gen_data; + + /* + * ---------------------------- + * Read command line parameters + * ---------------------------- + */ + if (argc != 2) { + fprintf(stderr, "Invalid parameter\n"); + _display_usage(argv[0]); + exit(EXIT_FAILURE); + } + else if ( (strcmp(argv[1], "--gen") == 0) || + (strcmp(argv[1], "-g") == 0) ) { + /* Generate UE data files */ + gen_data = TRUE; + } + else if ( (strcmp(argv[1], "--print") == 0) || + (strcmp(argv[1], "-p") == 0) ) { + /* Display content of UE data files */ + gen_data = FALSE; + } + else { + /* Display usage */ + _display_usage(argv[0]); + exit(EXIT_SUCCESS); + } + + /* + * ---------------------- + * UE's non-volatile data + * ---------------------- + */ + path = memory_get_path(USER_NVRAM_DIRNAME, USER_NVRAM_FILENAME); + if (path == NULL) { + perror("ERROR\t: memory_get_path() failed"); + exit(EXIT_FAILURE); + } + + if (gen_data) + { + /* + * Initialize UE's non-volatile data + */ + memset(&user_data, 0, sizeof(user_nvdata_t)); + _gen_user_data(&user_data); + /* + * Write UE's non-volatile data + */ + rc = memory_write(path, &user_data, sizeof(user_nvdata_t)); + if (rc != RETURNok) { + perror("ERROR\t: memory_write() failed"); + free(path); + exit(EXIT_FAILURE); + } + } + /* + * Read UE's non-volatile data + */ + memset(&user_data, 0, sizeof(user_nvdata_t)); + rc = memory_read(path, &user_data, sizeof(user_nvdata_t)); + if (rc != RETURNok) { + perror("ERROR\t: memory_read() failed"); + free(path); + exit(EXIT_FAILURE); + } + free(path); + /* + * Display UE's non-volatile data + */ + printf("\nUE's non-volatile data:\n\n"); + _display_ue_data(&user_data); + + /* + * --------------------- + * EMM non-volatile data + * --------------------- + */ + path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); + if (path == NULL) { + perror("ERROR\t: memory_get_path() failed"); + exit(EXIT_FAILURE); + } + + if (gen_data) + { + /* + * Initialize EMM non-volatile data + */ + memset(&emm_data, 0, sizeof(emm_nvdata_t)); + _gen_emm_data(&emm_data); + /* + * Write EMM non-volatile data + */ + rc = memory_write(path, &emm_data, sizeof(emm_nvdata_t)); + if (rc != RETURNok) { + perror("ERROR\t: memory_write() failed"); + free(path); + exit(EXIT_FAILURE); + } + } + /* + * Read EMM non-volatile data + */ + memset(&emm_data, 0, sizeof(emm_nvdata_t)); + rc = memory_read(path, &emm_data, sizeof(emm_nvdata_t)); + if (rc != RETURNok) { + perror("ERROR\t: memory_read() failed "); + free(path); + exit(EXIT_FAILURE); + } + free(path); + /* + * Display EMM non-volatile data + */ + printf("\nEMM non-volatile data:\n\n"); + _display_emm_data(&emm_data); + + /* + *--------------- + * Files location + *--------------- + */ + path = memory_get_path(USER_NVRAM_DIRNAME, USER_NVRAM_FILENAME); + printf("\nUE identity data file: %s\n", path); + free(path); + path = memory_get_path(EMM_NVRAM_DIRNAME, EMM_NVRAM_FILENAME); + printf("EPS Mobility Management data file: %s\n", path); + free(path); + + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * Displays command line usage + */ +static void _display_usage(const char* command) +{ + fprintf(stderr, "usage: %s [OPTION]\n", command); + fprintf(stderr, "\t[--gen|-g]\tGenerate the UE data files\n"); + fprintf(stderr, "\t[--print|-p]\tDisplay the content of the UE data files\n"); + fprintf(stderr, "\t[--help|-h]\tDisplay this usage\n"); + const char* path = getenv("NVRAM_DIR"); + if (path != NULL) { + fprintf(stderr, "NVRAM_DIR = %s\n", path); + } + else { + fprintf(stderr, "NVRAM_DIR environment variable is not defined\n"); + } +} + +/* + * Generates UE's non-volatile data + */ +static void _gen_user_data(user_nvdata_t* data) +{ + /* + * Product Serial Number Identification + * IMEI = AA-BBBBBB-CCCCCC-D + * AA-BBBBBB: Type Allocation Code (TAC) + * CCCCCC: Serial Number + * D: Luhn check digit + */ + snprintf(data->IMEI, USER_IMEI_SIZE+1, "%s%d", + USER_IMEI, _luhn(USER_IMEI)); + /* + * Manufacturer identifier + */ + strncpy(data->manufacturer, USER_MANUFACTURER, USER_MANUFACTURER_SIZE); + /* + * Model identifier + */ + strncpy(data->model, USER_MODEL, USER_MODEL_SIZE); + /* + * SIM Personal Identification Number + */ + strncpy(data->PIN, USER_PIN, USER_PIN_SIZE); +} + +/* + * Generates UE's non-volatile EMM data + */ +static void _gen_emm_data(emm_nvdata_t* data) +{ + /* + * International Mobile Subscriber Identity + * IMSI = MCC + MNC + MSIN = 208 (France) + 10 (SFR) + 00001234 + */ + data->imsi.length = 8; + data->imsi.u.num.parity = 0b0000; // Type of identity = IMSI, even + data->imsi.u.num.digit1 = 2; // MCC digit 1 + data->imsi.u.num.digit2 = 0; // MCC digit 2 + data->imsi.u.num.digit3 = 8; // MCC digit 3 + data->imsi.u.num.digit4 = 1; // MNC digit 1 + data->imsi.u.num.digit5 = 0; // MNC digit 2 + data->imsi.u.num.digit6 = 0b1111; // MNC digit 3 + data->imsi.u.num.digit7 = 0; + data->imsi.u.num.digit8 = 0; + data->imsi.u.num.digit9 = 0; + data->imsi.u.num.digit10 = 0; + data->imsi.u.num.digit11 = 1; + data->imsi.u.num.digit12 = 2; + data->imsi.u.num.digit13 = 3; + data->imsi.u.num.digit14 = 4; + data->imsi.u.num.digit15 = 0b1111; + /* + * Last registered home PLMN + */ + data->rplmn.MCCdigit1 = 2; + data->rplmn.MCCdigit2 = 0; + data->rplmn.MCCdigit3 = 8; + data->rplmn.MNCdigit1 = 1; + data->rplmn.MNCdigit2 = 0; + data->rplmn.MNCdigit3 = 0xf; + /* + * List of Equivalent PLMNs + */ + data->eplmn.n_plmns = 0; +} + +/* + * Computes the check digit using Luhn algorithm + */ +static int _luhn(const char* cc) +{ + const int m[] = {0,2,4,6,8,1,3,5,7,9}; + int odd = 1, sum = 0; + + for (int i = strlen(cc); i--; odd = !odd) { + int digit = cc[i] - '0'; + sum += odd ? m[digit] : digit; + } + + return 10 - (sum % 10); +} + +/* + * Displays UE's non-volatile data + */ +static void _display_ue_data(const user_nvdata_t* data) +{ + printf("IMEI\t\t= %s\n", data->IMEI); + printf("manufacturer\t= %s\n", data->manufacturer); + printf("model\t\t= %s\n", data->model); + printf("PIN\t\t= %s\n", data->PIN); +} + +/* + * Displays UE's non-volatile EMM data + */ +static void _display_emm_data(const emm_nvdata_t* data) +{ + printf("IMSI\t\t= "); + printf("%u%u%u%u%u%u%u%u%u%u%u%u%u\n", + data->imsi.u.num.digit1, + data->imsi.u.num.digit2, + data->imsi.u.num.digit3, + data->imsi.u.num.digit4, + data->imsi.u.num.digit5, + data->imsi.u.num.digit7, + data->imsi.u.num.digit8, + data->imsi.u.num.digit9, + data->imsi.u.num.digit10, + data->imsi.u.num.digit11, + data->imsi.u.num.digit12, + data->imsi.u.num.digit13, + data->imsi.u.num.digit14); + + printf("RPLMN\t\t= "); PRINT_PLMN(data->rplmn); + printf("\n"); + + for (int i = 0; i < data->eplmn.n_plmns; i++) { + printf("EPLMN[%d]\t= ", i); PRINT_PLMN(data->eplmn.plmn[i]); + printf("\n"); + } +} diff --git a/openair-cn/NAS/EURECOM-NAS/tools/usim_data.c b/openair-cn/NAS/EURECOM-NAS/tools/usim_data.c new file mode 100644 index 0000000000..8db4fb4fee --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tools/usim_data.c @@ -0,0 +1,518 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source usim_data.c + +Version 0.1 + +Date 2012/10/31 + +Product USIM data generator + +Subsystem USIM data generator main process + +Author Frederic Maurel + +Description Implements the utility used to generate data stored in the + USIM application + +*****************************************************************************/ + +#include "network.h" + +#include "usim_api.h" +#include "memory.h" + +#include <stdio.h> // perror, printf +#include <stdlib.h> // exit +#include <string.h> // memset, memcpy, strncpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +#define KSI USIM_KSI_NOT_AVAILABLE +#define KSI_ASME USIM_KSI_NOT_AVAILABLE +#define INT_ALGO USIM_INT_EIA0 +#define ENC_ALGO USIM_ENC_EEA0 +#define SECURITY_ALGORITHMS (ENC_ALGO | INT_ALGO) + +#define MIN_TAC 0x0000 +#define MAX_TAC 0xFFFE + +#define DEFAULT_TMSI 0x0000000D +#define DEFAULT_P_TMSI 0x0000000D +#define DEFAULT_M_TMSI 0x0000000D +#define DEFAULT_LAC 0xFFFE +#define DEFAULT_RAC 0x01 +#define DEFAULT_TAC 0x0001 + +#define DEFAULT_MME_ID 0x0102 +#define DEFAULT_MME_CODE 0x0F + +#define PRINT_PLMN_DIGIT(d) if ((d) != 0xf) printf("%u", (d)) + +#define PRINT_PLMN(plmn) \ + PRINT_PLMN_DIGIT((plmn).MCCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit3); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit3) + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static void _display_usage(const char* command); + +static void _display_usim_data(const usim_data_t* data); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int main (int argc, const char* argv[]) +{ + int rc; + usim_data_t usim_data; + + unsigned char gen_data; + + /* + * Read command line parameters + */ + if (argc != 2) { + fprintf(stderr, "Invalid parameter\n"); + _display_usage(argv[0]); + exit(EXIT_FAILURE); + } + else if ( (strcmp(argv[1], "--gen") == 0) || + (strcmp(argv[1], "-g") == 0) ) { + /* Generate USIM data files */ + gen_data = TRUE; + } + else if ( (strcmp(argv[1], "--print") == 0) || + (strcmp(argv[1], "-p") == 0) ) { + /* Display content of USIM data files */ + gen_data = FALSE; + } + else { + /* Display usage */ + _display_usage(argv[0]); + exit(EXIT_SUCCESS); + } + + if (gen_data) + { + /* + * Initialize USIM data + */ + memset(&usim_data, 0, sizeof(usim_data_t)); + /* + * International Mobile Subscriber Identity + * IMSI = MCC + MNC + MSIN = 208 (France) + 10 (SFR) + 00001234 + */ + usim_data.imsi.length = 8; + usim_data.imsi.u.num.parity = 0b0000; // Type of identity = IMSI, even + usim_data.imsi.u.num.digit1 = 2; // MCC digit 1 + usim_data.imsi.u.num.digit2 = 0; // MCC digit 2 + usim_data.imsi.u.num.digit3 = 8; // MCC digit 3 + usim_data.imsi.u.num.digit4 = 1; // MNC digit 1 + usim_data.imsi.u.num.digit5 = 0; // MNC digit 2 + usim_data.imsi.u.num.digit6 = 0b1111; // MNC digit 3 + usim_data.imsi.u.num.digit7 = 0; + usim_data.imsi.u.num.digit8 = 0; + usim_data.imsi.u.num.digit9 = 0; + usim_data.imsi.u.num.digit10 = 0; + usim_data.imsi.u.num.digit11 = 1; + usim_data.imsi.u.num.digit12 = 2; + usim_data.imsi.u.num.digit13 = 3; + usim_data.imsi.u.num.digit14 = 4; + usim_data.imsi.u.num.digit15 = 0b1111; + /* + * Ciphering and Integrity Keys + */ + usim_data.keys.ksi = KSI; + memset(&usim_data.keys.ck, 0, USIM_CK_SIZE); + memset(&usim_data.keys.ik, 0, USIM_IK_SIZE); + /* + * Higher Priority PLMN search period + */ + usim_data.hpplmn = 0x00; /* Disable timer */ + /* + * List of Forbidden PLMNs + */ + for (int i = 0; i < USIM_FPLMN_MAX; i++) { + memset(&usim_data.fplmn[i], 0xff, sizeof(plmn_t)); + } + /* + * Location Information + */ + usim_data.loci.tmsi = DEFAULT_TMSI; + usim_data.loci.lai.plmn = network_records[SFR1].plmn; + usim_data.loci.lai.lac = DEFAULT_LAC; + usim_data.loci.status = USIM_LOCI_NOT_UPDATED; + /* + * Packet Switched Location Information + */ + usim_data.psloci.p_tmsi = DEFAULT_P_TMSI; + usim_data.psloci.signature[0] = 0x01; + usim_data.psloci.signature[1] = 0x02; + usim_data.psloci.signature[2] = 0x03; + usim_data.psloci.rai.plmn = network_records[SFR1].plmn; + usim_data.psloci.rai.lac = DEFAULT_LAC; + usim_data.psloci.rai.rac = DEFAULT_RAC; + usim_data.psloci.status = USIM_PSLOCI_NOT_UPDATED; + /* + * Administrative Data + */ + usim_data.ad.UE_Operation_Mode = USIM_NORMAL_MODE; + usim_data.ad.Additional_Info = 0xffff; + usim_data.ad.MNC_Length = 2; + /* + * EPS NAS security context + */ + usim_data.securityctx.length = 52; + usim_data.securityctx.KSIasme.type = USIM_KSI_ASME_TAG; + usim_data.securityctx.KSIasme.length = 1; + usim_data.securityctx.KSIasme.value[0] = KSI_ASME; + usim_data.securityctx.Kasme.type = USIM_K_ASME_TAG; + usim_data.securityctx.Kasme.length = USIM_K_ASME_SIZE; + memset(usim_data.securityctx.Kasme.value, 0, + usim_data.securityctx.Kasme.length); + usim_data.securityctx.ulNAScount.type = USIM_UL_NAS_COUNT_TAG; + usim_data.securityctx.ulNAScount.length = USIM_UL_NAS_COUNT_SIZE; + memset(usim_data.securityctx.ulNAScount.value, 0, + usim_data.securityctx.ulNAScount.length); + usim_data.securityctx.dlNAScount.type = USIM_DL_NAS_COUNT_TAG; + usim_data.securityctx.dlNAScount.length = USIM_DL_NAS_COUNT_SIZE; + memset(usim_data.securityctx.dlNAScount.value, 0, + usim_data.securityctx.dlNAScount.length); + usim_data.securityctx.algorithmID.type = USIM_INT_ENC_ALGORITHMS_TAG; + usim_data.securityctx.algorithmID.length = 1; + usim_data.securityctx.algorithmID.value[0] = SECURITY_ALGORITHMS; + /* + * Subcriber's Number + */ + usim_data.msisdn.length = 7; + usim_data.msisdn.number.ext = 1; + usim_data.msisdn.number.ton = MSISDN_TON_UNKNOWKN; + usim_data.msisdn.number.npi = MSISDN_NPI_ISDN_TELEPHONY; + usim_data.msisdn.number.digit[0].msb = + usim_data.msisdn.number.digit[0].msb = 3; + usim_data.msisdn.number.digit[0].lsb = 3; + usim_data.msisdn.number.digit[1].msb = 6; + usim_data.msisdn.number.digit[1].lsb = 1; + usim_data.msisdn.number.digit[2].msb = 1; + usim_data.msisdn.number.digit[2].lsb = 1; + usim_data.msisdn.number.digit[3].msb = 2; + usim_data.msisdn.number.digit[3].lsb = 3; + usim_data.msisdn.number.digit[4].msb = 4; + usim_data.msisdn.number.digit[4].lsb = 5; + usim_data.msisdn.number.digit[5].msb = 6; + usim_data.msisdn.number.digit[5].lsb = 0xf; + usim_data.msisdn.number.digit[6].msb = 0xf; + usim_data.msisdn.number.digit[6].lsb = 0xf; + usim_data.msisdn.number.digit[7].msb = 0xf; + usim_data.msisdn.number.digit[7].lsb = 0xf; + usim_data.msisdn.number.digit[8].msb = 0xf; + usim_data.msisdn.number.digit[8].lsb = 0xf; + usim_data.msisdn.number.digit[9].msb = 0xf; + usim_data.msisdn.number.digit[9].lsb = 0xf; + usim_data.msisdn.conf1_record_id = 0xff; /* Not used */ + usim_data.msisdn.ext1_record_id = 0xff; /* Not used */ + /* + * PLMN Network Name and Operator PLMN List + */ + for (int i = SFR1; i < VDF2; i++) { + network_record_t record = network_records[i]; + usim_data.pnn[i].fullname.type = USIM_PNN_FULLNAME_TAG; + usim_data.pnn[i].fullname.length = strlen(record.fullname); + strncpy((char*)usim_data.pnn[i].fullname.value, record.fullname, + usim_data.pnn[i].fullname.length); + usim_data.pnn[i].shortname.type = USIM_PNN_SHORTNAME_TAG; + usim_data.pnn[i].shortname.length = strlen(record.shortname); + strncpy((char*)usim_data.pnn[i].shortname.value, record.shortname, + usim_data.pnn[i].shortname.length); + usim_data.opl[i].plmn = record.plmn; + usim_data.opl[i].start = record.tac_start; + usim_data.opl[i].end = record.tac_end; + usim_data.opl[i].record_id = i; + } + for (int i = VDF2; i < USIM_OPL_MAX; i++) { + memset(&usim_data.opl[i].plmn, 0xff, sizeof(plmn_t)); + } + + /* + * List of Equivalent HPLMNs + */ + usim_data.ehplmn[0] = network_records[SFR2].plmn; + usim_data.ehplmn[1] = network_records[SFR3].plmn; + /* + * Home PLMN Selector with Access Technology + */ + usim_data.hplmn.plmn = network_records[SFR1].plmn; + usim_data.hplmn.AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + /* + * List of user controlled PLMN selector with Access Technology + */ + for (int i = 0; i < USIM_PLMN_MAX; i++) { + memset(&usim_data.plmn[i], 0xff, sizeof(plmn_t)); + } + /* + * List of operator controlled PLMN selector with Access Technology + */ + usim_data.oplmn[0].plmn = network_records[VDF1].plmn; + usim_data.oplmn[0].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + usim_data.oplmn[1].plmn = network_records[VDF2].plmn; + usim_data.oplmn[1].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + usim_data.oplmn[2].plmn = network_records[VDF3].plmn; + usim_data.oplmn[2].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + usim_data.oplmn[3].plmn = network_records[VDF4].plmn; + usim_data.oplmn[3].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + usim_data.oplmn[4].plmn = network_records[VDF5].plmn; + usim_data.oplmn[4].AcT = (USIM_ACT_GSM | USIM_ACT_UTRAN | USIM_ACT_EUTRAN); + for (int i = 5; i < USIM_OPLMN_MAX; i++) { + memset(&usim_data.oplmn[i], 0xff, sizeof(plmn_t)); + } + /* + * EPS Location Information + */ + usim_data.epsloci.guti.gummei.plmn = network_records[SFR1].plmn; + usim_data.epsloci.guti.gummei.MMEgid = DEFAULT_MME_ID; + usim_data.epsloci.guti.gummei.MMEcode = DEFAULT_MME_CODE; + usim_data.epsloci.guti.m_tmsi = DEFAULT_M_TMSI; + usim_data.epsloci.tai.plmn = usim_data.epsloci.guti.gummei.plmn; + usim_data.epsloci.tai.tac = DEFAULT_TAC; + usim_data.epsloci.status = USIM_EPSLOCI_UPDATED; + /* + * Non-Access Stratum configuration + */ + usim_data.nasconfig.NAS_SignallingPriority.type = USIM_NAS_SIGNALLING_PRIORITY_TAG; + usim_data.nasconfig.NAS_SignallingPriority.length = 1; + usim_data.nasconfig.NAS_SignallingPriority.value[0] = 0x00; + usim_data.nasconfig.NMO_I_Behaviour.type = USIM_NMO_I_BEHAVIOUR_TAG; + usim_data.nasconfig.NMO_I_Behaviour.length = 1; + usim_data.nasconfig.NMO_I_Behaviour.value[0] = 0x00; + usim_data.nasconfig.AttachWithImsi.type = USIM_ATTACH_WITH_IMSI_TAG; + usim_data.nasconfig.AttachWithImsi.length = 1; + usim_data.nasconfig.AttachWithImsi.value[0] = 0x00; + usim_data.nasconfig.MinimumPeriodicSearchTimer.type = USIM_MINIMUM_PERIODIC_SEARCH_TIMER_TAG; + usim_data.nasconfig.MinimumPeriodicSearchTimer.length = 1; + usim_data.nasconfig.MinimumPeriodicSearchTimer.value[0] = 0x00; + usim_data.nasconfig.ExtendedAccessBarring.type = USIM_EXTENDED_ACCESS_BARRING_TAG; + usim_data.nasconfig.ExtendedAccessBarring.length = 1; + usim_data.nasconfig.ExtendedAccessBarring.value[0] = 0x00; + usim_data.nasconfig.Timer_T3245_Behaviour.type = USIM_TIMER_T3245_BEHAVIOUR_TAG; + usim_data.nasconfig.Timer_T3245_Behaviour.length = 1; + usim_data.nasconfig.Timer_T3245_Behaviour.value[0] = 0x00; + + /* + * Write USIM application data + */ + rc = usim_api_write(&usim_data); + if (rc != RETURNok) { + perror("ERROR\t: usim_api_write() failed"); + exit(EXIT_FAILURE); + } + } + + /* + * Read USIM application data + */ + memset(&usim_data, 0, sizeof(usim_data_t)); + rc = usim_api_read(&usim_data); + if (rc != RETURNok) { + perror("ERROR\t: usim_api_read() failed"); + exit(EXIT_FAILURE); + } + + /* + * Display USIM application data + */ + printf("\nUSIM data:\n\n"); + _display_usim_data(&usim_data); + + /* + * Display USIM file location + */ + char* path = memory_get_path("USIM_DIR", ".usim.nvram"); + printf("\nUSIM data file: %s\n", path); + free(path); + + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * Displays command line usage + */ +static void _display_usage(const char* command) +{ + fprintf(stderr, "usage: %s [OPTION]\n", command); + fprintf(stderr, "\t[--gen|-g]\tGenerate the USIM data file\n"); + fprintf(stderr, "\t[--print|-p]\tDisplay the content of the USIM data file\n"); + fprintf(stderr, "\t[--help|-h]\tDisplay this usage\n"); + const char* path = getenv("USIM_DIR"); + if (path != NULL) { + fprintf(stderr, "USIM_DIR = %s\n", path); + } + else { + fprintf(stderr, "USIM_DIR environment variable is not defined\n"); + } +} + +/* + * Displays USIM application data + */ +static void _display_usim_data(const usim_data_t* data) +{ + printf("Administrative Data:\n"); + printf("\tUE_Operation_Mode\t= 0x%.2x\n", data->ad.UE_Operation_Mode); + printf("\tAdditional_Info\t\t= 0x%.4x\n", data->ad.Additional_Info); + printf("\tMNC_Length\t\t= %d\n\n", data->ad.MNC_Length); + + printf("IMSI\t= %u%u%u%u%u%u%u%u%u%u%u%u%u\n\n", + data->imsi.u.num.digit1, + data->imsi.u.num.digit2, + data->imsi.u.num.digit3, + data->imsi.u.num.digit4, + data->imsi.u.num.digit5, + data->imsi.u.num.digit7, + data->imsi.u.num.digit8, + data->imsi.u.num.digit9, + data->imsi.u.num.digit10, + data->imsi.u.num.digit11, + data->imsi.u.num.digit12, + data->imsi.u.num.digit13, + data->imsi.u.num.digit14); + + printf("Ciphering and Integrity Keys:\n"); + printf("\tKSI\t: 0x%.2x\n", data->keys.ksi); + char key[USIM_CK_SIZE+1]; + key[USIM_CK_SIZE] = '\0'; + memcpy(key, data->keys.ck, USIM_CK_SIZE); + printf("\tCK\t: \"%s\"\n", key); + memcpy(key, data->keys.ik, USIM_IK_SIZE); + printf("\tIK\t: \"%s\"\n", key); + + printf("EPS NAS security context:\n"); + printf("\tKSIasme\t: 0x%.2x\n", data->securityctx.KSIasme.value[0]); + char kasme[USIM_K_ASME_SIZE+1]; + kasme[USIM_K_ASME_SIZE] = '\0'; + memcpy(kasme, data->securityctx.Kasme.value, USIM_K_ASME_SIZE); + printf("\tKasme\t: \"%s\"\n", kasme); + printf("\tulNAScount\t: 0x%.8x\n", + *(UInt32_t*)data->securityctx.ulNAScount.value); + printf("\tdlNAScount\t: 0x%.8x\n", + *(UInt32_t*)data->securityctx.dlNAScount.value); + printf("\talgorithmID\t: 0x%.2x\n\n", + data->securityctx.algorithmID.value[0]); + + printf("MSISDN\t= %u%u%u %u%u%u%u %u%u%u%u\n\n", + data->msisdn.number.digit[0].msb, + data->msisdn.number.digit[0].lsb, + data->msisdn.number.digit[1].msb, + data->msisdn.number.digit[1].lsb, + data->msisdn.number.digit[2].msb, + data->msisdn.number.digit[2].lsb, + data->msisdn.number.digit[3].msb, + data->msisdn.number.digit[3].lsb, + data->msisdn.number.digit[4].msb, + data->msisdn.number.digit[4].lsb, + data->msisdn.number.digit[5].msb); + + for (int i = 0; i < USIM_PNN_MAX; i++) { + printf("PNN[%d]\t= {%s, %s}\n", i, + data->pnn[i].fullname.value, data->pnn[i].shortname.value); + } + printf("\n"); + + for (int i = 0; i < USIM_OPL_MAX; i++) { + printf("OPL[%d]\t= ", i); PRINT_PLMN(data->opl[i].plmn); + printf(", TAC = [%.4x - %.4x], record_id = %d\n", + data->opl[i].start, data->opl[i].end, data->opl[i].record_id); + } + printf("\n"); + + printf("HPLMN\t\t= "); PRINT_PLMN(data->hplmn.plmn); + printf(", AcT = 0x%x\n\n", data->hplmn.AcT); + + for (int i = 0; i < USIM_FPLMN_MAX; i++) { + printf("FPLMN[%d]\t= ", i); PRINT_PLMN(data->fplmn[i]); + printf("\n"); + } + printf("\n"); + + for (int i = 0; i < USIM_EHPLMN_MAX; i++) { + printf("EHPLMN[%d]\t= ", i); PRINT_PLMN(data->ehplmn[i]); + printf("\n"); + } + printf("\n"); + + for (int i = 0; i < USIM_PLMN_MAX; i++) { + printf("PLMN[%d]\t\t= ", i); PRINT_PLMN(data->plmn[i].plmn); + printf(", AcTPLMN = 0x%x", data->plmn[i].AcT); + printf("\n"); + } + printf("\n"); + + for (int i = 0; i < USIM_OPLMN_MAX; i++) { + printf("OPLMN[%d]\t= ", i); PRINT_PLMN(data->oplmn[i].plmn); + printf(", AcTPLMN = 0x%x", data->oplmn[i].AcT); + printf("\n"); + } + printf("\n"); + + printf("HPPLMN\t\t= 0x%.2x (%d minutes)\n\n", data->hpplmn, data->hpplmn); + + printf("LOCI:\n"); + printf("\tTMSI = 0x%.4x\n", data->loci.tmsi); + printf("\tLAI\t: PLMN = "); PRINT_PLMN(data->loci.lai.plmn); + printf(", LAC = 0x%.2x\n", data->loci.lai.lac); + printf("\tstatus\t= %d\n\n", data->loci.status); + + printf("PSLOCI:\n"); + printf("\tP-TMSI = 0x%.4x\n", data->psloci.p_tmsi); + printf("\tsignature = 0x%x 0x%x 0x%x\n", + data->psloci.signature[0], + data->psloci.signature[1], + data->psloci.signature[2]); + printf("\tRAI\t: PLMN = "); PRINT_PLMN(data->psloci.rai.plmn); + printf(", LAC = 0x%.2x, RAC = 0x%.1x\n", + data->psloci.rai.lac, data->psloci.rai.rac); + printf("\tstatus\t= %d\n\n", data->psloci.status); + + printf("EPSLOCI:\n"); + printf("\tGUTI\t: GUMMEI\t: (PLMN = "); + PRINT_PLMN(data->epsloci.guti.gummei.plmn); + printf(", MMEgid = 0x%.2x, MMEcode = 0x%.1x)", + data->epsloci.guti.gummei.MMEgid, + data->epsloci.guti.gummei.MMEcode); + printf(", M-TMSI = 0x%.4x\n", data->epsloci.guti.m_tmsi); + printf("\tTAI\t: PLMN = "); + PRINT_PLMN(data->epsloci.tai.plmn); + printf(", TAC = 0x%.2x\n", + data->epsloci.tai.tac); + printf("\tstatus\t= %d\n\n", data->epsloci.status); + + printf("NASCONFIG:\n"); + printf("\tNAS_SignallingPriority\t\t: 0x%.2x\n", + data->nasconfig.NAS_SignallingPriority.value[0]); + printf("\tNMO_I_Behaviour\t\t\t: 0x%.2x\n", + data->nasconfig.NMO_I_Behaviour.value[0]); + printf("\tAttachWithImsi\t\t\t: 0x%.2x\n", + data->nasconfig.AttachWithImsi.value[0]); + printf("\tMinimumPeriodicSearchTimer\t: 0x%.2x\n", + data->nasconfig.MinimumPeriodicSearchTimer.value[0]); + printf("\tExtendedAccessBarring\t\t: 0x%.2x\n", + data->nasconfig.ExtendedAccessBarring.value[0]); + printf("\tTimer_T3245_Behaviour\t\t: 0x%.2x\n", + data->nasconfig.Timer_T3245_Behaviour.value[0]); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/ActivatePDN.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/ActivatePDN.png new file mode 100644 index 0000000000000000000000000000000000000000..7bdfb63d699e306fd53e495fc0b4cc7d13cd98e6 GIT binary patch literal 9430 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 literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/AuthenticationReject.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/AuthenticationReject.png new file mode 100644 index 0000000000000000000000000000000000000000..de5d3ead9db8457be75a1d26a9eb8d73c3d0655b GIT binary patch literal 21465 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 HPD1jZeA^z^ literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/DeactivatePDN.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/DeactivatePDN.png new file mode 100644 index 0000000000000000000000000000000000000000..28401eadea1b6b9de9b311d0bc7d6822272b158d GIT binary patch literal 8833 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 literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttach.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttach.png new file mode 100644 index 0000000000000000000000000000000000000000..35723a48fe2593974950dcfaee36faffed9518ac GIT binary patch literal 32243 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 literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttachReject.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/InitialAttachReject.png new file mode 100644 index 0000000000000000000000000000000000000000..efe658694f10fa535f9ab36d749cdd2594eb66fe GIT binary patch literal 16271 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 ObhK{YD7|*?_x}O>%now^ literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/NomalDetach.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/NomalDetach.png new file mode 100644 index 0000000000000000000000000000000000000000..e5ca319adaa40233cc3e0ac570d547f6ebfa7093 GIT binary patch literal 5844 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 CPCu{! literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/README b/openair-cn/NAS/EURECOM-NAS/tst/MSC/README new file mode 100644 index 0000000000..b78a7b3e74 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/MSC/README @@ -0,0 +1,34 @@ +================================================================================ + Message Sequence Chart generation +================================================================================ + +Message Sequence Charts (MSCs) are a way of representing entities and +interactions to demonstrate how protocols operate between network elements. + +The Access Stratum simulator generates MSC description file that can be +processed by the Python script msc_gen.py to generate a PNG (Portable +Network Graphic) file. + +msc_gen.py use mscgen utility that is fully discribed at +http://www.mcternan.me.uk/mscgen/ + +-------------------------------------------------------------------------------- + How to generate MSC description file ? +-------------------------------------------------------------------------------- + +Redirect stderr stream to a file that will be used as input by the Python +script msc_gen.py: + +ASprocess 2> ASprocess.msc + +-------------------------------------------------------------------------------- + How to generate PNG file ? +-------------------------------------------------------------------------------- + +Parse the MSC description file using the Python script msc_gen.py: + +./msc_gen.py ASprocess.msc + +Warning: msc_gen.py needs mscgen utility to be installed. mscgen is a C +program that uses the GD graphics library for PNG output. + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/SwitchOffDetach.png b/openair-cn/NAS/EURECOM-NAS/tst/MSC/SwitchOffDetach.png new file mode 100644 index 0000000000000000000000000000000000000000..77b28c11a52b7f5b8b6af762c6ea7bc3c77c6c93 GIT binary patch literal 3697 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 literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/msc_gen.py b/openair-cn/NAS/EURECOM-NAS/tst/MSC/msc_gen.py new file mode 100755 index 0000000000..2857cddc33 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/MSC/msc_gen.py @@ -0,0 +1,354 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Lionel GAUTHIER +# This script is a downgrade of a python script written for the openair stack, generating sequence diagrams charts, displaying +# messages exchanged between LTE access stratum protocol entities. +# This script needs mscgen tool (http://www.mcternan.me.uk/mscgen/). +# +# The aim of this script is to collect some traces from oaisim stack and generate a mscgen script, then generate a sequence diagram +# image (png or jpeg) based on the scripts generated. +# An example of how it can be invoqued: msc_gen.py /tmp/msc_log.txt /tmp/msc_log2.txt msc_logx.txt are input text files, +# They/It are/is generated by the execution of executables in linux user space. May be it is better to operate on log files 'grepped' with MSC: +# ./my_exe.exe | grep \[MSC > /tmp/msc_log1.txt + + +# Now, examples of how to generate a mscgen trace in a C executable: +# -First you have to declare the instance(s) of the protocol(s) that will send or receive messages. +# This is done with the following line: +# [MSC_NEW][system time][protocol_name=instance_name] +# examples: +# printf("[MSC_NEW][%s][MIH-F=%s]\n", getTimeStamp4Log(), g_mihf_id); for declaring a new instance of a protocol entity of type MIH-F +# with an instance name g_mihf_id (of type char*) +# printf("[MSC_NEW][%s][NAS=%s]\n", getTimeStamp4Log(), "nas"); other example. +# This declaration of instances of protocols is mandatory to for this script to work. +# +# -Then for tracing a message you have to log a line following this format: +# [MSC_MSG][system time][source instance_name][--- message_name --->][destination instance_name] +# Note: +# ---> means a message that has been received correctly by destination +# ---x means a message lost by destination +# example +# NOTICE("[MSC_MSG][%s][%s][--- Link_Register.indication\\n%s ---x][%s]\n",getTimeStamp4Log(),g_link_id,g_msc_gen_buf,g_mihf_id); +# + + + + +import sys +import subprocess +import re +import socket +import datetime +import os.path +from datetime import date + +MSCGEN_OUTPUT_TYPE = "png" +MAX_MESSAGES_PER_PAGE = 36 + +SYSTEM_FRAME_NUMBER_STR = 'FRAME' +MODULE_STR = 'MOD' +RADIO_BEARER_STR = 'RB' +MSC_NEW_STR = '[MSC_NEW]' +MSC_MSG_STR = '[MSC_MSG]' +MSC_NBOX_STR = '[MSC_NBOX]' +MSC_BOX_STR = '[MSC_BOX]' +MSC_ABOX_STR = '[MSC_ABOX]' +MSC_RBOX_STR = '[MSC_RBOX]' + +# This dic is filled as follow : g_entities_dic[protocol_instance_name].append(protocol_name) +# where protocol_name can be any of the following MI-USER, MIH-F, RAL, LINK-SAP +g_entities_dic = {} +g_reverse_entities_dic = {} + + +# g_messages is filled with dictionnaries: +# message_dic['entity_src'] = protocol_entity_src +# message_dic['entity_dst'] = protocol_entity_dest +# message_dic['msg'] = message +# message_dic['line_color'] = g_display_color[entity_name] +# message_dic['text_color'] = g_display_color[entity_name] +# message_dic['time'] = system_frame_number +# message_dic['seq_no'] = sequence_number_generator() +# g_messages.append(message_dic) +g_messages = [] +g_messages_dic = {} + + +# g_display_order_dic is a dictionnary where the order of the display of entities sharing the same module identifier is hardcoded +#MAC and PHY valus have to be above num max radio bearer value +#g_display_order_dic = {'MIH-USER': 0, 'MIH-F': 1, 'RAL': 3, 'NAS': 4} +g_display_order_dic = {'NAS-UE': 0, 'AS': 1, 'NAS-MME': 3} + +# Display color of messages of sending entities +g_display_color = {'IP': '\"teal\"', + 'RRC_UE': '\"red\"', + 'MIH-USER': '\"black\"', + 'MIH-F': '\"black\"', + 'RAL': '\"black\"', + 'RAL_M': '\"black\"', + 'RLC_UM': '\"navy\"', + 'RLC_TM': '\"navy\"', + 'NAS': '\"black\"', + 'MAC_eNB': '\"indigo\"', + 'PHY': '\"purple\"', + 'NAS-UE': '\"black\"', + 'NAS-MME': '\"black\"', + 'AS': '\"black\"'} + + +g_final_display_order_list = [] +g_sequence_generator = 0 + +def sequence_number_generator(): + global g_sequence_generator + l_seq = g_sequence_generator + g_sequence_generator = g_sequence_generator + 1 + return l_seq + +def parse_log_file_for_discovering_protocol_entities(filename): + global g_entities_dic + global g_entities + global g_messages + global g_final_display_order_list + #open TXT file that contain OAI filtered traces for mscgen + + fhandle = open(filename, 'r') + fcontent = fhandle.read() + fhandle.close() + + # split file content in lines + lines = fcontent.splitlines() + for line in lines: + system_time = 'unknown' + + # if line is a trace of the creation of a new protocol instance + if MSC_NEW_STR in line: + partition = line.rpartition(MSC_NEW_STR) + msc_log_string = partition[2] + #print (" %s " % msc_log_string) + partition = msc_log_string.split('[') + print ("\n\n %s \n" % partition) + #if len(partition) == 2: + + item = partition[1] + item = item.strip() + item = item.strip(']') + system_time = item.split(' ')[-1] + print ("NEW system_time %s " % system_time) + + item = partition[2] + item = item.strip() + item = item.strip(']') + protocol_entity_type = item.split('=')[0] + protocol_entity_name = item.split('=')[-1] + print ("NEW protocol_entity_type %s " % protocol_entity_type) + print ("NEW protocol_entity_name %s " % protocol_entity_name) + + if protocol_entity_name not in g_entities_dic: + g_entities_dic[protocol_entity_name] = protocol_entity_type + + if protocol_entity_type not in g_reverse_entities_dic: + g_reverse_entities_dic[protocol_entity_type] = protocol_entity_name + else: + entity_name_list = g_reverse_entities_dic[protocol_entity_type] + entity_name_list.append(protocol_entity_name) + g_reverse_entities_dic[protocol_entity_type] = entity_name_list + #print (" g_entities_dic[%d][%d].append(%s)" % (module_id_int, radio_bearer_id_int, entity_name_src)) + print (" g_entities_dic= %s\n\n" % (g_entities_dic)) + print (" g_reverse_entities_dic= %s\n\n" % (g_reverse_entities_dic)) + + #g_entities.append(protocol_entity_type) + #print (" %s \n" % protocol_entity) + + + + + +def parse_log_file(filename): + global g_entities_dic + global g_entities + global g_messages + global g_final_display_order_list + #open TXT file that contain OAI filtered traces for mscgen + fhandle = open(filename, 'r') + fcontent = fhandle.read() + fhandle.close() + + # split file content in lines + lines = fcontent.splitlines() + for line in lines: + system_time = 'unknown' + message = 'unknown' + entity_name_src = 'unknown' + entity_name_dest = 'unknown' + + + # if line is a trace of the creation of a new protocol instance + if MSC_MSG_STR in line: + partition = line.strip().rpartition(MSC_MSG_STR) + msc_log_string = partition[2].strip() + print (" ++++ %s " % msc_log_string) + partition = msc_log_string.split('[') + print (" ++++ %s " % partition) + + #if len(partition) == 9: + message_dic = {} + + system_time = partition[1].strip().split(' ')[-1].strip(']') + message_dic['display_time'] = system_time + seconds_int = int(system_time.split(':')[0]) + micro_seconds_int = int(system_time.split(':')[-1]) + system_time_int = seconds_int*1000000 + micro_seconds_int + system_time=str(system_time_int) + print ('system_time %s' % system_time) + + entity_name_src = partition[2].strip().split(' ')[-1].strip(']') + print ('entity_name_src %s' % entity_name_src) + + message = partition[3].strip().strip(']').strip() + if (message[-1] == 'x') or (message[-1] == 'X'): + message_dic['arc'] = '-x' + elif message[-1] == '>': + message_dic['arc'] = '=>' + message = message.strip('<').strip('>').strip('x').strip('X').strip('-').strip('=').strip() + print ('message %s' % message) + + entity_name_dest = partition[4].strip().split(' ')[-1].strip(']') + print ('entity_name_dest %s' % entity_name_dest) + message_dic['entity_src'] = entity_name_src + message_dic['entity_dst'] = entity_name_dest + message_dic['msg'] = message + message_dic['line_color'] = g_display_color[g_entities_dic[entity_name_src]] + message_dic['text_color'] = g_display_color[g_entities_dic[entity_name_src]] + message_dic['time'] = system_time + #message_dic['seq_no'] = sequence_number_generator() + print ('%s\n\n' % message_dic) + g_messages_dic[system_time_int] = message_dic + #g_messages.append(message_dic) + +#TODO !!! + if MSC_RBOX_STR in line: + partition = line.strip().rpartition(MSC_RBOX_STR) + msc_log_string = partition[2].strip() + print (" ==== %s " % msc_log_string) + partition = msc_log_string.split('[') + print (" ==== %s " % partition) +#TODO !!! + +def generate_sorted_message_list(): + first_time_stamp = 0 + for system_time_int in sorted(g_messages_dic.iterkeys()): + if first_time_stamp == 0: + first_time_stamp = system_time_int + message_dic = g_messages_dic[system_time_int] + message_dic['seq_no'] = sequence_number_generator() + message_dic['display_time'] = str(system_time_int - first_time_stamp) + g_messages.append(message_dic) + +def generate_sorted_entity_display_list(): + module_display_order_dic = {} + for entity_name in sorted(g_entities_dic.iterkeys()): + module_display_order_dic[g_display_order_dic[g_entities_dic[entity_name]]] = entity_name + + + print("------------------------------------") + print(" %s " % (module_display_order_dic)) + + for display_priority in sorted(module_display_order_dic.iterkeys()): + g_final_display_order_list.append(module_display_order_dic[display_priority]) + +def msc_chart_write_header(fileP): + global g_final_display_order_list + fileP.write("msc {\n") + fileP.write("width = \"2048\";\n") + + entity_line_list_str = '' + for entity in g_final_display_order_list: + entity_line_list_str = entity_line_list_str + ' ' + entity + ',' + + entity_line_list_str = entity_line_list_str.rstrip().strip(',') + fileP.write(" %s;" % (entity_line_list_str)) + + +def msc_chart_write_footer(fileP): + fileP.write("\n}\n") + +def msc_chart_generate(file_nameP): + global MSCGEN_OUTPUT_TYPE + command_line = "mscgen -T " + MSCGEN_OUTPUT_TYPE + " -i " + file_nameP + "; chmod 777 " +file_nameP + ";" + + print("Command Line: %s " % (command_line)) + fi,fo,fe=os.popen3(command_line) + for i in fe.readlines(): + print "error:",i + +def get_nem_file_descriptor(): + global g_base_file_name + global g_page_index + l_file_name = g_base_file_name + str(g_page_index)+'.txt' + l_file = open(l_file_name, "w", 0777) + return l_file + + +###### MAIN START HERE ################# +num_args = len(sys.argv) +if num_args < 2: # the program name and the arguments + # stop the program and print an error message + sys.exit("Must provide at least one file to parse") + +for i in range(1,num_args): + print sys.argv[i] + +for i in range(1,num_args): + parse_log_file_for_discovering_protocol_entities(sys.argv[i]) + +for i in range(1,num_args): + parse_log_file(sys.argv[i]) + +generate_sorted_message_list() +generate_sorted_entity_display_list() + +g_page_index = 0 +g_message_index = 0 +g_message_index_in_current_page = 0 +g_now = datetime.datetime.now() +g_now_formated = g_now.strftime("%Y-%m-%d_%H.%M.%S") +g_currentdir = os.curdir +g_resultdir = os.path.join(g_currentdir, g_now_formated) +os.mkdir(g_resultdir, 0777) +os.chdir(g_resultdir) + +g_base_file_name = 'mih_mscgen_page_' + +g_file = get_nem_file_descriptor() +msc_chart_write_header(g_file) + +for message in g_messages: + + if 'msg' in message: + print ('message %s' % message) + g_file.write(" %s%s%s [ label = \"(%d) T%s %s\", linecolour=%s , textcolour=%s ] ;\n" % (message['entity_src'], message['arc'], message['entity_dst'], message['seq_no'], message['display_time'], message['msg'], message['line_color'], message['text_color'])) + elif 'box' in message: + g_file.write(" %s %s %s [ label = \"%s\", textbgcolour=%s , textcolour=%s ] ;\n" % (message['entity_src'], message['box_type'], message['entity_dst'], message['box'], message['textbg_color'], message['text_color'])) + + g_message_index = g_message_index + 1 + g_message_index_in_current_page = g_message_index_in_current_page + 1 + + if (g_message_index_in_current_page == MAX_MESSAGES_PER_PAGE): + msc_chart_write_footer(g_file) + g_file.close() + msc_chart_generate(g_file.name) + g_page_index = g_page_index + 1 + g_message_index_in_current_page = 0 + + g_file = get_nem_file_descriptor() + msc_chart_write_header(g_file) + + +msc_chart_write_footer(g_file) +g_file.close() +if g_message_index_in_current_page >= 1: + msc_chart_generate(g_file.name) +else: + print("Removing empty seq diagram file: %s " % (g_file.name)) + os.remove(g_file.name) diff --git a/openair-cn/NAS/EURECOM-NAS/tst/MSC/mscgen b/openair-cn/NAS/EURECOM-NAS/tst/MSC/mscgen new file mode 100755 index 0000000000000000000000000000000000000000..7a146811c77e7c0256a4bea0078cae6f1cc802d1 GIT binary patch literal 197742 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 literal 0 HcmV?d00001 diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/Makefile b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/Makefile new file mode 100644 index 0000000000..fb99308999 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/Makefile @@ -0,0 +1,231 @@ +export PROCESS = MME + +include ../../Makerules +include ../../Makefile.inc + +PROJDIR = $(PWD)/../.. + +export LD_RUN_PATH = $(LIBDIR):$(LIBPROCESS) + +LIBS = -lutil -lapi -lEMMmsg -lESMmsg -lies +INCLUDES = -I. -I$(INCDIR) -I$(UTILDIR) -I$(NETAPIDIR) \ + -I$(EMMMSGDIR) -I$(ESMMSGDIR) -I$(IESDIR) + +TARGET = ASprocess + +all: $(TARGET) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGET) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +as_data.o: as_data.h +as_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/as_message.h +as_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +as_data.o: /usr/include/stdint.h /usr/include/features.h +as_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +as_data.o: /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h +as_data.o: /usr/include/wchar.h /usr/include/time.h /usr/include/xlocale.h +as_process.o: as_process.h +as_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/as_message.h +as_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +as_process.o: /usr/include/stdint.h /usr/include/features.h +as_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +as_process.o: nas_process.h as_data.h /usr/include/stdio.h +as_process.o: /usr/include/libio.h /usr/include/_G_config.h +as_process.o: /usr/include/wchar.h /usr/include/string.h +as_process.o: /usr/include/xlocale.h +as_simulator.o: as_simulator_parser.h as_data.h as_process.h +as_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/as_message.h +as_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +as_simulator.o: /usr/include/stdint.h /usr/include/features.h +as_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +as_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/socket.h +as_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/nas_log.h +as_simulator.o: /usr/include/stdio.h /usr/include/libio.h +as_simulator.o: /usr/include/_G_config.h /usr/include/wchar.h +as_simulator.o: /usr/include/errno.h /usr/include/netdb.h +as_simulator.o: /usr/include/netinet/in.h /usr/include/endian.h +as_simulator.o: /usr/include/rpc/netdb.h /usr/include/stdlib.h +as_simulator.o: /usr/include/alloca.h /usr/include/string.h +as_simulator.o: /usr/include/xlocale.h /usr/include/poll.h +as_simulator.o: /usr/include/signal.h /usr/include/time.h +as_simulator.o: /usr/include/pthread.h /usr/include/sched.h +as_simulator_parser.o: as_simulator_parser.h +as_simulator_parser.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/parser.h +nas_data.o: nas_data.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachType.h +nas_data.o: /usr/include/stdio.h /usr/include/features.h /usr/include/libio.h +nas_data.o: /usr/include/_G_config.h /usr/include/wchar.h +nas_data.o: /usr/include/stdlib.h /usr/include/alloca.h /usr/include/stdint.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DetachType.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileIdentity.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/IdentityType2.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RequestType.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnType.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnAddress.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GprsTimer.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmmCause.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmCause.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +nas_data.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +nas_process.o: nas_process.h nas_data.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachType.h +nas_process.o: /usr/include/stdio.h /usr/include/features.h +nas_process.o: /usr/include/libio.h /usr/include/_G_config.h +nas_process.o: /usr/include/wchar.h /usr/include/stdlib.h +nas_process.o: /usr/include/alloca.h /usr/include/stdint.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DetachType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/IdentityType2.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RequestType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnAddress.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GprsTimer.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmmCause.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmCause.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/nas_message.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MessageType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DrxParameter.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TmsiStatus.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GutiType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PlmnList.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Nonce.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ServiceType.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CsfbResponse.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ShortMac.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NetworkName.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZone.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PagingIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Cli.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SsCode.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsIndicator.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/QualityOfService.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RadioPriority.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AccessPointName.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h +nas_process.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h +nas_process.o: /usr/include/string.h /usr/include/xlocale.h diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.c new file mode 100644 index 0000000000..cdb39015ce --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.c @@ -0,0 +1,139 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_data.c + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Access-Stratum data + +Author Frederic Maurel + +Description Defines constants and functions used by the AS simulator + process. + +*****************************************************************************/ + +#include "as_data.h" + +#include "as_message.h" + +#include <stdio.h> // snprintf +#include <time.h> // clock_gettime + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Time stamp generator + * ----------------------------------------------------------------------------- + */ +const char* getTime(void) +{ +#define TIME_BUFFER_SIZE 16 + static char time_buffer[TIME_BUFFER_SIZE]; + struct timespec ts; + + clock_gettime (CLOCK_REALTIME, &ts); + snprintf(time_buffer, TIME_BUFFER_SIZE, "%.6ld:%.6ld", + ts.tv_sec % 3600, ts.tv_nsec / 1000); + return (time_buffer); +} + +/* + * ----------------------------------------------------------------------------- + * Return RRC establishment cause + * ----------------------------------------------------------------------------- + */ +const char* rrcCause(char cause) +{ + if (cause == AS_CAUSE_EMERGENCY) { + return "EMERGENCY"; + } else if (cause == AS_CAUSE_HIGH_PRIO) { + return "HIGH_PRIORITY"; + } else if (cause == AS_CAUSE_MT_ACCESS) { + return "MT_ACCESS"; + } else if (cause == AS_CAUSE_MO_SIGNAL) { + return "MO_SIGNALLING"; + } else if (cause == AS_CAUSE_MO_DATA) { + return "MO_DATA"; + } else if (cause == AS_CAUSE_V1020) { + return "V1020"; + } else { + return "Unknown"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return RRC call type + * ----------------------------------------------------------------------------- + */ +const char* rrcType(char type) +{ + if (type == AS_TYPE_ORIGINATING_SIGNAL) { + return "ORIGINATING_SIGNAL"; + } else if (type == AS_TYPE_EMERGENCY_CALLS) { + return "EMERGENCY_CALLS"; + } else if (type == AS_TYPE_ORIGINATING_CALLS) { + return "ORIGINATING_CALLS"; + } else if (type == AS_TYPE_TERMINATING_CALLS) { + return "TERMINATING_CALLS"; + } else if (type == AS_TYPE_MO_CS_FALLBACK) { + return "MO_CS_FALLBACK"; + } else { + return "Unknown"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return Error Code + * ----------------------------------------------------------------------------- + */ +const char* rrcErrCode(char code) +{ + if (code == AS_SUCCESS) { + return "SUCCESS"; + } else if (code == AS_TERMINATED_NAS) { + return "TERMINATED_NAS"; + } else if (code == AS_TERMINATED_AS) { + return "TERMINATED_AS"; + } else if (code == AS_FAILURE) { + return "FAILURE"; + } else { + return "Unknown"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return NAS release cause + * ----------------------------------------------------------------------------- + */ +const char* rrcReleaseCause(char cause) +{ + if (cause == AS_AUTHENTICATION_FAILURE) { + return "AUTHENTICATION FAILURE"; + } else if (cause == AS_DETACH) { + return "DETACH"; + } else { + return "Unknown"; + } +} + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.h b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.h new file mode 100644 index 0000000000..40aeaa8338 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_data.h @@ -0,0 +1,56 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_data.h + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Access-Stratum data + +Author Frederic Maurel + +Description Defines constants and functions used by the AS simulator + process. + +*****************************************************************************/ + +#ifndef __AS_DATA_H__ +#define __AS_DATA_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* + * Constansts used for MSCGEN (Message Sequence Chart Generator) + */ +#define MSCGEN(args...) fprintf(stderr, ##args); +#define _ue_id "UE" +#define _mme_id "MME" +#define _as_id "AS" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +const char* getTime(void); + +const char* rrcCause(char cause); +const char* rrcType(char type); +const char* rrcErrCode(char code); +const char* rrcReleaseCause(char cause); + +#endif // __AS_DATA_H__ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.c new file mode 100644 index 0000000000..795cfce835 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.c @@ -0,0 +1,1231 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_process.c + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem AS message processing + +Author Frederic Maurel + +Description Defines functions executed by the Access-Stratum sublayer + upon receiving AS messages from the Non-Access-Stratum. + +*****************************************************************************/ + +#include "as_process.h" +#include "nas_process.h" + +#include "commonDef.h" +#include "as_data.h" + +#include <sys/types.h> +#include <stdio.h> // snprintf +#include <string.h> // memcpy + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* Message Sequence Chart Generator's buffer */ +#define MSCGEN_BUFFER_SIZE 1024 +static char _mscgen_buffer[MSCGEN_BUFFER_SIZE]; + +/* Tracking area code */ +#define DEFAULT_TAC 0xCAFE // two byte in hexadecimal format + +/* Cell identity */ +#define DEFAULT_CI 0x01020304 // four byte in hexadecimal format + +/* Reference signal received power */ +#define DEFAULT_RSRP 27 + +/* Reference signal received quality */ +#define DEFAULT_RSRQ 55 + +static ssize_t _process_plmn(char* buffer, const plmn_t* plmn, size_t len); +static int _process_dump(char* buffer, int len, const char* msg, int size); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * ============================================================================= + * Functions used to process messages received from the UE NAS process + * ============================================================================= + */ + +/* + * ----------------------------------------------------------------------------- + * Process cell information request message + * ----------------------------------------------------------------------------- + */ +int process_cell_info_req(int msg_id, const cell_info_req_t* req, + cell_info_cnf_t* cnf) +{ + int index = 0; + + printf("INFO\t: %s - Process cell information request\n", __FUNCTION__); + + index += _process_plmn(_mscgen_buffer, &req->plmnID, MSCGEN_BUFFER_SIZE); + snprintf(_mscgen_buffer + index, MSCGEN_BUFFER_SIZE - index, + ", rat = 0x%x%c", req->rat, '\0'); + MSCGEN("[MSC_MSG][%s][%s][--- Cell Information Request (0x%.4x)\\n%s --->][%s]\n", + getTime(), _ue_id, msg_id, _mscgen_buffer, _as_id); + + /* Setup cell information confirm message */ + cnf->errCode = AS_SUCCESS; + cnf->tac = DEFAULT_TAC; + cnf->cellID = DEFAULT_CI; + cnf->rat = AS_EUTRAN; + cnf->rsrp = DEFAULT_RSRP; + cnf->rsrq = DEFAULT_RSRQ; + + snprintf(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + "tac = 0x%.4x, cellID = 0x%.8x, rat = 0x%x, RSRQ = %u, RSRP = %u%c", + cnf->tac, cnf->cellID, cnf->rat, cnf->rsrq, cnf->rsrp, '\0'); + MSCGEN("[MSC_MSG][%s][%s][--- Cell Information Confirm (0x%.4x)\\n%s --->][%s]\n", + getTime(), _as_id, AS_CELL_INFO_CNF, _mscgen_buffer, _ue_id); + + printf("INFO\t: %s - Send cell informtion confirm\n", __FUNCTION__); + return (AS_CELL_INFO_CNF); +} + +/* + * ----------------------------------------------------------------------------- + * Process NAS signalling connection establishment request message + * ----------------------------------------------------------------------------- + */ +int process_nas_establish_req(int msg_id, const nas_establish_req_t* req, + nas_establish_ind_t* ind, + nas_establish_cnf_t* cnf) +{ + int bytes; + + printf("INFO\t: %s - Process NAS signalling connection establishment " + "request\n", __FUNCTION__); + + // Attach_Request.Pdn_Connectivity_Request.ebi = 5 + //req->initialNasMsg.data[23] = 0x52; // MME DEBUG (Reject Attachment) + // Attach_Request.Pdn_Connectivity_Request.messagetype = WRONG_MESSAGE_TYPE + //req->initialNasMsg.data[25] = 0xc4; // MME DEBUG (Send ESM status) + + snprintf(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + "cause = %s, type = %s, tmsi = {MMEcode = %d, m_tmsi = %u}%c", + rrcCause(req->cause), rrcType(req->type), + req->s_tmsi.MMEcode, req->s_tmsi.m_tmsi, '\0'); + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment Request " + "(0x%.4x)\\n%s --->][%s]\n", + getTime(), _ue_id, msg_id, _mscgen_buffer, _as_id); + + _process_dump(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->initialNasMsg.data, req->initialNasMsg.length); + MSCGEN("[MSC_RBOX][%s][%s][%s]\n", _ue_id, _as_id, _mscgen_buffer); + + /* Process initial NAS message */ + bytes = nas_process(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->initialNasMsg.data, + req->initialNasMsg.length); + if (bytes < 0) { + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment " + "Indication (0x%.4x)\\ntac = 0x%.4x\\n%s ---x][%s]\n", getTime(), + _as_id, AS_NAS_ESTABLISH_IND, ind->tac, _mscgen_buffer, _mme_id); + /* Setup NAS signalling connection establishment confirmation message */ + cnf->errCode = AS_TERMINATED_AS; + return (0); + } + + /* Setup NAS signalling connection establishment indication message */ + ind->UEid = 1; // Valid UEid starts at index 1 + ind->tac = DEFAULT_TAC; + if (req->initialNasMsg.length > 0) { + ind->initialNasMsg.data = (Byte_t*)malloc(req->initialNasMsg.length); + if (ind->initialNasMsg.data) { + memcpy(ind->initialNasMsg.data, req->initialNasMsg.data, + req->initialNasMsg.length); + ind->initialNasMsg.length = req->initialNasMsg.length; + } + } + + // Attach_Request.messagetype = WRONG_MESSAGE_TYPE + //ind->initialNasMsg.data[1] = 0x47; // MME DEBUG (Send EMM status) + + /* Setup NAS signalling connection establishment confirmation message */ + cnf->errCode = AS_SUCCESS; + // Transmission failure of Attach Request message + //cnf->errCode = AS_FAILURE; // UE DEBUG + + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment Indication " + "(0x%.4x)\\nUEid = %u, tac = 0x%.4x\\n%s --->][%s]\n", getTime(), + _as_id, AS_NAS_ESTABLISH_IND, ind->UEid, ind->tac, _mscgen_buffer, _mme_id); + + printf("INFO\t: %s - Send NAS signalling connection establishment " + "indication\n", __FUNCTION__); + return (AS_NAS_ESTABLISH_IND); +} + +/* + * ----------------------------------------------------------------------------- + * Process Uplink data transfer request message + * ----------------------------------------------------------------------------- + */ +int process_ul_info_transfer_req(int msg_id, const ul_info_transfer_req_t* req, + ul_info_transfer_ind_t* ind, + ul_info_transfer_cnf_t* cnf) +{ + int bytes; + + printf("INFO\t: %s - Process uplink data transfer request\n", __FUNCTION__); + + // Attach_Complete.Activate_Default_EPS_Bearer_Context_Accept.ebi = UNASSIGNED + //if (req->nasMsg.data[7] == 0x43) { + // req->nasMsg.data[10] = 0x02; // MME DEBUG (Send ESM status) + //} + // Deactivate_EPS_Bearer_Context_Accept.ebi = UNASSIGNED + //if (req->nasMsg.data[8] == 0xCE) { + // req->nasMsg.data[6] = 0x02; // MME DEBUG (Discard ESM message) + //} + + snprintf(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + "tmsi = {MMEcode = %d, m_tmsi = %u}%c", + req->s_tmsi.MMEcode, req->s_tmsi.m_tmsi, '\0'); + MSCGEN("[MSC_MSG][%s][%s][--- Uplink Information Request " + "(0x%.4x)\\n%s --->][%s]\n", + getTime(), _ue_id, msg_id, _mscgen_buffer, _as_id); + + _process_dump(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->nasMsg.data, req->nasMsg.length); + MSCGEN("[MSC_RBOX][%s][%s][%s]\n", _ue_id, _as_id, _mscgen_buffer); + + /* Process NAS message */ + bytes = nas_process(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->nasMsg.data, + req->nasMsg.length); + if (bytes < 0) { + MSCGEN("[MSC_MSG][%s][%s][--- Uplink Information Indication " + "(0x%.4x)\\n%s ---x][%s]\n", getTime(), + _as_id, AS_UL_INFO_TRANSFER_IND, _mscgen_buffer, _mme_id); + /* Setup uplink information confirmation message */ + cnf->errCode = AS_TERMINATED_AS; + return (0); + } + + /* Setup uplink information indication message */ + ind->UEid = 1; // Valid UEid starts at index 1 + if (req->nasMsg.length > 0) { + ind->nasMsg.data = (Byte_t*)malloc(req->nasMsg.length); + if (ind->nasMsg.data) { + memcpy(ind->nasMsg.data, req->nasMsg.data, req->nasMsg.length); + ind->nasMsg.length = req->nasMsg.length; + } + } + + // Identity-Response.messagetype = WRONG_MESSAGE_TYPE + //if (ind->nasMsg.data[1] == 0x56) { + // ind->nasMsg.data[1] = 0x47; // MME DEBUG (Send EMM status) + //} + // Authentication-Response.messagetype = WRONG_MESSAGE_TYPE + //if (ind->nasMsg.data[1] == 0x53) { + // ind->nasMsg.data[1] = 0x47; // MME DEBUG (Send EMM status) + //} + // Security-Mode-Complete.messagetype = WRONG_MESSAGE_TYPE + //if (ind->nasMsg.data[7] == 0x5e) { + // ind->nasMsg.data[7] = 0x47; // MME DEBUG (Send EMM status) + //} + + /* Setup uplink information confirmation message */ + cnf->UEid = 0; + cnf->errCode = AS_SUCCESS; + // Transmission failure of Attach Complete message + //if (req->nasMsg.data[7] == 0x43) { + // cnf->errCode = AS_FAILURE; // UE DEBUG + //} + + MSCGEN("[MSC_MSG][%s][%s][--- Uplink Information Indication " + "(0x%.4x), UEid = %u\\n%s --->][%s]\n", getTime(), + _as_id, AS_UL_INFO_TRANSFER_IND, ind->UEid, _mscgen_buffer, _mme_id); + + printf("INFO\t: %s - Send uplink data transfer indication\n", __FUNCTION__); + return (AS_UL_INFO_TRANSFER_IND); +} + +/* + * ----------------------------------------------------------------------------- + * Process NAS signalling connection release request message + * ----------------------------------------------------------------------------- + */ +int process_nas_release_req(int msg_id, const nas_release_req_t* req) +{ + printf("INFO\t: %s - Process NAS signalling connection release request\n", + __FUNCTION__); + + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Release Request " + "(0x%.4x), tmsi = {MMEcode = %d, m_tmsi = %u}, " + "cause = %s (%u) --->][%s]\n", getTime(), _ue_id, msg_id, + req->s_tmsi.MMEcode, req->s_tmsi.m_tmsi, + rrcReleaseCause(req->cause), req->cause, _as_id); + return (AS_NAS_RELEASE_REQ); +} + +/* + * ============================================================================= + * Functions used to process messages received from the MME NAS process + * ============================================================================= + */ + +/* + * ----------------------------------------------------------------------------- + * Process NAS signalling connection establishment response message + * ----------------------------------------------------------------------------- + */ +int process_nas_establish_rsp(int msg_id, const nas_establish_rsp_t* rsp, + nas_establish_cnf_t* cnf) +{ + int bytes; + + printf("INFO\t: %s - Process NAS signalling connection establishment " + "response\n", __FUNCTION__); + + // Attach_Accept + //if (rsp->nasMsg.data[7] == 0x42) { + // Activate_Default_EPS_Bearer_Context_Request.ebi = UNASSIGNED + //rsp->nasMsg.data[19] = 0x02; // UE DEBUG (Send ESM status) + // Activate_Default_EPS_Bearer_Context_Request.messagetype = WRONG_MESSAGE_TYPE + //rsp->nasMsg.data[21] = 0xc4; // MME DEBUG (Send ESM status) + //} + + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment " + "Response (0x%.4x)\\nerrCode = %s, UEid = %u --->][%s]\n", + getTime(), _mme_id, msg_id, + rrcErrCode(rsp->errCode), rsp->UEid, _as_id); + + _process_dump(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)rsp->nasMsg.data, rsp->nasMsg.length); + MSCGEN("[MSC_RBOX][%s][%s][%s]\n", _mme_id, _as_id, _mscgen_buffer); + + // Discard Attach Accept message + //return (0); // UE DEBUG + + /* Process initial NAS message */ + bytes = nas_process(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)rsp->nasMsg.data, + rsp->nasMsg.length); + + if (bytes < 0) { + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment " + "Confirm (0x%.4x)\\n%s ---x][%s]\n", getTime(), + _as_id, AS_NAS_ESTABLISH_CNF, _mscgen_buffer, _ue_id); + return (0); + } + + /* Setup NAS signalling connection establishment confirm message */ + cnf->errCode = rsp->errCode; + if (rsp->nasMsg.length > 0) { + cnf->nasMsg.data = (Byte_t*)malloc(rsp->nasMsg.length); + if (cnf->nasMsg.data) { + memcpy(cnf->nasMsg.data, rsp->nasMsg.data, + rsp->nasMsg.length); + cnf->nasMsg.length = rsp->nasMsg.length; + } + } + + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Establishment " + "Confirm (0x%.4x)\\n%s --->][%s]\n", getTime(), + _as_id, AS_NAS_ESTABLISH_CNF, _mscgen_buffer, _ue_id); + + printf("INFO\t: %s - Send NAS signalling connection establishment " + "confirm\n", __FUNCTION__); + return (AS_NAS_ESTABLISH_CNF); +} + +/* + * ----------------------------------------------------------------------------- + * Process Downlink data transfer request message + * ----------------------------------------------------------------------------- + */ +int process_dl_info_transfer_req(int msg_id, const dl_info_transfer_req_t* req, + dl_info_transfer_ind_t* ind, + dl_info_transfer_cnf_t* cnf) +{ + int bytes; + + printf("INFO\t: %s - Process downlink data transfer request\n", + __FUNCTION__); + + // Activate_default_EPS_Bearer_Context_Request.ebi = 6 (already active) + //if (req->nasMsg.data[8] == 0xC1) { + // req->nasMsg.data[6] = 0x52; // UE DEBUG (Accept with same ebi) + //} + // Deactivate_EPS_Bearer_Context_Request.ebi = UNASSIGNED + //if (req->nasMsg.data[8] == 0xCD) { + // req->nasMsg.data[6] = 0x02; // UE DEBUG + //} + + MSCGEN("[MSC_MSG][%s][%s][--- Downlink Information Request " + "(0x%.4x), UEid = %u --->][%s]\n", + getTime(), _mme_id, msg_id, req->UEid, _as_id); + + _process_dump(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->nasMsg.data, req->nasMsg.length); + MSCGEN("[MSC_RBOX][%s][%s][%s]\n", _mme_id, _as_id, _mscgen_buffer); + + /* Process NAS message */ + bytes = nas_process(_mscgen_buffer, MSCGEN_BUFFER_SIZE, + (char*)req->nasMsg.data, + req->nasMsg.length); + if (bytes < 0) { + MSCGEN("[MSC_MSG][%s][%s][--- Downlink Information Indication " + "(0x%.4x)\\n%s ---x][%s]\n", getTime(), + _as_id, AS_DL_INFO_TRANSFER_IND, _mscgen_buffer, _ue_id); + /* Setup downlink information confirmation message */ + cnf->UEid = req->UEid; + cnf->errCode = AS_TERMINATED_AS; + return (0); + } + + /* Setup downlink information indication message */ + if (req->nasMsg.length > 0) { + ind->nasMsg.data = (Byte_t*)malloc(req->nasMsg.length); + if (ind->nasMsg.data) { + memcpy(ind->nasMsg.data, req->nasMsg.data, req->nasMsg.length); + ind->nasMsg.length = req->nasMsg.length; + } + } + + /* Setup downlink information confirmation message */ + cnf->UEid = req->UEid; + cnf->errCode = AS_SUCCESS; + + //if (req->nasMsg.data[1] == 0x55) { + // Transmission failure of identification request message + // cnf->errCode = AS_FAILURE; // MME DEBUG + // Discard identification request message + // return (0); // MME DEBUG + //} + + MSCGEN("[MSC_MSG][%s][%s][--- Downlink Information Indication " + "(0x%.4x)\\n%s --->][%s]\n", getTime(), + _as_id, AS_DL_INFO_TRANSFER_IND, _mscgen_buffer, _ue_id); + + printf("INFO\t: %s - Send downlink data transfer indication\n", __FUNCTION__); + return (AS_DL_INFO_TRANSFER_IND); +} + +/* + * ----------------------------------------------------------------------------- + * Process NAS signalling connection release indication message + * ----------------------------------------------------------------------------- + */ +int process_nas_release_ind(int msg_id, const nas_release_req_t* req, + nas_release_ind_t* ind) +{ + printf("INFO\t: %s - Process NAS signalling connection release request\n", + __FUNCTION__); + + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Release Request " + "(0x%.4x), UEid = %u, cause = %s (%u) --->][%s]\n", + getTime(), _mme_id, msg_id, req->UEid, + rrcReleaseCause(req->cause), req->cause, _as_id); + + /* Forward NAS release indication to the UE */ + ind->cause = req->cause; + MSCGEN("[MSC_MSG][%s][%s][--- NAS Signalling Connection Release Indication " + "(0x%.4x), cause = %s (%u) --->][%s]\n", + getTime(), _as_id, msg_id, rrcReleaseCause(req->cause), + ind->cause, _ue_id); + + printf("INFO\t: %s - Send NAS signalling connection release indication\n", + __FUNCTION__); + return (AS_NAS_RELEASE_IND); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Display PLMN identity + * ----------------------------------------------------------------------------- + */ +static ssize_t _process_plmn(char* buffer, const plmn_t* plmn, size_t len) +{ + int index = 0; + index += snprintf(buffer + index, len - index, "plmnID = %u%u%u%u%u", + plmn->MCCdigit1, plmn->MCCdigit2, plmn->MCCdigit3, + plmn->MNCdigit1, plmn->MNCdigit2); + if ( (index < len) && (plmn->MNCdigit3 != 0xf) ) { + index += snprintf(buffer + index, len - index, "%u", plmn->MNCdigit3); + } + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Message dump utility + * ----------------------------------------------------------------------------- + */ +static int _process_dump(char* buffer, int len, const char* msg, int size) +{ + int index = 0; + for (int i = 0; i < size; i++) { + if ( (i%16) == 0 ) index += snprintf(buffer + index, + len - index, "\\n"); + index += snprintf(buffer + index, len - index, + " %.2hx", (unsigned char)(msg[i])); + } + buffer[index] = '\0'; + return (index); +} + +/* + 04 01 04 10 00 00 0f 00 00 00 01 00 00 00 20 8f + 10 00 22 00 00 00 07 41 71 0b f6 02 f8 01 01 02 + 0f 00 00 00 01 05 80 80 00 00 00 00 04 02 01 d0 + 31 52 02 f8 01 00 01 e0 +*/ +/* + U16 msgID = [04 01] - AS_NAS_ESTABLISH_REQ + U8 cause = [04] - NET_ESTABLISH_CAUSE_MO_SIGNAL + U8 type = [10] - NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + plmn_t plmnID = [20 8f 10] + Byte_t MCCdigit2:4 = [0] + Byte_t MCCdigit1:4 = [2] + Byte_t MNCdigit3:4 = [f] + Byte_t MCCdigit3:4 = [8] + Byte_t MNCdigit2:4 = [0] + Byte_t MNCdigit1:4 = [1] + + U32 Length = [22 00 00 00] (34 octets) + U8* initialNasMsg = [07 41 71 0b f6 02 f8 01 01 02 0f 00 00 00 01 05] + [80 80 00 00 00 00 04 02 01 d0 31 52 02 f8 01 00] + [01 e0] + + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [41] - Attach Request + + U8:4 NAS KSI = [7] - No key available + U8:4 Attach Type = [1] + EPS Mobile Identity = [0b f6 02 f8 01 01 02 0f 00 00 00 01] + Length = [0b] (11 bytes) + U8:4 = 1111 = [f] + U8:1 oddeven = 0 + U8:3 typeofidentity = 110 = [6] - GUTI + U8:4 mccdigit2 = [0] + U8:4 mccdigit1 = [2] + U8:4 mncdigit3 = [f] + U8:4 mccdigit3 = [8] + U8:4 mncdigit2 = [0] + U8:4 mncdigit1 = [1] + U16 mmegroupid = [01 02] + U8 mmecode = [0f] + U32 mtmsi = [00 00 00 01] + UE network capability = [05 80 80 00 00 00] + Length = [05] (5 bytes) + U8 eea = [80] - EEA0 + U8 eia = [80] - EIA0 + U8 uea = [00] + U8:1 ucs2 = 0 + U8:7 uia = 0000000 = [00] + U8:3 spare = 000 + U8:1 csfb = 0 + U8:1 lpp = 0 + U8:1 lcs = 0 + U8:1 srvcc = 0 + U8:1 nf = 0 = [00] + + ESM message container = [00 04 02 01 d0 31] + Length = [00 04] (4 bytes) + ESM message = [02 01 d0 31] + U8:4 EPS bearer identity = [0] - Not assigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [01] + U8 ESM message identifier = [d0] - PDN Connectivity Request + U8:4 Pdn type = [3] - IPv4v6 + U8:4 Request type = [1] - Initial request + + Last TAI = [52 02 f8 01 00 01] - PLMN = 20810, TAC = 00 01 + Old GUTI type = [e0] - Native GUTI +*/ + +/* + 07 04 00 00 00 00 03 00 00 00 07 44 03 +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [03 00 00 00] (3 octets) + U8* NasMsg = [07 44 03] + + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [44] - Attach Reject + + U8 EMM cause code = [03] - EMM_CAUSE_ILLEGAL_UE +*/ + +/* + 07 04 00 00 00 00 10 00 00 00 27 ab ab ab ab 00 + 07 44 13 78 00 04 02 01 d1 1f +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [10 00 00 00] (16 octets) + U8* NasMsg = [27 ab ab ab ab 00 07 44 13 78 00 04 02 01 d1 1f] + + U8:4 Security header type = [2] - Integrity protected and cyphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - 0 + + NAS message = [07 44 13 78 00 04 02 d1 1f] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [44] - Attach Reject + + U8 EMM cause code = [13] - #19 ESM failure + + ESM message container = [00 04 02 01 d1 1f] + U16 Length = [00 04] (4 octets) + U8* EsmMsg = [02 01 d1 1f] + U8:4 EPS bearer identity = [0] - Not assigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [01] + U8 ESM message identifier = [d1] - PDN Connectivity Reject + + U8 ESM cause code = [1f] - REQUEST_REJECTED_UNSPECIFIED +*/ + +/* + 04 08 01 00 00 00 46 00 00 00 27 ab ab ab ab 00 + 07 42 01 e0 06 24 02 f8 01 00 01 00 26 52 01 c1 + 05 03 48 87 40 78 0e 77 77 77 2e 65 75 72 65 63 + 6f 6d 2e 66 72 0d 03 c0 a8 02 3c 02 21 70 ff c0 + a8 02 3c 50 0b f6 02 f8 01 01 02 0f 00 00 00 01 +*/ +/* + U16 msgID = [04 08] - AS_NAS_ESTABLISH_CNF + U8 errCode = [01] - SUCCESS + + U32 Length = [00 00 00 46] (70 octets) + U8* NasMsg = [27 ab ab ab ab 00 07 42 01 e0 06 24 02 f8 01 00] + [01 00 26 52 01 c1 05 03 48 87 40 78 0e 77 77 77] + [2e 65 75 72 65 63 6f 6d 2e 66 72 0d 03 c0 a8 02] + [3c 02 21 70 ff c0 a8 02 3c 50 0b f6 02 f8 01 01] + [02 0f 00 00 00 01] + + U8:4 Security header type = [2] - Integrity protected and cyphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - 0 + + NAS message = [07 42 01 e0 06 24 02 f8 01 00 01 00 26 52 01 c1] + [05 03 48 87 40 78 0e 77 77 77 2e 65 75 72 65 63] + [6f 6d 2e 66 72 0d 03 c0 a8 02 3c 02 21 70 ff c0] + [a8 02 3c 50 0b f6 02 f8 01 01 02 0f 00 00 00 01] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [42] - Attach Accept + + U8:4 Spare = [0] + U8:4 EPS attach result = [1] - EPS + U8:3 T3412 unit = 111 - Deactivated + U8:5 T3412 value = 00000 + + TAI list = [06 24 02 f8 01 00 01] + Length = [06] + U8:1 spare = 0 + U8:2 Type of list = 01 - list of TACs belonging to one PLMN, + with consecutive TAC values + U8:5 Number of elements = 0 0100 - 4 consecutive TACs + TAI = [02 f8 01 00 01] - PLMN = 20810, TAC = 00 01 + + ESM message container = [00 26 52 01 c1 05 03 48 87 40 78 0e 77 77 77 2e] + [65 75 72 65 63 6f 6d 2e 66 72 0d 03 c0 a8 02 3c] + [02 21 70 ff c0 a8 02 3c] + U16 Length = [00 26] (38 octets) + U8:4 EPS bearer identity = [5] - ebi = 5 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [01] + U8 ESM message identifier = [c1] - Activate Default EPS Bearer Context Request + + EPS Qos = [05 03 48 87 40 78] + Length = [05] - 5 octets + QCI = [03] - 3 + Maximum bit rate for uplink = [48] - 128K + Maximum bit rate for downlink = [87] - 1024K + Guaranteed bit rate for uplink = [40] - 64K + Guaranteed bit rate for downlink = [78] - 512K + + Access point name = [0e 77 77 77 2e 65 75 72 65 63 6f 6d 2e 66 72] + Length = [0e] - 14 octets + APN = "www.eurecom.fr" + + PDN address = [0d 03 c0 a8 02 3c 02 21 70 ff c0 a8 02 3c] + Length = [0d] - 13 octets + U8:5 Spare = 00000 - 0 + U8:3 Pdn type = 011 - IPv4v6 + PDN address information = [c0 a8 02 3c 02 21 70 ff c0 a8 02 3c] +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 0d 00 + 00 00 27 ab ab ab ab 00 07 43 00 03 52 00 c2 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 0d] (13 octets) + U8* NasMsg = [27 ab ab ab ab 00 07 43 00 03 52 00 c2] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [07 43 00 03 52 00 c2] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [43] - Attach Complete + + ESM message container = [00 03 52 00 c2] + Length = [00 03] (3 bytes) + ESM message = [52 00 c2] + U8:4 EPS bearer identity = [5] - ebi = 5 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] - unassigned + U8 ESM message identifier = [c2] - Activate Default EPS Bearer Context Accept +*/ + +/* + 07 04 00 00 00 00 03 00 00 00 07 55 10 +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [03 00 00 00] (3 octets) + U8* NasMsg = [07 55 10] + + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [55] - Identity Request + + U8:4 Identity type = [1] - IMSI + U8:4 spare = [0] +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 0b 00 + 00 00 07 56 08 21 80 01 0f 00 10 32 f4 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 0b] (11 octets) + U8* NasMsg = [07 56 08 21 80 01 0f 00 10 32 f4] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [56] - Identity Response + + Mobile identity = [08 21 80 01 0f 00 10 32 f4] + Length = [08] - 8 octets + U8:4 Identity digit 1 = [2] - 2 + U8:1 odd/even indicator = [0] - even number of identity digits + U8:3 Type of identity = [001] - IMSI + U8:4 Identity digit 3 = [8] - 8 + U8:4 Identity digit 2 = [0] - 0 + U8:4 Identity digit 5 = [0] - 0 + U8:4 Identity digit 4 = [1] - 1 + U8:4 Identity digit 7 = [0] - 0 + U8:4 Identity digit 6 = [f] - f + U8:4 Identity digit 9 = [0] - 0 + U8:4 Identity digit 8 = [0] - 0 + U8:4 Identity digit 11 = [1] - 1 + U8:4 Identity digit 10 = [0] - 0 + U8:4 Identity digit 13 = [3] - 3 + U8:4 Identity digit 12 = [2] - 2 + U8:4 Identity digit 15 = [f] - f + U8:4 Identity digit 16 = [4] - 4 + +IMSI = 20810f00001234f (2081000001234) +*/ + +/* + 07 04 00 00 00 00 24 00 00 00 07 52 00 00 00 00 + 00 00 00 00 00 00 00 00 00 01 02 03 04 10 00 00 + 00 00 00 00 80 05 04 03 02 00 00 00 00 00 +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [24 00 00 00] (36 octets) + U8* NasMsg = [07 52 00 00 00 00 00 00 00 00 00 00 00 00 00 01] + [02 03 04 10 00 00 00 00 00 00 80 05 04 03 02 00] + [00 00 00 00] + + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [52] - Authentication Request + + U8:4 NAS key set identifier = [0] - 000 + U8:4 spare = [0] + RAND = [00 00 00 00 00 00 00 00 00 00 00 00 01 02 03 04] + AUTHN Length = [10] - 16 octets + AUTHN = [00 00 00 00 00 00 80 05 04 03 02 00 00 00 00 00] +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 13 00 + 00 00 07 53 10 67 70 3a 31 f2 2a 2d 51 00 00 00 + 00 00 00 00 00 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 13] (19 octets) + U8* NasMsg = [07 53 10 67 70 3a 31 f2 2a 2d 51 00 00 00 00 00 00 00 00] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [53] - Authentication Response + + RES Length = [10] - 16 octets + RES = [67 70 3a 31 f2 2a 2d 51 00 00 00 00 00 00 00 00] +*/ + +/* + 07 04 00 00 00 00 10 00 00 00 37 ab ab ab ab 00 + 07 5d 00 00 05 80 80 00 00 00 +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [10 00 00 00] (16 octets) + U8* NasMsg = [37 ab ab ab ab 00 07 5d 00 00 05 80 80 00 00 00] + + U8:4 Security header type = [3] - Integrity protected with + new EPS security context + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - 0 + + NAS message = [07 5d 00 00 05 80 80 00 00 00] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [5d] - Security Mode Command + + U8 Selected NAS security algorithms = [00] + U8:4 Spare half octet = [0] + U8:4 NAS key set identifier = [0] + Replayed UE security capabilities = [05 80 80 00 00 00] + U8 EEA = [80] - EEA0 + U8 EIA = [80] - EIA0 + U8 UEA = [00] + U8 UIA = [00] + U8 GEA = [00] +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 08 00 + 00 00 47 ab ab ab ab 00 07 5e +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 08] (8 octets) + U8* NasMsg = [47 ab ab ab ab 00 07 5e] + + U8:4 Security header type = [4] - Integrity protected and ciphered with + new EPS security context + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [07 5e] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [5e] - Security Mode Complete +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 09 00 + 00 00 27 ab ab ab ab 00 07 5f 18 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 09] (9 octets) + U8* NasMsg = [27 ab ab ab ab 00 07 5f 18] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [07 5f 18] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [5f] - Security Mode Reject + + U8 EMM cause code = [18] - EMM_CAUSE_SECURITY_MODE_REJECTED +*/ + +/* + 07 01 00 00 00 00 00 00 00 00 00 00 00 00 04 00 + 00 00 52 00 e8 6f +*/ +/* + U16 msgID = [07 01] - AS_DL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [00] - !!! + U32 m_tmsi = [00 00 00 00] - !!! + + U32 Length = [00 00 00 04] (4 octets) + NAS message = [52 00 e8 6f] + + U8:4 EPS bearer identity = [5] - ebi = 5 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] - unassigned + U8 ESM message identifier = [e8] - ESM Status + + U8 ESM cause code = [6f] - #111 PROTOCOL_ERROR +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 0a 00 + 00 00 27 ab ab ab ab 00 02 01 e8 2b +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 0a] (10 octets) + U8* NasMsg = [27 ab ab ab ab 00 02 01 e8 2b] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [02 01 e8 2b] + U8:4 EPS bearer identity = [0] - Not assigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [01] + U8 ESM message identifier = [e8] - ESM Status + + U8 ESM cause code = [2b] - #43 INVALID_EPS_BEARER_IDENTITY +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 0a 00 + 00 00 27 ab ab ab ab 00 02 03 d2 06 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 0a] (10 octets) + U8* NasMsg = [27 ab ab ab ab 00 02 03 d2 06] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [02 03 d2 06] + U8:4 EPS bearer identity = [0] - Not assigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [03] + U8 ESM message identifier = [d2] - PDN Disconnect Request + + U8:4 Spare half octet = [0] + U8:4 Linked EPS bearer identity = [6] - ebi = 6 +*/ + +/* + 06 08 00 00 00 00 01 00 00 00 +*/ +/* + U16 msgID = [06 08] - AS_UL_INFO_TRANSFER_CNF + U32 UEid = [00 00 00 00] + U8 errCode = [01] - SUCCESS +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 09 00 + 00 00 27 ab ab ab ab 00 82 00 ce +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 09] (9 octets) + U8* NasMsg = [27 ab ab ab ab 00 82 00 ce] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [82 00 ce] + U8:4 EPS bearer identity = [8] - 8 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] + U8 ESM message identifier = [ce] - Deactivate EPS Bearer Context Accept +*/ + +/* + 07 01 01 00 00 00 00 00 00 00 00 00 00 00 0a 00 + 00 00 27 ab ab ab ab 00 62 02 cd 24 +*/ +/* + U16 msgID = [07 01] - AS_DL_INFO_TRANSFER_REQ + U32 UEid = [01 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [00] + U32 m_tmsi = [00 00 00 00] + + U32 Length = [00 00 00 0a] (10 octets) + NAS message = [27 ab ab ab ab 00 62 02 cd 24] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [62 02 cd 24] + U8:4 EPS bearer identity = [6] - ebi = 6 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [02] + U8 ESM message identifier = [cd] - Deactivate EPS Bearer Context Request + + U8 ESM cause code = [24] - #36 REGULAR_DEACTIVATION +*/ + +/* + 04 08 01 00 00 00 00 00 00 00 +*/ +/* + U16 msgID = [04 08] - AS_NAS_ESTABLISH_CNF + U8 errCode = [01] - SUCCESS + U32 Length = [00 00 00 00] (0 octets) +*/ + + +/* + 07 01 01 00 00 00 00 00 00 00 00 00 00 00 0e 00 + 00 00 27 ab ab ab ab 00 72 00 c5 06 01 02 01 00 +*/ +/* + U16 msgID = [07 01] - AS_DL_INFO_TRANSFER_REQ + U32 UEid = [01 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [00] + U32 m_tmsi = [00 00 00 00] + + U32 Length = [00 00 00 0e] (14 octets) + NAS message = [27 ab ab ab ab 00 72 00 c5 06 01 02 01 00] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [72 00 c5 06 00 00 00 00] + U8:4 EPS bearer identity = [7] - ebi = 7 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity - Unassigned + U8 ESM message identifier = [c5] - Activate dedicated EPS Bearer Context Request + + U8:4 Spare half octet = [0] + U8:4 Linked EPS bearer identity = [6] + U8 QoS length = [01] + U8 QCI = [02] + U8 TFT length = [01] + U8 TFT = [00] +*/ + +/* + 07 04 00 00 00 00 36 00 00 00 27 ab ab ab ab 00 + 72 00 c5 06 01 02 29 22 11 02 11 10 c0 a8 0c 01 + ff ff ff 00 30 11 40 27 11 50 2e e1 22 03 11 10 + c0 a8 0c 01 ff ff ff 00 30 11 40 27 12 50 2e e2 +*/ +/* + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 UEid = [00 00 00 00] + + U32 Length = [36 00 00 00] (54 octets) + U8* NasMsg = [27 ab ab ab ab 00 72 00 c5 06 01 02 29 22 11 02] + [11 10 c0 a8 0c 01 ff ff ff 00 30 11 40 27 11 50] + [2e e1 22 03 11 10 c0 a8 0c 01 ff ff ff 00 30 11] + [40 27 12 50 2e e2] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - 0 + + NAS message = [72 00 c5 06 01 02 29 22 11 02 11 10 c0 a8 0c 01] + [ff ff ff 00 30 11 40 27 11 50 2e e1 22 03 11 10] + [c0 a8 0c 01 ff ff ff 00 30 11 40 27 12 50 2e e2] + U8:4 EPS bearer identity = [7] - ebi = 7 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity - Unassigned + U8 ESM message identifier = [c5] - Activate dedicated EPS Bearer Context Request + + U8:4 Spare half octet = [0] + U8:4 Linked EPS bearer identity = [6] + U8 QoS length = [01] - 1 octet + U8 QCI = [02] + U8 TFT length = [29] - 41 octets + U8 TFT = [22 11 02 11 10 c0 a8 0c 01 ff ff ff 00 30 11 40] + [27 11 50 2e e1 22 03 11 10 c0 a8 0c 01 ff ff ff] + [00 30 11 40 27 12 50 2e e2] +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 0a 00 + 00 00 27 ab ab ab ab 00 72 00 c7 2d +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 0a] (10 octets) + U8* NasMsg = [27 ab ab ab ab 00 72 00 c7 2d] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [72 00 c7 2d] + U8:4 EPS bearer identity = [7] - 7 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] + U8 ESM message identifier = [c7] - Activate Dedicated EPS Bearer Context + Reject + + U8 ESM cause code = [2d] - SYNTACTICAL_ERROR_IN_PACKET_FILTER +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 09 00 + 00 00 27 ab ab ab ab 00 72 00 c6 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 09] (9 octets) + U8* NasMsg = [27 ab ab ab ab 00 72 00 c6] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [72 00 c6] + U8:4 EPS bearer identity = [7] - 7 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] + U8 ESM message identifier = [c6] - Activate Dedicated EPS Bearer Context + Accept +*/ + +/* + 06 01 00 00 00 00 12 00 00 00 01 00 00 00 15 00 + 00 00 27 ab ab ab ab 00 07 45 01 0b f6 02 f8 01 + 01 02 12 00 00 00 01 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + U32 UEid = [00 00 00 00] + as_stmsi_t s_tmsi + U8 MMEcode = [12] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 15] (21 octets) + U8* NasMsg = [27 ab ab ab ab 00 07 45 01 0b f6 02 f8 01 01 02] + [12 00 00 00 01] + + U8:4 Security header type = [2] - Integrity protected and ciphered + U8:4 Protocol discriminator = [7] - EMM message + U32 Message authentication code = [ab ab ab ab] + U8 Sequence number = [00] - Uplink counter value + + NAS message = [07 45 01 0b f6 02 f8 01 01 02 12 00 00 00 01] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [45] - Detach Request + + U8:4 NAS key set identifier = [0] - Native 0 + U8:4 Detach type = [1] - EPS Detach + + Mobile identity = [0b f6 02 f8 01 01 02 12 00 00 00 01] + Length = [0b] - 11 octets + U8:4 = 1111 = [f] + U8:1 odd/even indicator = [0] - even number of identity digits + U8:3 Type of identity = [110] - GUTI + plmn = [02 f8 01] - 20810 + U16 mmegroupid = [01 02] + U8 mmecode = [12] + U32 mtmsi = [00 00 00 01] +*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.h b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.h new file mode 100644 index 0000000000..7d8541ef58 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_process.h @@ -0,0 +1,70 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_process.h + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem AS message processing + +Author Frederic Maurel + +Description Defines functions executed by the Access-Stratum sublayer + upon receiving AS messages from the Non-Access-Stratum. + +*****************************************************************************/ + +#ifndef __AS_PROCESS_H__ +#define __AS_PROCESS_H__ + +#include "as_message.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Functions used to process messages received from the UE NAS process + * ----------------------------------------------------------------------------- + */ + +int process_cell_info_req(int msg_id, const cell_info_req_t* req, + cell_info_cnf_t* cnf); +int process_nas_establish_req(int msg_id, const nas_establish_req_t* req, + nas_establish_ind_t* ind, nas_establish_cnf_t* cnf); +int process_ul_info_transfer_req(int msg_id, const ul_info_transfer_req_t* req, + ul_info_transfer_ind_t* ind, ul_info_transfer_cnf_t* cnf); +int process_nas_release_req(int msg_id, const nas_release_req_t* req); + +/* + * ----------------------------------------------------------------------------- + * Functions used to process messages received from the MME NAS process + * ----------------------------------------------------------------------------- + */ + +int process_nas_establish_rsp(int msg_id, const nas_establish_rsp_t* rsp, + nas_establish_cnf_t* cnf); +int process_dl_info_transfer_req(int msg_id, const dl_info_transfer_req_t* req, + dl_info_transfer_ind_t* ind, dl_info_transfer_cnf_t* cnf); +int process_nas_release_ind(int msg_id, const nas_release_req_t* req, + nas_release_ind_t* ind); + +#endif /* __AS_PROCESS_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator.c new file mode 100644 index 0000000000..c11f816ab1 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator.c @@ -0,0 +1,630 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_simulator.c + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Main process + +Author Frederic Maurel + +Description Implements the Access-Stratum simulator operating between + the Non-Access-Stratum running in the UE at the user side + and the Non-Access-Stratum running in the MME at the network + side for testing purpose. + +*****************************************************************************/ + +#include "as_simulator_parser.h" + +#include "as_data.h" +#include "as_process.h" + +#include "commonDef.h" +#include "socket.h" + +#include "nas_log.h" + +#include <stdio.h> // printf, perror, snprintf +#include <errno.h> // errno +#include <netdb.h> // gai_strerror +#include <stdlib.h> // exit +#include <string.h> // memset +#include <poll.h> // poll +#include <signal.h> // sigaction +#include <pthread.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#define SLEEP_TIMEOUT 1000 /* 1 second */ + +#define AS_SIMULATOR_NO_TRANSFER (0) +#define AS_SIMULATOR_TRANSFER_TO_UE (1 << 0) +#define AS_SIMULATOR_TRANSFER_TO_MME (1 << 1) + +/* + * Direction of the message to be transfered to the UE NAS process + */ +static UInt8_t _as_simulator_ue_transfer = AS_SIMULATOR_NO_TRANSFER; + +/* + * Direction of the message to be transfered to the MME NAS process + */ +static UInt8_t _as_simulator_mme_transfer = AS_SIMULATOR_NO_TRANSFER; + +/* + * Size of the message to be transfered to the UE NAS process + */ +static int _as_simulator_ue_size = 0; + +/* + * Size of the message to be transfered to the MME NAS process + */ +static int _as_simulator_mme_size = 0; + +/* + * String buffer used to send/receive messages to/from the UE NAS process + */ +#define AS_SIMULATOR_UE_BUFFER_SIZE 1024 +static char _as_simulator_ue_buffer [AS_SIMULATOR_UE_BUFFER_SIZE]; + +/* + * String buffer used to send/receive messages to/from the MME NAS process + */ +#define AS_SIMULATOR_MME_BUFFER_SIZE 1024 +static char _as_simulator_mme_buffer [AS_SIMULATOR_MME_BUFFER_SIZE]; + +/* + * The connection endpoint used for communication with the UE NAS process + */ +static socket_id_t * _as_simulator_ue_sid = NULL; + +/* + * The connection endpoint used for communication with the MME NAS process + */ +static socket_id_t * _as_simulator_mme_sid = NULL; + +/* + * UE NAS process connection manager's running indicator + */ +static int _as_simulator_ue_is_running = FALSE; + +/* + * MME NAS process connection manager's running indicator + */ +static int _as_simulator_mme_is_running = FALSE; + +static int _set_signal_handler(int signal, void (handler)(int)); +static void _signal_handler(int signal_number); + +static void* _as_simulator_ue_mngr(void*); +static void* _as_simulator_mme_mngr(void*); + +static int _as_simulator_ue_process(int msg_id, as_message_t* msg); +static int _as_simulator_mme_process(int msg_id, as_message_t* msg); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * RRC simulator main process + * ----------------------------------------------------------------------------- + */ +int main (int argc, const char* argv[]) +{ + /* + * Get the command line options + */ + if ( as_simulator_parser_get_options(argc, argv) != RETURNok ) + { + as_simulator_parser_print_usage(); + exit(EXIT_FAILURE); + } + const char* uhost = as_simulator_parser_get_uhost(); + const char* uport = as_simulator_parser_get_uport(); + const char* mhost = as_simulator_parser_get_mhost(); + const char* mport = as_simulator_parser_get_mport(); + + log_init(0x2f); + + /* + * Initialize the communication channel to the UE NAS process + */ + _as_simulator_ue_sid = socket_udp_open(SOCKET_SERVER, uhost, uport); + if (_as_simulator_ue_sid == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + printf("ERROR\t: socket_udp_open() failed: %s\n", error); + exit(EXIT_FAILURE); + } + printf("INFO\t: %s - The RRC Simulator is now connected to %s/%s (%d)\n", + __FUNCTION__, uhost, uport, socket_get_fd(_as_simulator_ue_sid)); + + /* + * Initialize the communication channel to the MME NAS process + */ + _as_simulator_mme_sid = socket_udp_open(SOCKET_CLIENT, mhost, mport); + if (_as_simulator_mme_sid == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + printf("ERROR\t: socket_udp_open() failed: %s\n", error); + socket_close(_as_simulator_ue_sid); + exit(EXIT_FAILURE); + } + printf("INFO\t: %s - The RRC Simulator is now connected to %s/%s (%d)\n", + __FUNCTION__, mhost, mport, socket_get_fd(_as_simulator_mme_sid)); + + MSCGEN("[MSC_NEW][%s][AS=%s]\n", getTime(), _as_id); + + /* + * Set up signal handler + */ + (void) _set_signal_handler(SIGINT, _signal_handler); + (void) _set_signal_handler(SIGTERM, _signal_handler); + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + /* + * Start thread use to manage the connection endpoint with the + * UE NAS process + */ + pthread_t ue_mngr; + if ( pthread_create (&ue_mngr, &attr, _as_simulator_ue_mngr, NULL) != 0 ) + { + perror("ERROR\t: Failed to create the UE management thread\n"); + socket_close(_as_simulator_ue_sid); + socket_close(_as_simulator_mme_sid); + exit(EXIT_FAILURE); + } + + /* + * Start thread use to manage the connection endpoint with the + * MME NAS process + */ + pthread_t mme_mngr; + if ( pthread_create (&mme_mngr, &attr, _as_simulator_mme_mngr, NULL) != 0 ) + { + perror("ERROR\t: Failed to create the MME management thread\n"); + socket_close(_as_simulator_ue_sid); + socket_close(_as_simulator_mme_sid); + exit(EXIT_FAILURE); + } + pthread_attr_destroy(&attr); + + /* + * Suspend execution of the main process until connection + * managers are running + */ + poll(NULL, 0, SLEEP_TIMEOUT); + while (_as_simulator_ue_is_running && _as_simulator_mme_is_running) + { + poll(NULL, 0, SLEEP_TIMEOUT); + } + + /* + * Termination cleanup + */ + printf("INFO\t: %s - Closing UE's connection endpoint %d\n", + __FUNCTION__, socket_get_fd(_as_simulator_ue_sid)); + socket_close(_as_simulator_ue_sid); + printf("INFO\t: %s - Closing MME's connection endpoint %d\n", + __FUNCTION__, socket_get_fd(_as_simulator_mme_sid)); + socket_close(_as_simulator_mme_sid); + + printf("INFO\t: %s - RRC simulator exited\n", __FUNCTION__); + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Signal handler setup function + * ----------------------------------------------------------------------------- + */ +static int _set_signal_handler(int signal, void (handler)(int)) +{ + struct sigaction act; + + /* Initialize signal set */ + (void) memset (&act, 0, sizeof (act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + /* Initialize signal handler */ + act.sa_handler = handler; + if ( sigaction (signal, &act, 0) < 0 ) { + return RETURNerror; + } + + return RETURNok; +} + +/* + * ----------------------------------------------------------------------------- + * Signal handler + * ----------------------------------------------------------------------------- + */ +static void _signal_handler(int signal_number) +{ + printf("\nWARNING\t: %s - Signal %d received\n", __FUNCTION__, + signal_number); + _as_simulator_ue_is_running = FALSE; + _as_simulator_mme_is_running = FALSE; +} + +/* + * ----------------------------------------------------------------------------- + * UE connection manager + * ----------------------------------------------------------------------------- + */ +static void* _as_simulator_ue_mngr(void* args) +{ + int msg_id; + as_message_t msg; + + _as_simulator_ue_is_running = TRUE; + + printf("INFO\t: %s - UE connection manager started\n", __FUNCTION__); + + MSCGEN("[MSC_NEW][%s][NAS-UE=%s]\n", getTime(), _ue_id); + + /* Receiving loop */ + while (_as_simulator_ue_is_running) + { + int rc, rbytes, sbytes; + + /* Receive message from the UE NAS process */ + rbytes = socket_recv(_as_simulator_ue_sid, _as_simulator_ue_buffer, + AS_SIMULATOR_UE_BUFFER_SIZE); + if (rbytes == RETURNerror) { + perror("ERROR\t: socket_recv() failed"); + break; + } + + /* Decode the received message */ + msg_id = as_message_decode(_as_simulator_ue_buffer, &msg, rbytes); + if (msg_id == RETURNerror) { + printf("WARNING\t: %s - Failed to decode AS message\n", + __FUNCTION__); + continue; + } + + /* Reset the size of the message to be transfered */ + _as_simulator_ue_size = 0; + _as_simulator_mme_size = 0; + + /* Process the received message */ + rc = _as_simulator_ue_process(msg_id, &msg); + if (rc != RETURNok) { + printf("WARNING\t: %s - Failed to process AS message (0x%x)\n", + __FUNCTION__, msg_id); + continue; + } + + if (_as_simulator_ue_size > 0) { + /* Return the response message to the UE NAS process */ + sbytes = socket_send(_as_simulator_ue_sid, + _as_simulator_ue_buffer, + _as_simulator_ue_size); + if (sbytes == RETURNerror) { + perror("ERROR\t: socket_send() failed"); + break; + } + } + + if (_as_simulator_mme_size > 0) { + /* Forward the received message to the MME NAS process */ + sbytes = socket_send(_as_simulator_mme_sid, + _as_simulator_mme_buffer, + _as_simulator_mme_size); + if (sbytes == RETURNerror) { + perror("ERROR\t: socket_send() failed"); + break; + } + } + } + + /* Close the connection to the network sublayer */ + _as_simulator_ue_is_running = FALSE; + printf("ERROR\t: The UE connection manager exited\n"); + return (NULL); +} + +/* + * ----------------------------------------------------------------------------- + * MME connection manager + * ----------------------------------------------------------------------------- + */ +static void* _as_simulator_mme_mngr(void* args) +{ + int msg_id; + as_message_t msg; + + _as_simulator_mme_is_running = TRUE; + + printf("INFO\t: %s - MME connection manager started\n", __FUNCTION__); + + MSCGEN("[MSC_NEW][%s][NAS-MME=%s]\n", getTime(), _mme_id); + + /* Receiving loop */ + while (_as_simulator_mme_is_running) + { + int rc, rbytes, sbytes; + + /* Receive message from the MME NAS process */ + rbytes = socket_recv(_as_simulator_mme_sid, _as_simulator_mme_buffer, + AS_SIMULATOR_MME_BUFFER_SIZE); + if (rbytes == RETURNerror) { + perror("ERROR\t: socket_recv() failed"); + break; + } + + /* Decode the received message */ + msg_id = as_message_decode(_as_simulator_mme_buffer, &msg, rbytes); + if (msg_id == RETURNerror) { + printf("ERROR\t: %s - as_message_decode() failed\n", __FUNCTION__); + continue; + } + + /* Reset the size of the message to be transfered */ + _as_simulator_ue_size = 0; + _as_simulator_mme_size = 0; + + /* Process the received message */ + rc = _as_simulator_mme_process(msg_id, &msg); + if (rc != RETURNok) { + printf("WARNING\t: %s - Failed to process AS message (0x%x)\n", + __FUNCTION__, msg_id); + continue; + } + + if (_as_simulator_mme_size > 0) { + /* Return the response message to the MME NAS process */ + sbytes = socket_send(_as_simulator_mme_sid, + _as_simulator_mme_buffer, + _as_simulator_mme_size); + if (sbytes == RETURNerror) { + perror("ERROR\t: socket_send() failed"); + break; + } + } + + if (_as_simulator_ue_size > 0) { + /* Forward the received message to the UE NAS process */ + sbytes = socket_send(_as_simulator_ue_sid, + _as_simulator_ue_buffer, + _as_simulator_ue_size); + if (sbytes == RETURNerror) { + perror("ERROR\t: socket_send() failed"); + break; + } + } + } + + /* Close the connection to the network sublayer */ + _as_simulator_mme_is_running = FALSE; + printf("ERROR\t: %s - The MME connection manager exited\n", __FUNCTION__); + return (NULL); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to process messages received from the UE NAS process + * ----------------------------------------------------------------------------- + */ +static int _as_simulator_ue_process(int msg_id, as_message_t* msg) +{ + int rc = RETURNok; + + as_message_t cnf; + as_message_t ind; + + printf("\nINFO\t: %s - Received AS message 0x%x from UE NAS process\n", + __FUNCTION__, msg_id); + + _as_simulator_ue_transfer = AS_SIMULATOR_NO_TRANSFER; + + memset(&cnf, 0, sizeof(as_message_t)); + memset(&ind, 0, sizeof(as_message_t)); + + switch (msg_id) + { + case AS_CELL_INFO_REQ: + cnf.msgID = process_cell_info_req(msg_id, + &msg->msg.cell_info_req, + &cnf.msg.cell_info_cnf); + /* Return confirm message to the UE */ + _as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + break; + + case AS_NAS_ESTABLISH_REQ: + ind.msgID = process_nas_establish_req(msg_id, + &msg->msg.nas_establish_req, + &ind.msg.nas_establish_ind, + &cnf.msg.nas_establish_cnf); + if (ind.msgID) { + /* Forward indication message to the MME */ + _as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_MME; + } + /* Return confirm message to the UE */ + cnf.msgID = AS_NAS_ESTABLISH_CNF; + _as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + break; + + case AS_UL_INFO_TRANSFER_REQ: + ind.msgID = process_ul_info_transfer_req(msg_id, + &msg->msg.ul_info_transfer_req, + &ind.msg.ul_info_transfer_ind, + &cnf.msg.ul_info_transfer_cnf); + if (ind.msgID) { + /* Forward indication message to the MME */ + _as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_MME; + } + /* Return confirm message to the UE */ + cnf.msgID = AS_UL_INFO_TRANSFER_CNF; + _as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + break; + + case AS_NAS_RELEASE_REQ: + ind.msgID = process_nas_release_req(msg_id, + &msg->msg.nas_release_req); + break; + + default: + printf("WARNING\t: %s - AS message is not valid (0x%x)\n", + __FUNCTION__, msg_id); + rc = RETURNerror; + break; + } + + if (_as_simulator_ue_transfer & AS_SIMULATOR_TRANSFER_TO_UE) { + /* Encode the message confirmation returned to the NAS running + * at the UE side */ + _as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer, &cnf, + AS_SIMULATOR_UE_BUFFER_SIZE); + if (_as_simulator_ue_size == RETURNerror) { + _as_simulator_ue_size = 0; + rc = RETURNerror; + } + } + + if (_as_simulator_ue_transfer & AS_SIMULATOR_TRANSFER_TO_MME) { + /* Encode the message indication forwarded to the NAS running + * at the MME side */ + _as_simulator_mme_size = as_message_encode(_as_simulator_mme_buffer, &ind, + AS_SIMULATOR_MME_BUFFER_SIZE); + if (_as_simulator_mme_size == RETURNerror) { + _as_simulator_mme_size = 0; + rc = RETURNerror; + } + } + + return (rc); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to process messages received from the MME NAS process + * ----------------------------------------------------------------------------- + */ +static int _as_simulator_mme_process(int msg_id, as_message_t* msg) +{ + int rc = RETURNok; + + as_message_t cnf; + as_message_t ind; + + printf("\nINFO\t: %s - Received AS message 0x%x from MME NAS process\n", + __FUNCTION__, msg_id); + + _as_simulator_mme_transfer = AS_SIMULATOR_NO_TRANSFER; + + memset(&cnf, 0, sizeof(as_message_t)); + memset(&ind, 0, sizeof(as_message_t)); + + switch (msg_id) + { + case AS_NAS_ESTABLISH_RSP: + cnf.msgID = process_nas_establish_rsp(msg_id, + &msg->msg.nas_establish_rsp, + &cnf.msg.nas_establish_cnf); + if (cnf.msgID) { + /* Forward confirm message to the UE */ + _as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + } + break; + + case AS_DL_INFO_TRANSFER_REQ: + ind.msgID = process_dl_info_transfer_req(msg_id, + &msg->msg.dl_info_transfer_req, + &ind.msg.dl_info_transfer_ind, + &cnf.msg.dl_info_transfer_cnf); + if (ind.msgID) { + /* Forward indication message to the UE */ + _as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + } + /* Return confirm message to the MME */ + cnf.msgID = AS_DL_INFO_TRANSFER_CNF; + _as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_MME; + break; + + case AS_NAS_RELEASE_REQ: + ind.msgID = process_nas_release_ind(msg_id, + &msg->msg.nas_release_req, + &ind.msg.nas_release_ind); + /* Forward indication message to the UE */ + _as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE; + break; + + default: + printf("WARNING\t: %s - AS message is not valid (0x%x)\n", + __FUNCTION__, msg_id); + rc = RETURNerror; + break; + } + + if (_as_simulator_mme_transfer & AS_SIMULATOR_TRANSFER_TO_UE) { + if (ind.msgID > 0) { + /* Encode the message indication forwarded to the NAS running + * at the UE side */ + _as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer, + &ind, AS_SIMULATOR_UE_BUFFER_SIZE); + } + else if (cnf.msgID > 0) { + /* Encode the message confirmation forwarded to the NAS running + * at the UE side */ + _as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer, + &cnf, AS_SIMULATOR_UE_BUFFER_SIZE); + } + if (_as_simulator_ue_size == RETURNerror) { + _as_simulator_ue_size = 0; + rc = RETURNerror; + } + } + + if (_as_simulator_mme_transfer & AS_SIMULATOR_TRANSFER_TO_MME) { + /* Encode the message confirmation returned to the NAS running + * at the MME side */ + _as_simulator_mme_size = as_message_encode(_as_simulator_mme_buffer, + &cnf, AS_SIMULATOR_MME_BUFFER_SIZE); + if (_as_simulator_mme_size == RETURNerror) { + _as_simulator_mme_size = 0; + rc = RETURNerror; + } + } + + return (rc); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.c new file mode 100644 index 0000000000..b8cb4318a7 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.c @@ -0,0 +1,206 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_simulator_parser.c + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the AS Simulator process + +*****************************************************************************/ + +#include "as_simulator_parser.h" + +#include "parser.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * Identifiers of the AS Simulator command line options + */ +enum +{ + AS_SIMULATOR_PARSER_UE_HOST, /* UE process hostname */ + AS_SIMULATOR_PARSER_UE_PORT, /* UE process port number */ + AS_SIMULATOR_PARSER_MME_HOST, /* MME process hostname */ + AS_SIMULATOR_PARSER_MME_PORT, /* MME process port number */ + AS_SIMULATOR_PARSER_NB_OPTIONS +}; + +/* -------------------------------------------------------------- + * Definition of the internal AS Simulator command line structure + * -------------------------------------------------------------- + * The command line is defined with a name (default is "ASprocess" + * but it will be replaced by the command name actually used at + * runtime), a number of options and the list of options. + * An option is defined with a name, an argument following the name, + * the usage displayed by the usage function and a default value. + */ +static parser_command_line_t asParserCommandLine = { + "ASprocess", /* Command name */ + AS_SIMULATOR_PARSER_NB_OPTIONS, /* Number of options */ + { /* Command line options */ + {"-uhost", "<uhost>", "UE process hostname\t\t", + AS_SIMULATOR_PARSER_DEFAULT_UE_HOSTNAME}, + {"-uport", "<uport>", "UE process port number\t\t", + AS_SIMULATOR_PARSER_DEFAULT_UE_PORT_NUMBER}, + {"-mhost", "<mhost>", "MME process hostname\t\t", + AS_SIMULATOR_PARSER_DEFAULT_MME_HOSTNAME}, + {"-mport", "<mport>", "MME process port number\t\t", + AS_SIMULATOR_PARSER_DEFAULT_MME_PORT_NUMBER}, + } +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_print_usage() ** + ** ** + ** Description: Displays the command line options used to run the AS ** + ** Simulator process ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline void as_simulator_parser_print_usage(void) +{ + parser_print_usage(&asParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_options() ** + ** ** + ** Description: Gets the command line options used to run the AS ** + ** Simulator process ** + ** ** + ** Inputs: argc: Number of options ** + ** argv: Pointer to the list of options ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: asParserCommandLine.options ** + ** ** + ***************************************************************************/ +inline int as_simulator_parser_get_options(int argc, const char** argv) +{ + return parser_get_options(argc, argv, &asParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_nb_options() ** + ** ** + ** Description: Returns the number of the command line options used to ** + ** run the As Simulator process ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: Number of command line options ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline int as_simulator_parser_get_nb_options(void) +{ + return asParserCommandLine.nb_options; +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_uhost() ** + ** ** + ** Description: Returns the value of the UE process hostname ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: Value of the remote hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* as_simulator_parser_get_uhost(void) +{ + return asParserCommandLine.options[AS_SIMULATOR_PARSER_UE_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_uport() ** + ** ** + ** Description: Returns the value of the UE process port number ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: Value of the remote port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* as_simulator_parser_get_uport(void) +{ + return asParserCommandLine.options[AS_SIMULATOR_PARSER_UE_PORT].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_mhost() ** + ** ** + ** Description: Returns the value of the MME process hostname ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: Value of the remote hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* as_simulator_parser_get_mhost(void) +{ + return asParserCommandLine.options[AS_SIMULATOR_PARSER_MME_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: as_simulator_parser_get_mport() ** + ** ** + ** Description: Returns the value of the MME process port number ** + ** ** + ** Inputs: None ** + ** Others: asParserCommandLine.options ** + ** ** + ** Outputs: Return: Value of the remote port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* as_simulator_parser_get_mport(void) +{ + return asParserCommandLine.options[AS_SIMULATOR_PARSER_MME_PORT].pvalue; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.h b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.h new file mode 100644 index 0000000000..aa54e791c4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/as_simulator_parser.h @@ -0,0 +1,61 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source as_simulator_parser.h + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the AS Simulator process + +*****************************************************************************/ + +#ifndef __AS_SIMULATOR_PARSER_H__ +#define __AS_SIMULATOR_PARSER_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* UE process default hostname */ +#define AS_SIMULATOR_PARSER_DEFAULT_UE_HOSTNAME "localhost" + +/* MME process default hostname */ +#define AS_SIMULATOR_PARSER_DEFAULT_MME_HOSTNAME "localhost" + +/* UE process default port number */ +#define AS_SIMULATOR_PARSER_DEFAULT_UE_PORT_NUMBER "12000" + +/* MME process default port number */ +#define AS_SIMULATOR_PARSER_DEFAULT_MME_PORT_NUMBER "14000" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void as_simulator_parser_print_usage(void); +int as_simulator_parser_get_options(int argc, const char** argv); + +int as_simulator_parser_get_nb_options(void); +const char* as_simulator_parser_get_uhost(void); +const char* as_simulator_parser_get_uport(void); +const char* as_simulator_parser_get_mhost(void); +const char* as_simulator_parser_get_mport(void); + +#endif /* __AS_SIMULATOR_PARSER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.c new file mode 100644 index 0000000000..07cd019600 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.c @@ -0,0 +1,919 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_data.c + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Non-Access-Stratum data + +Author Frederic Maurel + +Description Defines constants and functions used by the AS simulator + process. + +*****************************************************************************/ + +#include "nas_data.h" + +#include "emm_msgDef.h" +#include "esm_msgDef.h" + +#include "emm_cause.h" +#include "esm_cause.h" + +#include <stdio.h> // snprintf + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +static ssize_t imsiIdentity(char* buffer, size_t len, + const ImsiMobileIdentity_t* ident); +static ssize_t imeiIdentity(char* buffer, size_t len, + const ImeiMobileIdentity_t* ident); +static ssize_t tmsiIdentity(char* buffer, size_t len, + const TmsiMobileIdentity_t* ident); +static ssize_t tmgiIdentity(char* buffer, size_t len, + const TmgiMobileIdentity_t* ident); + +static const char* timerUnit(int unit); + +static ssize_t ipv4Addr(char* buffer, size_t len, const OctetString* addr); +static ssize_t ipv6Addr(char* buffer, size_t len, const OctetString* addr); +static ssize_t ipv4v6Addr(char* buffer, size_t len, const OctetString* addr); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Return EMM message type + * ----------------------------------------------------------------------------- + */ +const char* emmMsgType(int type) +{ + if (type == ATTACH_REQUEST) { + return "ATTACH_REQUEST"; + } else if (type == ATTACH_ACCEPT) { + return "ATTACH_ACCEPT"; + } else if (type == ATTACH_COMPLETE) { + return "ATTACH_COMPLETE"; + } else if (type == ATTACH_REJECT) { + return "ATTACH_REJECT"; + } else if (type == DETACH_REQUEST) { + return "DETACH_REQUEST"; + } else if (type == DETACH_ACCEPT) { + return "DETACH_ACCEPT"; + } else if (type == TRACKING_AREA_UPDATE_REQUEST) { + return "TRACKING_AREA_UPDATE_REQUEST"; + } else if (type == TRACKING_AREA_UPDATE_ACCEPT) { + return "TRACKING_AREA_UPDATE_ACCEPT"; + } else if (type == TRACKING_AREA_UPDATE_COMPLETE) { + return "TRACKING_AREA_UPDATE_COMPLETE"; + } else if (type == TRACKING_AREA_UPDATE_REJECT) { + return "TRACKING_AREA_UPDATE_REJECT"; + } else if (type == EXTENDED_SERVICE_REQUEST) { + return "EXTENDED_SERVICE_REQUEST"; + } else if (type == SERVICE_REJECT) { + return "SERVICE_REJECT"; + } else if (type == GUTI_REALLOCATION_COMMAND) { + return "GUTI_REALLOCATION_COMMAND"; + } else if (type == GUTI_REALLOCATION_COMPLETE) { + return "GUTI_REALLOCATION_COMPLETE"; + } else if (type == AUTHENTICATION_REQUEST) { + return "AUTHENTICATION_REQUEST"; + } else if (type == AUTHENTICATION_RESPONSE) { + return "AUTHENTICATION_RESPONSE"; + } else if (type == AUTHENTICATION_REJECT) { + return "AUTHENTICATION_REJECT"; + } else if (type == AUTHENTICATION_FAILURE) { + return "AUTHENTICATION_FAILURE"; + } else if (type == IDENTITY_REQUEST) { + return "IDENTITY_REQUEST"; + } else if (type == IDENTITY_RESPONSE) { + return "IDENTITY_RESPONSE"; + } else if (type == SECURITY_MODE_COMMAND) { + return "SECURITY_MODE_COMMAND"; + } else if (type == SECURITY_MODE_COMPLETE) { + return "SECURITY_MODE_COMPLETE"; + } else if (type == SECURITY_MODE_REJECT) { + return "SECURITY_MODE_REJECT"; + } else if (type == EMM_STATUS) { + return "EMM_STATUS"; + } else if (type == EMM_INFORMATION) { + return "EMM_INFORMATION"; + } else if (type == DOWNLINK_NAS_TRANSPORT) { + return "DOWNLINK_NAS_TRANSPORT"; + } else if (type == UPLINK_NAS_TRANSPORT) { + return "UPLINK_NAS_TRANSPORT"; + } else if (type == CS_SERVICE_NOTIFICATION) { + return "CS_SERVICE_NOTIFICATION"; + } else if (type == SERVICE_REQUEST) { + return "SERVICE_REQUEST"; + } else { + return "Unknown EMM message type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return ESM message type + * ----------------------------------------------------------------------------- + */ +const char* esmMsgType(int type) +{ + if (type == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST) { + return "ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST"; + } else if (type == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT) { + return "ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT"; + } else if (type == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT) { + return "ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT"; + } else if (type == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST) { + return "ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST"; + } else if (type == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT) { + return "ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT"; + } else if (type == ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT) { + return "ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT"; + } else if (type == MODIFY_EPS_BEARER_CONTEXT_REQUEST) { + return "MODIFY_EPS_BEARER_CONTEXT_REQUEST"; + } else if (type == MODIFY_EPS_BEARER_CONTEXT_ACCEPT) { + return "MODIFY_EPS_BEARER_CONTEXT_ACCEPT"; + } else if (type == MODIFY_EPS_BEARER_CONTEXT_REJECT) { + return "MODIFY_EPS_BEARER_CONTEXT_REJECT"; + } else if (type == DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST) { + return "DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST"; + } else if (type == DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT) { + return "DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT"; + } else if (type == PDN_CONNECTIVITY_REQUEST) { + return "PDN_CONNECTIVITY_REQUEST"; + } else if (type == PDN_CONNECTIVITY_REJECT) { + return "PDN_CONNECTIVITY_REJECT"; + } else if (type == PDN_DISCONNECT_REQUEST) { + return "PDN_DISCONNECT_REQUEST"; + } else if (type == PDN_DISCONNECT_REJECT) { + return "PDN_DISCONNECT_REJECT"; + } else if (type == BEARER_RESOURCE_ALLOCATION_REQUEST) { + return "BEARER_RESOURCE_ALLOCATION_REQUEST"; + } else if (type == BEARER_RESOURCE_ALLOCATION_REJECT) { + return "BEARER_RESOURCE_ALLOCATION_REJECT"; + } else if (type == BEARER_RESOURCE_MODIFICATION_REQUEST) { + return "BEARER_RESOURCE_MODIFICATION_REQUEST"; + } else if (type == BEARER_RESOURCE_MODIFICATION_REJECT) { + return "BEARER_RESOURCE_MODIFICATION_REJECT"; + } else if (type == ESM_INFORMATION_REQUEST) { + return "ESM_INFORMATION_REQUEST"; + } else if (type == ESM_INFORMATION_RESPONSE) { + return "ESM_INFORMATION_RESPONSE"; + } else if (type == ESM_STATUS) { + return "ESM_STATUS"; + } else { + return "Unknown ESM message type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return EMM cause code + * ----------------------------------------------------------------------------- + */ +const char* emmCauseCode(EmmCause code) +{ + if (code == EMM_CAUSE_SUCCESS) { + return "SUCCESS"; + } else if (code == EMM_CAUSE_IMSI_UNKNOWN_IN_HSS) { + return "IMSI_UNKNOWN_IN_HSS"; + } else if (code == EMM_CAUSE_ILLEGAL_UE) { + return "ILLEGAL_UE"; + } else if (code == EMM_CAUSE_ILLEGAL_ME) { + return "ILLEGAL_ME"; + } else if (code == EMM_CAUSE_INVALID_UE) { + return "INVALID_UE"; + } else if (code == EMM_CAUSE_IMPLICITLY_DETACHED) { + return "IMPLICITLY_DETACHED"; + } else if (code == EMM_CAUSE_IMEI_NOT_ACCEPTED) { + return "IMEI_NOT_ACCEPTED"; + } else if (code == EMM_CAUSE_EPS_NOT_ALLOWED) { + return "EPS_NOT_ALLOWED"; + } else if (code == EMM_CAUSE_BOTH_NOT_ALLOWED) { + return "BOTH_NOT_ALLOWED"; + } else if (code == EMM_CAUSE_PLMN_NOT_ALLOWED) { + return "PLMN_NOT_ALLOWED"; + } else if (code == EMM_CAUSE_TA_NOT_ALLOWED) { + return "TA_NOT_ALLOWED"; + } else if (code == EMM_CAUSE_ROAMING_NOT_ALLOWED) { + return "ROAMING_NOT_ALLOWED"; + } else if (code == EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN) { + return "EPS_NOT_ALLOWED_IN_PLMN"; + } else if (code == EMM_CAUSE_NO_SUITABLE_CELLS) { + return "NO_SUITABLE_CELLS"; + } else if (code == EMM_CAUSE_CSG_NOT_AUTHORIZED) { + return "CSG_NOT_AUTHORIZED"; + } else if (code == EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN) { + return "NOT_AUTHORIZED_IN_PLMN"; + } else if (code == EMM_CAUSE_NO_EPS_BEARER_CTX_ACTIVE) { + return "NO_EPS_BEARER_CTX_ACTIVE"; + } else if (code == EMM_CAUSE_MSC_NOT_REACHABLE) { + return "MSC_NOT_REACHABLE"; + } else if (code == EMM_CAUSE_NETWORK_FAILURE) { + return "NETWORK_FAILURE"; + } else if (code == EMM_CAUSE_CS_DOMAIN_NOT_AVAILABLE) { + return "CS_DOMAIN_NOT_AVAILABLE"; + } else if (code == EMM_CAUSE_ESM_FAILURE) { + return "ESM_FAILURE"; + } else if (code == EMM_CAUSE_MAC_FAILURE) { + return "MAC_FAILURE"; + } else if (code == EMM_CAUSE_SYNCH_FAILURE) { + return "SYNCH_FAILURE"; + } else if (code == EMM_CAUSE_CONGESTION) { + return "CONGESTION"; + } else if (code == EMM_CAUSE_UE_SECURITY_MISMATCH) { + return "UE_SECURITY_MISMATCH"; + } else if (code == EMM_CAUSE_SECURITY_MODE_REJECTED) { + return "SECURITY_MODE_REJECTED"; + } else if (code == EMM_CAUSE_NON_EPS_AUTH_UNACCEPTABLE) { + return "NON_EPS_AUTH_UNACCEPTABLE"; + } else if (code == EMM_CAUSE_CS_SERVICE_NOT_AVAILABLE) { + return "CS_SERVICE_NOT_AVAILABLE"; + } else if (code == EMM_CAUSE_SEMANTICALLY_INCORRECT) { + return "SEMANTICALLY_INCORRECT"; + } else if (code == EMM_CAUSE_INVALID_MANDATORY_INFO) { + return "INVALID_MANDATORY_INFO"; + } else if (code == EMM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED) { + return "MESSAGE_TYPE_NOT_IMPLEMENTED"; + } else if (code == EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE) { + return "MESSAGE_TYPE_NOT_COMPATIBLE"; + } else if (code == EMM_CAUSE_IE_NOT_IMPLEMENTED) { + return "IE_NOT_IMPLEMENTED"; + } else if (code == EMM_CAUSE_CONDITIONAL_IE_ERROR) { + return "CONDITIONAL_IE_ERROR"; + } else if (code == EMM_CAUSE_MESSAGE_NOT_COMPATIBLE) { + return "MESSAGE_NOT_COMPATIBLE"; + } else if (code == EMM_CAUSE_PROTOCOL_ERROR) { + return "PROTOCOL_ERROR"; + } else { + return "Unknown EMM cause code"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return EMM cause code + * ----------------------------------------------------------------------------- + */ +const char* esmCauseCode(EsmCause code) +{ + if (code == ESM_CAUSE_SUCCESS) { + return "SUCCESS"; + } else if (code == ESM_CAUSE_OPERATOR_DETERMINED_BARRING) { + return "OPERATOR_DETERMINED_BARRING"; + } else if (code == ESM_CAUSE_INSUFFICIENT_RESOURCES) { + return "INSUFFICIENT_RESOURCES"; + } else if (code == ESM_CAUSE_UNKNOWN_ACCESS_POINT_NAME) { + return "UNKNOWN_ACCESS_POINT_NAME"; + } else if (code == ESM_CAUSE_UNKNOWN_PDN_TYPE) { + return "UNKNOWN_PDN_TYPE"; + } else if (code == ESM_CAUSE_USER_AUTHENTICATION_FAILED) { + return "USER_AUTHENTICATION_FAILED"; + } else if (code == ESM_CAUSE_REQUEST_REJECTED_BY_GW) { + return "REQUEST_REJECTED_BY_GW"; + } else if (code == ESM_CAUSE_REQUEST_REJECTED_UNSPECIFIED) { + return "REQUEST_REJECTED_UNSPECIFIED"; + } else if (code == ESM_CAUSE_SERVICE_OPTION_NOT_SUPPORTED) { + return "SERVICE_OPTION_NOT_SUPPORTED"; + } else if (code == ESM_CAUSE_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED) { + return "REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED"; + } else if (code == ESM_CAUSE_SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER) { + return "SERVICE_OPTION_TEMPORARILY_OUT_OF_ORDER"; + } else if (code == ESM_CAUSE_PTI_ALREADY_IN_USE) { + return "PTI_ALREADY_IN_USE"; + } else if (code == ESM_CAUSE_REGULAR_DEACTIVATION) { + return "REGULAR_DEACTIVATION"; + } else if (code == ESM_CAUSE_EPS_QOS_NOT_ACCEPTED) { + return "EPS_QOS_NOT_ACCEPTED"; + } else if (code == ESM_CAUSE_NETWORK_FAILURE) { + return "NETWORK_FAILURE"; + } else if (code == ESM_CAUSE_REACTIVATION_REQUESTED) { + return "REACTIVATION_REQUESTED"; + } else if (code == ESM_CAUSE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION) { + return "SEMANTIC_ERROR_IN_THE_TFT_OPERATION"; + } else if (code == ESM_CAUSE_SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION) { + return "SYNTACTICAL_ERROR_IN_THE_TFT_OPERATION"; + } else if (code == ESM_CAUSE_INVALID_EPS_BEARER_IDENTITY) { + return "INVALID_EPS_BEARER_IDENTITY"; + } else if (code == ESM_CAUSE_SEMANTIC_ERRORS_IN_PACKET_FILTER) { + return "SEMANTIC_ERRORS_IN_PACKET_FILTER"; + } else if (code == ESM_CAUSE_SYNTACTICAL_ERROR_IN_PACKET_FILTER) { + return "SYNTACTICAL_ERROR_IN_PACKET_FILTER"; + } else if (code == ESM_CAUSE_PTI_MISMATCH) { + return "PTI_MISMATCH"; + } else if (code == ESM_CAUSE_LAST_PDN_DISCONNECTION_NOT_ALLOWED) { + return "LAST_PDN_DISCONNECTION_NOT_ALLOWED"; + } else if (code == ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED) { + return "PDN_TYPE_IPV4_ONLY_ALLOWED"; + } else if (code == ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED) { + return "PDN_TYPE_IPV6_ONLY_ALLOWED"; + } else if (code == ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED) { + return "SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED"; + } else if (code == ESM_CAUSE_ESM_INFORMATION_NOT_RECEIVED) { + return "ESM_INFORMATION_NOT_RECEIVED"; + } else if (code == ESM_CAUSE_PDN_CONNECTION_DOES_NOT_EXIST) { + return "PDN_CONNECTION_DOES_NOT_EXIST"; + } else if (code == ESM_CAUSE_MULTIPLE_PDN_CONNECTIONS_NOT_ALLOWED) { + return "MULTIPLE_PDN_CONNECTIONS_NOT_ALLOWED"; + } else if (code == ESM_CAUSE_COLLISION_WITH_NETWORK_INITIATED_REQUEST) { + return "COLLISION_WITH_NETWORK_INITIATED_REQUEST"; + } else if (code == ESM_CAUSE_UNSUPPORTED_QCI_VALUE) { + return "UNSUPPORTED_QCI_VALUE"; + } else if (code == ESM_CAUSE_BEARER_HANDLING_NOT_SUPPORTED) { + return "BEARER_HANDLING_NOT_SUPPORTED"; + } else if (code == ESM_CAUSE_INVALID_PTI_VALUE) { + return "INVALID_PTI_VALUE"; + } else if (code == ESM_CAUSE_APN_RESTRICTION_VALUE_NOT_COMPATIBLE) { + return "APN_RESTRICTION_VALUE_NOT_COMPATIBLE"; + } else if (code == ESM_CAUSE_SEMANTICALLY_INCORRECT) { + return "SEMANTICALLY_INCORRECT"; + } else if (code == ESM_CAUSE_INVALID_MANDATORY_INFO) { + return "INVALID_MANDATORY_INFO"; + } else if (code == ESM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED) { + return "MESSAGE_TYPE_NOT_IMPLEMENTED"; + } else if (code == ESM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE) { + return "MESSAGE_TYPE_NOT_COMPATIBLE"; + } else if (code == ESM_CAUSE_IE_NOT_IMPLEMENTED) { + return "IE_NOT_IMPLEMENTED"; + } else if (code == ESM_CAUSE_CONDITIONAL_IE_ERROR) { + return "CONDITIONAL_IE_ERROR"; + } else if (code == ESM_CAUSE_MESSAGE_NOT_COMPATIBLE) { + return "MESSAGE_NOT_COMPATIBLE"; + } else if (code == ESM_CAUSE_PROTOCOL_ERROR) { + return "PROTOCOL_ERROR"; + } else { + return "Unknown ESM cause code"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return attach type + * ----------------------------------------------------------------------------- + */ +const char* attachType(const EpsAttachType* type) +{ + if (*type == EPS_ATTACH_TYPE_EPS) { + return "EPS"; + } else if (*type == EPS_ATTACH_TYPE_IMSI) { + return "IMSI"; + } else if (*type == EPS_ATTACH_TYPE_EMERGENCY) { + return "EMERGENCY"; + } else if (*type == EPS_ATTACH_TYPE_RESERVED) { + return "RESERVED"; + } else { + return "Unknown attach type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return detach type + * ----------------------------------------------------------------------------- + */ +const char* detachType(const DetachType* type) +{ + if (type->switchoff == DETACH_TYPE_NORMAL_DETACH) + { + if (type->typeofdetach == DETACH_TYPE_EPS) { + return "Normal EPS"; + } else if (type->typeofdetach == DETACH_TYPE_IMSI) { + return "Normal IMSI"; + } else if (type->typeofdetach == DETACH_TYPE_EPS_IMSI) { + return "Normal EMERGENCY"; + } else if (type->typeofdetach == DETACH_TYPE_RESERVED_1) { + return "Normal RESERVED"; + } else if (type->typeofdetach == DETACH_TYPE_RESERVED_2) { + return "Normal RESERVED"; + } else { + return "Unknown attach type"; + } + } + else if (type->switchoff == DETACH_TYPE_SWITCH_OFF) + { + if (type->typeofdetach == DETACH_TYPE_EPS) { + return "Switch-off EPS"; + } else if (type->typeofdetach == DETACH_TYPE_IMSI) { + return "Switch-off IMSI"; + } else if (type->typeofdetach == DETACH_TYPE_EPS_IMSI) { + return "Switch-off EMERGENCY"; + } else if (type->typeofdetach == DETACH_TYPE_RESERVED_1) { + return "Switch-off RESERVED"; + } else if (type->typeofdetach == DETACH_TYPE_RESERVED_2) { + return "Switch-off RESERVED"; + } else { + return "Unknown attach type"; + } + } + + return "Unknon switch-off parameter"; +} + +/* + * ----------------------------------------------------------------------------- + * Display EPS mobile identity + * ----------------------------------------------------------------------------- + */ +ssize_t epsIdentity(char* buffer, size_t len, const EpsMobileIdentity* ident) +{ + int index = 0; + + if (ident->imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) { + index += imsiIdentity(buffer + index, len - index, + (ImsiMobileIdentity_t*)(&ident->imsi)); + } + else if (ident->imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) { + index += imeiIdentity(buffer + index, len - index, + (ImeiMobileIdentity_t*)(&ident->imei)); + } + else if (ident->guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) { + index += snprintf(buffer + index, len - index, "GUTI = {"); + index += snprintf(buffer + index, len - index, + "plmn = %u%u%u%u%u", + ident->guti.mccdigit1, ident->guti.mccdigit2, + ident->guti.mccdigit3, ident->guti.mncdigit1, + ident->guti.mncdigit2); + if (ident->guti.mncdigit3 != 0xf) { + index += snprintf(buffer + index, len - index, "%u", + ident->guti.mncdigit3); + } + index += snprintf(buffer + index, len - index, + ", MMEgid = %u, MMEcode = %u, m_tmsi = %u}", + ident->guti.mmegroupid, ident->guti.mmecode, + ident->guti.mtmsi); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Display mobile identity + * ----------------------------------------------------------------------------- + */ +ssize_t mobileIdentity(char* buffer, size_t len, const MobileIdentity* ident) +{ + int index = 0; + + if (ident->imsi.typeofidentity == MOBILE_IDENTITY_IMSI) { + index += imsiIdentity(buffer + index, len - index, &ident->imsi); + } else if (ident->imei.typeofidentity == MOBILE_IDENTITY_IMEI) { + index += imeiIdentity(buffer + index, len - index, &ident->imei); + } else if (ident->tmsi.typeofidentity == MOBILE_IDENTITY_TMSI) { + index += tmsiIdentity(buffer + index, len - index, &ident->tmsi); + } else if (ident->tmgi.typeofidentity == MOBILE_IDENTITY_TMGI) { + index += tmgiIdentity(buffer + index, len - index, &ident->tmgi); + } else if (ident->no_id.typeofidentity == MOBILE_IDENTITY_NOT_AVAILABLE) { + index += snprintf(buffer + index, len - index, "NOT AVAILABLE"); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Return mobile identity type + * ----------------------------------------------------------------------------- + */ +const char* identityType(const IdentityType2* type) +{ + if (*type == IDENTITY_TYPE_2_IMSI) { + return "IMSI"; + } else if (*type == IDENTITY_TYPE_2_IMEI) { + return "IMEI"; + } else if (*type == IDENTITY_TYPE_2_IMEISV) { + return "IMEISV"; + } else if (*type == IDENTITY_TYPE_2_TMSI) { + return "TMSI"; + } else { + return "Unknown identity type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return PDN request type + * ----------------------------------------------------------------------------- + */ +const char* requestType(const RequestType* type) +{ + if (*type == REQUEST_TYPE_INITIAL_REQUEST) { + return "INITIAL"; + } else if (*type == REQUEST_TYPE_HANDOVER) { + return "HANDOVER"; + } else if (*type == REQUEST_TYPE_UNUSED) { + return "UNUSED"; + } else if (*type == REQUEST_TYPE_EMERGENCY) { + return "EMERGENCY"; + } else { + return "Unknown PDN request type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return PDN type + * ----------------------------------------------------------------------------- + */ +const char* pdnType(const PdnType* type) +{ + if (*type == PDN_TYPE_IPV4) { + return "IPV4"; + } else if (*type == PDN_TYPE_IPV6) { + return "IPV6"; + } else if (*type == PDN_TYPE_IPV4V6) { + return "IPV4V6"; + } else if (*type == PDN_TYPE_UNUSED) { + return "UNUSED"; + } else { + return "Unknown PDN type"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Display PDN address + * ----------------------------------------------------------------------------- + */ +ssize_t pdnAddress(char* buffer, size_t len, const PdnAddress* addr) +{ + int index = 0; + + switch (addr->pdntypevalue) + { + case PDN_VALUE_TYPE_IPV4: + /* Display IPv4 PDN address */ + index += ipv4Addr(buffer + index, len - index, + &addr->pdnaddressinformation); + break; + + case PDN_VALUE_TYPE_IPV6: + /* Display IPv6 suffix */ + index += ipv6Addr(buffer + index, len - index, + &addr->pdnaddressinformation); + break; + + case PDN_VALUE_TYPE_IPV4V6: + /* Display IPv4 PDN address and IPv6 suffix */ + index += ipv4v6Addr(buffer + index, len - index, + &addr->pdnaddressinformation); + break; + + default: + index += snprintf(buffer + index, len - index, "Unknown"); + break; + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Dispay the NAS key set identifier + * ----------------------------------------------------------------------------- + */ +ssize_t nasKeySetIdentifier(char* buffer, size_t len, + const NasKeySetIdentifier* ksi) +{ + int index = 0; + + index += snprintf(buffer + index, len - index, "{%s: %d}", + (ksi->tsc == NAS_KEY_SET_IDENTIFIER_NATIVE)? "NATIVE" : + (ksi->tsc == NAS_KEY_SET_IDENTIFIER_MAPPED)? "MAPPED" : + "Unknown", ksi->naskeysetidentifier); + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Dispay the authentication parameter (RAND, AUTN, RES) + * ----------------------------------------------------------------------------- + */ +ssize_t authenticationParameter(char* buffer, size_t len, const OctetString* param) +{ + int index = 0; + + for (int i = 0; i < param->length; i++) { + index += snprintf(buffer + index, len - index, "%.2hx", + (unsigned char)(param->value[i])); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Return the NAS ciphering algorithm identifier + * ----------------------------------------------------------------------------- + */ +const char* nasCipheringAlgorithm(const NasSecurityAlgorithms* algo) +{ + if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA0) { + return "EEA0"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA1) { + return "128-EEA1"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA2) { + return "128-EEA2"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA3) { + return "EEA3"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA4) { + return "EEA4"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA5) { + return "EEA5"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA6) { + return "EEA6"; + } + else if (algo->typeofcipheringalgorithm == NAS_SECURITY_ALGORITHMS_EEA7) { + return "EEA7"; + } else { + return "Unknown"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Return the NAS integrity algorithm identifier + * ----------------------------------------------------------------------------- + */ +const char* nasIntegrityAlgorithm(const NasSecurityAlgorithms* algo) +{ + if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA0) { + return "EIA0"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA1) { + return "128-EIA1"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA2) { + return "128-EIA2"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA3) { + return "EIA3"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA4) { + return "EIA4"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA5) { + return "EIA5"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA6) { + return "EIA6"; + } + else if (algo->typeofintegrityalgorithm == NAS_SECURITY_ALGORITHMS_EIA7) { + return "EIA7"; + } else { + return "Unknown"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Display GPRS timer + * ----------------------------------------------------------------------------- + */ +ssize_t gprsTimer(char* buffer, size_t len, const GprsTimer* timer) +{ + int index = 0; + + if (timer->unit != GPRS_TIMER_UNIT_0S) { + index += snprintf(buffer + index, len - index, + "{Unit = %s, Value = %u}", + timerUnit(timer->unit), timer->timervalue); + } else { + index += snprintf(buffer + index, len - index, "{Deactivated}"); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Display the content of TAI list + * ----------------------------------------------------------------------------- + */ +ssize_t taiList(char* buffer, size_t len, const TrackingAreaIdentityList* tai) +{ + int index = 0; + + index += snprintf(buffer + index, len - index, "TAI = {%s", + (tai->typeoflist == TRACKING_AREA_IDENTITY_LIST_ONE_PLMN_CONSECUTIVE_TACS)? + "One PLMN consecutive TACs" : "Unknown"); + + index += snprintf(buffer + index, len - index, + ", plmn = %u%u%u%u%u", + tai->mccdigit1, tai->mccdigit2, + tai->mccdigit3, tai->mncdigit1, + tai->mncdigit2); + if (tai->mncdigit3 != 0xf) { + index += snprintf(buffer + index, len - index, "%u", + tai->mncdigit3); + } + + if (tai->numberofelements > 0) { + index += snprintf(buffer + index, len - index, + ", n_tacs = %u, tac = 0x%.4x", + tai->numberofelements, tai->tac); + } + + index += snprintf(buffer + index, len - index, "}"); + + return (index); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Display the International Mobile Subscriber Identity + * ----------------------------------------------------------------------------- + */ +ssize_t imsiIdentity(char* buffer, size_t len, const ImsiMobileIdentity_t* imsi) +{ + int index = 0; + + if (imsi->oddeven != MOBILE_IDENTITY_EVEN) { + index += snprintf(buffer + index, len - index, + "IMSI = %u%u%u%u%u%u%u%u%u%u%u%u%u%u", + imsi->digit1, imsi->digit2, imsi->digit3, imsi->digit4, + imsi->digit5, imsi->digit6, imsi->digit7, imsi->digit8, + imsi->digit9, imsi->digit10, imsi->digit11, imsi->digit12, + imsi->digit13, imsi->digit14); + } else { + index += snprintf(buffer + index, len - index, + "IMSI = %u%u%u%u%u%u%u%u%u%u%u%u%u", + imsi->digit1, imsi->digit2, imsi->digit3, imsi->digit4, + imsi->digit5, imsi->digit7, imsi->digit8, imsi->digit9, + imsi->digit10, imsi->digit11, imsi->digit12, + imsi->digit13, imsi->digit14); + } + if (imsi->digit15 != 0xf) { + index += snprintf(buffer + index, len - index, "%u", imsi->digit15); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Display the International Mobile Equipment Identity + * ----------------------------------------------------------------------------- + */ +ssize_t imeiIdentity(char* buffer, size_t len, const ImeiMobileIdentity_t* imei) +{ + int index = 0; + + if (imei->oddeven != MOBILE_IDENTITY_EVEN) { + index += snprintf(buffer + index, len - index, + "IMEI = %u%u%u%u%u%u%u%u%u%u%u%u%u%u%u", + imei->digit1, imei->digit2, imei->digit3, imei->digit4, + imei->digit5, imei->digit6, imei->digit7, imei->digit8, + imei->digit9, imei->digit10, imei->digit11, imei->digit12, + imei->digit13, imei->digit14, imei->digit15); + } else { + index += snprintf(buffer + index, len - index, + "IMEI = %u%u%u%u%u%u%u%u%u%u%u%u%u%u", + imei->digit1, imei->digit2, imei->digit3, imei->digit4, + imei->digit5, imei->digit6, imei->digit7, imei->digit8, + imei->digit9, imei->digit10, imei->digit11, imei->digit12, + imei->digit13, imei->digit14); + } + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Display the Temporary Mobile Subscriber Identity + * ----------------------------------------------------------------------------- + */ +ssize_t tmsiIdentity(char* buffer, size_t len, const TmsiMobileIdentity_t* tmsi) +{ + int index = 0; + + index += snprintf(buffer + index, len - index, + "TMSI = %u%u%u%u%u%u%u%u%u%u%u%u%u%u", + tmsi->digit2, tmsi->digit3, tmsi->digit4, + tmsi->digit5, tmsi->digit6, tmsi->digit7, tmsi->digit8, + tmsi->digit9, tmsi->digit10, tmsi->digit11, tmsi->digit12, + tmsi->digit13, tmsi->digit14, tmsi->digit15); + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Display the Temporary Mobile Group Identity + * ----------------------------------------------------------------------------- + */ +ssize_t tmgiIdentity(char* buffer, size_t len, const TmgiMobileIdentity_t* tmgi) +{ + int index = 0; + + index += snprintf(buffer + index, len - index, "TMGI = {"); + index += snprintf(buffer + index, len - index, "MBMS service ID = %u", + tmgi->mbmsserviceid); + if (tmgi->mccmncindication) { + index += snprintf(buffer + index, len - index, ", MCC = %u%u%u", + tmgi->mccdigit1, tmgi->mccdigit2, tmgi->mccdigit3); + index += snprintf(buffer + index, len - index, ", MNC = %u%u", + tmgi->mncdigit1, tmgi->mncdigit2); + if (tmgi->mncdigit3 != 0xf) { + index += snprintf(buffer + index, len - index, "%u", + tmgi->mncdigit3); + } + } + if (tmgi->mbmssessionidindication) { + index += snprintf(buffer + index, len - index, ", MBMS session ID = %u", + tmgi->mbmssessionid); + } + index += snprintf(buffer + index, len - index, "}"); + + return (index); +} + +/* + * ----------------------------------------------------------------------------- + * Return GPRS timer unit + * ----------------------------------------------------------------------------- + */ +const char* timerUnit(int unit) +{ + if (unit == GPRS_TIMER_UNIT_2S) { + return "2 seconds"; + } else if (unit == GPRS_TIMER_UNIT_60S) { + return "Minutes"; + } else if (unit == GPRS_TIMER_UNIT_360S) { + return "Decihours"; + } else if (unit == GPRS_TIMER_UNIT_0S) { + return "Deactivated"; + } else { + return "Unknown timer unit"; + } +} + +/* + * ----------------------------------------------------------------------------- + * Display IPv4 address + * ----------------------------------------------------------------------------- + */ +ssize_t ipv4Addr(char* buffer, size_t len, const OctetString* addr) +{ + return snprintf(buffer, len, "%u.%u.%u.%u", + addr->value[0], addr->value[1], + addr->value[2], addr->value[3]); +} + +/* + * ----------------------------------------------------------------------------- + * Display IPv6 address + * ----------------------------------------------------------------------------- + */ +ssize_t ipv6Addr(char* buffer, size_t len, const OctetString* addr) +{ + return snprintf(buffer, len, "%x%.2x:%x%.2x:%x%.2x:%x%.2x", + addr->value[0], addr->value[1], + addr->value[2], addr->value[3], + addr->value[4], addr->value[5], + addr->value[6], addr->value[7]); +} + +/* + * ----------------------------------------------------------------------------- + * Display IPv4v6 address + * ----------------------------------------------------------------------------- + */ +ssize_t ipv4v6Addr(char* buffer, size_t len, const OctetString* addr) +{ + return snprintf(buffer, len, "%u.%u.%u.%u / %x%.2x:%x%.2x:%x%.2x:%x%.2x", + addr->value[0], addr->value[1], + addr->value[2], addr->value[3], + addr->value[4], addr->value[5], + addr->value[6], addr->value[7], + addr->value[8], addr->value[9], + addr->value[10], addr->value[11]); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.h b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.h new file mode 100644 index 0000000000..25ad7557e4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_data.h @@ -0,0 +1,81 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_data.h + +Version 0.1 + +Date 2013/04/11 + +Product Access-Stratum sublayer simulator + +Subsystem Non-Access-Stratum data + +Author Frederic Maurel + +Description Defines constants and functions used by the AS simulator + process. + +*****************************************************************************/ + +#ifndef __NAS_DATA_H__ +#define __NAS_DATA_H__ + +#include "EpsAttachType.h" +#include "DetachType.h" +#include "NasKeySetIdentifier.h" +#include "EpsMobileIdentity.h" +#include "MobileIdentity.h" +#include "IdentityType2.h" +#include "RequestType.h" +#include "PdnType.h" +#include "PdnAddress.h" +#include "NasSecurityAlgorithms.h" +#include "GprsTimer.h" +#include "TrackingAreaIdentityList.h" +#include "EmmCause.h" +#include "EsmCause.h" + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +const char* emmMsgType(int type); +const char* esmMsgType(int type); + +const char* emmCauseCode(EmmCause code); +const char* esmCauseCode(EsmCause code); + +const char* attachType(const EpsAttachType* type); +const char* detachType(const DetachType* type); + +ssize_t epsIdentity(char* buffer, size_t len, const EpsMobileIdentity* ident); +const char* identityType(const IdentityType2* type); +ssize_t mobileIdentity(char* buffer, size_t len, const MobileIdentity* ident); + +const char* requestType(const RequestType* type); +const char* pdnType(const PdnType* type); +ssize_t pdnAddress(char* buffer, size_t len, const PdnAddress* addr); + +ssize_t nasKeySetIdentifier(char* buffer, size_t len, const NasKeySetIdentifier* ksi); +ssize_t authenticationParameter(char* buffer, size_t len, const OctetString* param); +const char* nasCipheringAlgorithm(const NasSecurityAlgorithms* algo); +const char* nasIntegrityAlgorithm(const NasSecurityAlgorithms* algo); + +ssize_t gprsTimer(char* buffer, size_t len, const GprsTimer* timer); +ssize_t taiList(char* buffer, size_t len, const TrackingAreaIdentityList* tai); + +#endif // __NAS_DATA_H__ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.c b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.c new file mode 100644 index 0000000000..2dac50c923 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.c @@ -0,0 +1,937 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_process.c + +Version 0.1 + +Date 2013/04/16 + +Product Access-Stratum sublayer simulator + +Subsystem NAS message processing + +Author Frederic Maurel + +Description Defines functions executed by the Access-Stratum sublayer + upon receiving NAS messages. + +*****************************************************************************/ + +#include "nas_process.h" + +#include "nas_data.h" +#include "nas_message.h" + +#include <stdio.h> // snprintf +#include <string.h> // memset + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + *----------------------------------------------------------------------------- + * Functions used to process EPS Mobility Management messages + *----------------------------------------------------------------------------- + */ +static int _nas_process_emm(char* buffer, int length, const EMM_msg* msg); + +static int _attach_request(char* buffer, int length, const attach_request_msg* msg); +static int _attach_accept(char* buffer, int length, const attach_accept_msg* msg); +static int _attach_reject(char* buffer, int length, const attach_reject_msg* msg); +static int _attach_complete(char* buffer, int length, const attach_complete_msg* msg); + +static int _detach_request(char* buffer, int length, const detach_request_msg* msg); +static int _detach_accept(char* buffer, int length, const detach_accept_msg* msg); + +static int _identity_request(char* buffer, int length, const identity_request_msg* msg); +static int _identity_response(char* buffer, int length, const identity_response_msg* msg); + +static int _authentication_request(char* buffer, int length, const authentication_request_msg* msg); +static int _authentication_response(char* buffer, int length, const authentication_response_msg* msg); +static int _authentication_failure(char* buffer, int length, const authentication_failure_msg* msg); +static int _authentication_reject(char* buffer, int length, const authentication_reject_msg* msg); + +static int _security_mode_command(char* buffer, int length, const security_mode_command_msg* msg); +static int _security_mode_complete(char* buffer, int length, const security_mode_complete_msg* msg); +static int _security_mode_reject(char* buffer, int length, const security_mode_reject_msg* msg); + +static int _esm_message_container(char* buffer, int length, const EsmMessageContainer* msg); + +static int _emm_status(char* buffer, int length, const emm_status_msg* msg); + +/* + *----------------------------------------------------------------------------- + * Functions used to process EPS Session Management messages + *----------------------------------------------------------------------------- + */ +static int _nas_process_esm(char* buffer, int length, const ESM_msg* msg); + +static int _pdn_connectivity_request(char* buffer, int length, const pdn_connectivity_request_msg* msg); +static int _pdn_connectivity_reject(char* buffer, int length, const pdn_connectivity_reject_msg* msg); + +static int _pdn_disconnect_request(char* buffer, int length, const pdn_disconnect_request_msg* msg); +static int _pdn_disconnect_reject(char* buffer, int length, const pdn_disconnect_reject_msg* msg); + +static int _activate_default_eps_bearer_context_request(char* buffer, int length, const activate_default_eps_bearer_context_request_msg* msg); +static int _activate_default_eps_bearer_context_accept(char* buffer, int length, const activate_default_eps_bearer_context_accept_msg* msg); +static int _activate_default_eps_bearer_context_reject(char* buffer, int length, const activate_default_eps_bearer_context_reject_msg* msg); + +static int _activate_dedicated_eps_bearer_context_request(char* buffer, int length, const activate_dedicated_eps_bearer_context_request_msg* msg); +static int _activate_dedicated_eps_bearer_context_accept(char* buffer, int length, const activate_dedicated_eps_bearer_context_accept_msg* msg); +static int _activate_dedicated_eps_bearer_context_reject(char* buffer, int length, const activate_dedicated_eps_bearer_context_reject_msg* msg); + +static int _deactivate_eps_bearer_context_request(char* buffer, int length, const deactivate_eps_bearer_context_request_msg* msg); +static int _deactivate_eps_bearer_context_accept(char* buffer, int length, const deactivate_eps_bearer_context_accept_msg* msg); + +static int _esm_status(char* buffer, int length, const esm_status_msg* msg); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/* + *----------------------------------------------------------------------------- + * Process NAS message + *----------------------------------------------------------------------------- + */ +int nas_process(char* buffer, int length, const char* msg, int size) +{ + int index = 0; + int bytes; + nas_message_t nas_msg; + + /* Decode NAS message */ + memset(&nas_msg, 0, sizeof(nas_message_t)); + bytes = nas_message_decode(msg, &nas_msg, size); + if (bytes < 0) { + printf("ERROR\t: %s - Failed to decode NAS message (err=%d)\n", + __FUNCTION__, bytes); + return (RETURNerror); + } + + int protocol_discriminator = nas_msg.header.protocol_discriminator; + if (protocol_discriminator == EPS_MOBILITY_MANAGEMENT_MESSAGE) { + /* Process EPS Mobility Management NAS message */ + index += _nas_process_emm(buffer + index, length - index, + &nas_msg.plain.emm); + } + else if (protocol_discriminator == EPS_SESSION_MANAGEMENT_MESSAGE) { + /* Process EPS Session Management NAS message */ + index += _nas_process_esm(buffer + index, length - index, + &nas_msg.plain.esm); + } + else { + printf("ERROR\t: %s - Protocol discriminator is not valid (%d)\n", + __FUNCTION__, protocol_discriminator); + return (RETURNerror); + } + + buffer[index] = '\0'; + + return (bytes); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * ============================================================================= + * Functions used to process EPS Mobility Management messages + * ============================================================================= + */ + +/* + *----------------------------------------------------------------------------- + * Process EPS Mobility Management NAS message + *----------------------------------------------------------------------------- + */ +static int _nas_process_emm(char* buffer, int length, const EMM_msg* msg) +{ + int index = 0; + const EsmMessageContainer* esm_container = NULL; + + printf("INFO\t: Process %s\n", emmMsgType(msg->header.message_type)); + index += snprintf(buffer + index, length - index, "%s (", + emmMsgType(msg->header.message_type)); + + switch (msg->header.message_type) + { + case ATTACH_REQUEST: + esm_container = &msg->attach_request.esmmessagecontainer; + index += _attach_request(buffer + index, length - index, + &msg->attach_request); + break; + + case ATTACH_ACCEPT: + esm_container = &msg->attach_accept.esmmessagecontainer; + index += _attach_accept(buffer + index, length - index, + &msg->attach_accept); + break; + + case ATTACH_REJECT: + esm_container = &msg->attach_reject.esmmessagecontainer; + index += _attach_reject(buffer + index, length - index, + &msg->attach_reject); + break; + + case ATTACH_COMPLETE: + esm_container = &msg->attach_complete.esmmessagecontainer; + index += _attach_complete(buffer + index, length - index, + &msg->attach_complete); + break; + + case DETACH_REQUEST: + index += _detach_request(buffer + index, length - index, + &msg->detach_request); + break; + + case DETACH_ACCEPT: + index += _detach_accept(buffer + index, length - index, + &msg->detach_accept); + break; + + case IDENTITY_REQUEST: + index += _identity_request(buffer + index, length - index, + &msg->identity_request); + break; + + case IDENTITY_RESPONSE: + index += _identity_response(buffer + index, length - index, + &msg->identity_response); + break; + + case AUTHENTICATION_REQUEST: + index += _authentication_request(buffer + index, length - index, + &msg->authentication_request); + break; + + case AUTHENTICATION_RESPONSE: + index += _authentication_response(buffer + index, length - index, + &msg->authentication_response); + break; + + case AUTHENTICATION_FAILURE: + index += _authentication_failure(buffer + index, length - index, + &msg->authentication_failure); + break; + + case AUTHENTICATION_REJECT: + index += _authentication_reject(buffer + index, length - index, + &msg->authentication_reject); + break; + + case SECURITY_MODE_COMMAND: + index += _security_mode_command(buffer + index, length - index, + &msg->security_mode_command); + break; + + case SECURITY_MODE_COMPLETE: + index += _security_mode_complete(buffer + index, length - index, + &msg->security_mode_complete); + break; + + case SECURITY_MODE_REJECT: + index += _security_mode_reject(buffer + index, length - index, + &msg->security_mode_reject); + break; + + case EMM_STATUS: + index += _emm_status(buffer + index, length - index, + &msg->emm_status); + break; + + default: + printf("WARNING\t: %s - EMM NAS message is not valid (0x%x)\n", + __FUNCTION__, msg->header.message_type); + break; + } + + index += snprintf(buffer + index, length - index, ")"); + + /* Process ESM message container */ + if (esm_container) { + index += _esm_message_container(buffer + index, length - index, + esm_container); + } + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Attach Request + *----------------------------------------------------------------------------- + */ +static int _attach_request(char* buffer, int length, + const attach_request_msg* msg) +{ + int index = 0; + + /* EPS attach type */ + index += snprintf(buffer + index, length - index, "Type = %s", + attachType(&msg->epsattachtype)); + /* NAS key set identifier */ + index += snprintf(buffer + index, length - index, ", KSI = "); + index += nasKeySetIdentifier(buffer + index, length - index, + &msg->naskeysetidentifier); + /* EPS mobile identity */ + index += snprintf(buffer + index, length - index, ", "); + index += epsIdentity(buffer + index, length - index, + &msg->oldgutiorimsi); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Attach Accept + *----------------------------------------------------------------------------- + */ +static int _attach_accept(char* buffer, int length, + const attach_accept_msg* msg) +{ + int index = 0; + +#if 0 + /* T3412 timer value */ + index += snprintf(buffer + index, length - index, "T3412 = "); + index += gprsTimer(buffer + index, length - index, &msg->t3412value); + /* TAI list */ + index += snprintf(buffer + index, length - index, ", "); + index += taiList(buffer + index, length - index, &msg->tailist); +#endif + /* GUTI */ + if (msg->presencemask & ATTACH_ACCEPT_GUTI_PRESENT) { + index += epsIdentity(buffer + index, length - index, &msg->guti); + } + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Attach Reject + *----------------------------------------------------------------------------- + */ +static int _attach_reject(char* buffer, int length, + const attach_reject_msg* msg) +{ + int index = 0; + + /* EMM cause code */ + index += snprintf(buffer + index, length - index, "EmmCause = %s (%d)", + emmCauseCode(msg->emmcause), msg->emmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Attach Complete + *----------------------------------------------------------------------------- + */ +static int _attach_complete(char* buffer, int length, + const attach_complete_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Identity Request + *----------------------------------------------------------------------------- + */ +static int _identity_request(char* buffer, int length, + const identity_request_msg* msg) +{ + int index = 0; + + /* Type of requested identity */ + index += snprintf(buffer + index, length - index, "Type = %s", + identityType(&msg->identitytype)); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Detach Request + *----------------------------------------------------------------------------- + */ +static int _detach_request(char* buffer, int length, + const detach_request_msg* msg) +{ + int index = 0; + + /* EPS attach type */ + index += snprintf(buffer + index, length - index, "Type = %s", + detachType(&msg->detachtype)); + /* NAS key set identifier */ + index += snprintf(buffer + index, length - index, ", KSI = "); + index += nasKeySetIdentifier(buffer + index, length - index, + &msg->naskeysetidentifier); + /* EPS mobile identity */ + index += snprintf(buffer + index, length - index, ", "); + index += epsIdentity(buffer + index, length - index, + &msg->gutiorimsi); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Detach Accept + *----------------------------------------------------------------------------- + */ +static int _detach_accept(char* buffer, int length, + const detach_accept_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Identity Response + *----------------------------------------------------------------------------- + */ +static int _identity_response(char* buffer, int length, + const identity_response_msg* msg) +{ + int index = 0; + + /* Mobile identity */ + index += mobileIdentity(buffer + index, length - index, + &msg->mobileidentity); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Authentication Request + *----------------------------------------------------------------------------- + */ +static int _authentication_request(char* buffer, int length, + const authentication_request_msg* msg) +{ + int index = 0; + + /* NAS key set identifier ASME */ + index += snprintf(buffer + index, length - index, "KSIasme = "); + index += nasKeySetIdentifier(buffer + index, length - index, + &msg->naskeysetidentifierasme); + /* Authentication parameter RAND */ + index += snprintf(buffer + index, length - index, "\\nRAND = "); + index += authenticationParameter(buffer + index, length - index, + &msg->authenticationparameterrand.rand); + /* Authentication parameter AUTN */ + index += snprintf(buffer + index, length - index, ", AUTN = "); + index += authenticationParameter(buffer + index, length - index, + &msg->authenticationparameterautn.autn); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Authentication Response + *----------------------------------------------------------------------------- + */ +static int _authentication_response(char* buffer, int length, + const authentication_response_msg* msg) +{ + int index = 0; + + /* Authentication response parameter */ + index += snprintf(buffer + index, length - index, "RES = "); + index += authenticationParameter(buffer + index, length - index, + &msg->authenticationresponseparameter.res); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Authentication Failure + *----------------------------------------------------------------------------- + */ +static int _authentication_failure(char* buffer, int length, + const authentication_failure_msg* msg) +{ + int index = 0; + + /* EMM cause */ + index += snprintf(buffer + index, length - index, "EmmCause = %s (%d)", + emmCauseCode(msg->emmcause), msg->emmcause); + /* Authenticattion failure parameter */ + if (msg->presencemask & + AUTHENTICATION_FAILURE_AUTHENTICATION_FAILURE_PARAMETER_PRESENT) { + index += snprintf(buffer + index, length - index, "AUTS = "); + index += authenticationParameter(buffer + index, length - index, + &msg->authenticationfailureparameter.auts); + } + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Authentication Reject + *----------------------------------------------------------------------------- + */ +static int _authentication_reject(char* buffer, int length, + const authentication_reject_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Security Mode Command + *----------------------------------------------------------------------------- + */ +static int _security_mode_command(char* buffer, int length, + const security_mode_command_msg* msg) +{ + int index = 0; + + /* Selected NAS ciphering algorithm */ + index += snprintf(buffer + index, length - index, "%s (%d)", + nasCipheringAlgorithm(&msg->selectednassecurityalgorithms), + msg->selectednassecurityalgorithms.typeofcipheringalgorithm); + /* Selected NAS integrity algorithm */ + index += snprintf(buffer + index, length - index, ", %s (%d)", + nasIntegrityAlgorithm(&msg->selectednassecurityalgorithms), + msg->selectednassecurityalgorithms.typeofintegrityalgorithm); + /* NAS key set identifier */ + index += snprintf(buffer + index, length - index, ", KSI = "); + index += nasKeySetIdentifier(buffer + index, length - index, + &msg->naskeysetidentifier); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Security Mode Complete + *----------------------------------------------------------------------------- + */ +static int _security_mode_complete(char* buffer, int length, + const security_mode_complete_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Security Mode Reject + *----------------------------------------------------------------------------- + */ +static int _security_mode_reject(char* buffer, int length, + const security_mode_reject_msg* msg) +{ + int index = 0; + + /* EMM cause code */ + index += snprintf(buffer + index, length - index, "EmmCause = %s (%d)", + emmCauseCode(msg->emmcause), msg->emmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * ESM message container + *----------------------------------------------------------------------------- + */ +static int _esm_message_container(char* buffer, int length, + const EsmMessageContainer* msg) +{ + int index = 0; + int bytes; + + if (msg->esmmessagecontainercontents.length > 0) + { + nas_message_t nas_msg; + memset(&nas_msg, 0, sizeof(nas_message_t)); + + /* Decode ESM message container */ + bytes = nas_message_decode((char*)msg->esmmessagecontainercontents.value, + &nas_msg, msg->esmmessagecontainercontents.length); + if (bytes < 0) { + printf("ERROR\t: %s - Failed to decode ESM message container " + "(err=%d)\n", __FUNCTION__, bytes); + return (0); + } + + index += snprintf(buffer + index, length - index, "\\n + "); + + /* Process EPS Session Management NAS message */ + index += _nas_process_esm(buffer + index, length - index, + &nas_msg.plain.esm); + } + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process EMM Status + *----------------------------------------------------------------------------- + */ +static int _emm_status(char* buffer, int length, const emm_status_msg* msg) +{ + int index = 0; + + /* EMM cause code */ + index += snprintf(buffer + index, length - index, "EmmCause = %s (%d)", + emmCauseCode(msg->emmcause), msg->emmcause); + + return (index); +} +/* + * ============================================================================= + * Functions used to process EPS Session Management messages + * ============================================================================= + */ + +/* + *----------------------------------------------------------------------------- + * Process EPS Session MAnagement NAS message + *----------------------------------------------------------------------------- + */ +static int _nas_process_esm(char* buffer, int length, const ESM_msg* msg) +{ + int index = 0; + + printf("INFO\t: Process %s\n", esmMsgType(msg->header.message_type)); + index += snprintf(buffer + index, length - index, "%s (pti=%d, ebi=%d", + esmMsgType(msg->header.message_type), + msg->header.procedure_transaction_identity, + msg->header.eps_bearer_identity); + + switch (msg->header.message_type) + { + case PDN_CONNECTIVITY_REQUEST: + index += _pdn_connectivity_request(buffer + index, length - index, + &msg->pdn_connectivity_request); + break; + + case PDN_CONNECTIVITY_REJECT: + index += _pdn_connectivity_reject(buffer + index, length - index, + &msg->pdn_connectivity_reject); + break; + + case PDN_DISCONNECT_REQUEST: + index += _pdn_disconnect_request(buffer + index, length - index, + &msg->pdn_disconnect_request); + break; + + case PDN_DISCONNECT_REJECT: + index += _pdn_disconnect_reject(buffer + index, length - index, + &msg->pdn_disconnect_reject); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + index += _activate_default_eps_bearer_context_request( + buffer + index, length - index, + &msg->activate_default_eps_bearer_context_request); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + index += _activate_default_eps_bearer_context_accept( + buffer + index, length - index, + &msg->activate_default_eps_bearer_context_accept); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + index += _activate_default_eps_bearer_context_reject( + buffer + index, length - index, + &msg->activate_default_eps_bearer_context_reject); + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REQUEST: + index += _activate_dedicated_eps_bearer_context_request( + buffer + index, length - index, + &msg->activate_dedicated_eps_bearer_context_request); + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_ACCEPT: + index += _activate_dedicated_eps_bearer_context_accept( + buffer + index, length - index, + &msg->activate_dedicated_eps_bearer_context_accept); + break; + + case ACTIVATE_DEDICATED_EPS_BEARER_CONTEXT_REJECT: + index += _activate_dedicated_eps_bearer_context_reject( + buffer + index, length - index, + &msg->activate_dedicated_eps_bearer_context_reject); + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST: + index += _deactivate_eps_bearer_context_request(buffer + index, + length - index, + &msg->deactivate_eps_bearer_context_request); + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + index += _deactivate_eps_bearer_context_accept(buffer + index, + length - index, + &msg->deactivate_eps_bearer_context_accept); + break; + + case ESM_STATUS: + index += _esm_status(buffer + index, length - index, + &msg->esm_status); + break; + + default: + printf("WARNING\t: %s - ESM NAS message is not valid (0x%x)\n", + __FUNCTION__, msg->header.message_type); + break; + } + + index += snprintf(buffer + index, length - index, ")"); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process PDN Connectivity Request + *----------------------------------------------------------------------------- + */ +static int _pdn_connectivity_request(char* buffer, int length, + const pdn_connectivity_request_msg* msg) +{ + int index = 0; + + /* PDN request type and PDN type */ + index += snprintf(buffer + index, length - index, + ", RequestType = %s, PdnType = %s", + requestType(&msg->requesttype), + pdnType(&msg->pdntype)); + /* Access Point Name */ + if (msg->presencemask & PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) + { + index += snprintf(buffer + index, length - index, ", APN = %s", + (char*)msg->accesspointname.accesspointnamevalue.value); + } + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process PDN Connectivity Reject + *----------------------------------------------------------------------------- + */ +static int _pdn_connectivity_reject(char* buffer, int length, + const pdn_connectivity_reject_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process PDN Disconnect Request + *----------------------------------------------------------------------------- + */ +static int _pdn_disconnect_request(char* buffer, int length, + const pdn_disconnect_request_msg* msg) +{ + int index = 0; + + /* Linked EPS bearer identity */ + index += snprintf(buffer + index, length - index, ", Linked EBI = %d", + msg->linkedepsbeareridentity); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process PDN Disconnect Reject + *----------------------------------------------------------------------------- + */ +static int _pdn_disconnect_reject(char* buffer, int length, + const pdn_disconnect_reject_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Default EPS Bearer Context Request + *----------------------------------------------------------------------------- + */ +static int _activate_default_eps_bearer_context_request(char* buffer, int length, + const activate_default_eps_bearer_context_request_msg* msg) +{ + int index = 0; + + /* Access Point Name */ + index += snprintf(buffer + index, length - index, ", APN = %s", + (char*)msg->accesspointname.accesspointnamevalue.value); + + /* PDN address */ + index += snprintf(buffer + index, length - index, ", PDN addr = "); + index += pdnAddress(buffer + index, length - index, &msg->pdnaddress); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Default EPS Bearer Context Accept + *----------------------------------------------------------------------------- + */ +static int _activate_default_eps_bearer_context_accept(char* buffer, int length, + const activate_default_eps_bearer_context_accept_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Default EPS Bearer Context Reject + *----------------------------------------------------------------------------- + */ +static int _activate_default_eps_bearer_context_reject(char* buffer, int length, + const activate_default_eps_bearer_context_reject_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Dedicated EPS Bearer Context Request + *----------------------------------------------------------------------------- + */ +static int _activate_dedicated_eps_bearer_context_request( + char* buffer, int length, + const activate_dedicated_eps_bearer_context_request_msg* msg) +{ + int index = 0; + + /* Linked EPS bearer identity */ + index += snprintf(buffer + index, length - index, ", Linked EBI = %d", + msg->linkedepsbeareridentity); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Dedicated EPS Bearer Context Accept + *----------------------------------------------------------------------------- + */ +static int _activate_dedicated_eps_bearer_context_accept( + char* buffer, int length, + const activate_dedicated_eps_bearer_context_accept_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Activate Dedicated EPS Bearer Context Reject + *----------------------------------------------------------------------------- + */ +static int _activate_dedicated_eps_bearer_context_reject( + char* buffer, int length, + const activate_dedicated_eps_bearer_context_reject_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Deactivate EPS Bearer Context Request + *----------------------------------------------------------------------------- + */ +static int _deactivate_eps_bearer_context_request(char* buffer, int length, + const deactivate_eps_bearer_context_request_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process Deactivate EPS Bearer Context Accept + *----------------------------------------------------------------------------- + */ +static int _deactivate_eps_bearer_context_accept(char* buffer, int length, + const deactivate_eps_bearer_context_accept_msg* msg) +{ + int index = 0; + + return (index); +} + +/* + *----------------------------------------------------------------------------- + * Process ESM Status + *----------------------------------------------------------------------------- + */ +static int _esm_status(char* buffer, int length, const esm_status_msg* msg) +{ + int index = 0; + + /* ESM cause code */ + index += snprintf(buffer + index, length - index, ", EsmCause = %s (%d)", + esmCauseCode(msg->esmcause), msg->esmcause); + + return (index); +} + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.h b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.h new file mode 100644 index 0000000000..3c2a866670 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/as_simulator/nas_process.h @@ -0,0 +1,43 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source nas_process.h + +Version 0.1 + +Date 2013/04/16 + +Product Access-Stratum sublayer simulator + +Subsystem NAS message processing + +Author Frederic Maurel + +Description Defines functions executed by the Access-Stratum sublayer + upon receiving NAS messages. + +*****************************************************************************/ + +#ifndef __NAS_PROCESS_H__ +#define __NAS_PROCESS_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +int nas_process(char* buffer, int length, const char* msg, int size); + +#endif /* __NAS_PROCESS_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/network/Makefile b/openair-cn/NAS/EURECOM-NAS/tst/network/Makefile new file mode 100644 index 0000000000..78a64c659a --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/network/Makefile @@ -0,0 +1,187 @@ +export PROCESS = MME + +include ../../Makerules +include ../../Makefile.inc + +PROJDIR = $(PWD)/../.. + +export LD_RUN_PATH = $(LIBDIR):$(LIBPROCESS) + +LIBS = -lutil -lapi -lEMMmsg -lESMmsg -lies +INCLUDES = -I. -I$(SRCDIR) -I$(INCDIR) -I$(UTILDIR) \ + -I$(EMMMSGDIR) -I$(ESMMSGDIR) -I$(IESDIR) + +TARGET = NetworkProcess + +all: $(TARGET) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGET) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +network_parser.o: network_parser.h +network_parser.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/parser.h +network_simulator.o: network_parser.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +network_simulator.o: /usr/include/stdint.h /usr/include/features.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/socket.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/as_message.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/networkDef.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/api/network/nas_message.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msg.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_msgDef.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachRequest.h +network_simulator.o: /usr/include/stdio.h /usr/include/libio.h +network_simulator.o: /usr/include/_G_config.h /usr/include/wchar.h +network_simulator.o: /usr/include/xlocale.h /usr/include/stdlib.h +network_simulator.o: /usr/include/alloca.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolDiscriminator.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/OctetString.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SecurityHeaderType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MessageType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasKeySetIdentifier.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsMobileIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeNetworkCapability.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmMessageContainer.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PTmsiSignature.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DrxParameter.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MsNetworkCapability.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LocationAreaIdentification.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TmsiStatus.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark2.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileStationClassmark3.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SupportedCodecList.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GutiType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsAttachResult.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/GprsTimer.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrackingAreaIdentityList.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/MobileIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmmCause.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PlmnList.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EmergencyNumberList.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AdditionalUpdateResult.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachComplete.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AttachReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DetachType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DetachAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Nonce.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerContextStatus.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsUpdateResult.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ServiceType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/CsfbResponse.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/KsiAndSequenceNumber.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ShortMac.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/ServiceReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterRand.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationParameterAutn.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationResponse.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationResponseParameter.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/AuthenticationFailure.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AuthenticationFailureParameter.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/IdentityType2.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/IdentityResponse.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeCommand.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasSecurityAlgorithms.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/UeSecurityCapability.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ImeisvRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeComplete.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/SecurityModeReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmStatus.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/EmmInformation.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NetworkName.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZone.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TimeZoneAndTime.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/DaylightSavingTime.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/NasMessageContainer.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/UplinkNasTransport.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/CsServiceNotification.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PagingIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/Cli.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/SsCode.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsIndicator.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LcsClientIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msg.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_msgDef.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsBearerIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EpsQualityOfService.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowTemplate.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TransactionIdentifier.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/QualityOfService.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RadioPriority.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PacketFlowIdentifier.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmCause.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/AccessPointName.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnAddress.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/RequestType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/PdnType.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/EsmInformationTransferFlag.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationRequest.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmInformationResponse.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/EsmStatus.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/emm/msg/emm_cause.h +network_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/esm/msg/esm_cause.h +network_simulator.o: /usr/include/errno.h /usr/include/netdb.h +network_simulator.o: /usr/include/netinet/in.h /usr/include/endian.h +network_simulator.o: /usr/include/rpc/netdb.h /usr/include/signal.h +network_simulator.o: /usr/include/time.h /usr/include/string.h +network_simulator.o: /usr/include/unistd.h /usr/include/getopt.h diff --git a/openair-cn/NAS/EURECOM-NAS/tst/network/README b/openair-cn/NAS/EURECOM-NAS/tst/network/README new file mode 100644 index 0000000000..25a6de5d14 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/network/README @@ -0,0 +1,255 @@ +================================================================================ + EURECOM LTE NAS emulation +================================================================================ + +The EURECOM-NAS.tar.bz2 archive contains libraries and binary files used to +execute emulation of the NAS protocol running on the control plane between +the UE and the core network in the Evolved Packet System. + +-------------------------------------------------------------------------------- + How to extract files from EURECOM-NAS.tar.bz2 tarball file ? +-------------------------------------------------------------------------------- + +> tar xvzf EURECOM-NAS.tar.bz2 + +EURECOM-NAS directory should contain following files: + +> tree -a EURECOM-NAS + +EURECOM-NAS +|-- bin +| |-- .ue.nvram +| |-- .ue_emm.nvram +| |-- .usim.nvram +| |-- NetworkProcess +| |-- UEprocess +| `-- UserProcess +`-- lib + |-- libEMMmsg.a + |-- libEMMmsg.so + |-- libEMMsap.a + |-- libEMMsap.so + |-- libESMmsg.a + |-- libESMmsg.so + |-- libESMsap.a + |-- libESMsap.so + |-- libapi.a + |-- libapi.so + |-- libies.a + |-- libies.so + |-- libutil.a + `-- libutil.so + +-------------------------------------------------------------------------------- + EURECOM-NAS/bin directory +-------------------------------------------------------------------------------- + +EURECOM-NAS/bin contains binary files. + +UEprocess is an implementation of the NAS protocol running at the UE side. + +NetworkProcess is a simulation of the core network running at the eNodeB +(network registration) and the MME (network attachment and PDN connection). + +UserProcess is a pseudo Connection Manager used to send AT commands to the +UE for testing purpose. + +When starting up, UEprocess reads configuration data from .nvram binary +files used as UE's non-volatile memory. + +.usim.nvram contains data stored into the USIM +.ue.nvram contains data related to the UE identification (IMEI, +manufacturer, model, PIN code) +.ue_emm.nvram contains data related to EPS Mobility Management (IMSI, last +registered PLMN) + +-------------------------------------------------------------------------------- + EURECOM-NAS/lib directory +-------------------------------------------------------------------------------- + +EURECOM-NAS/lib contains static libraries (lib*.a) and dynamically linked +shared object libraries (lib*.so). + +-------------------------------------------------------------------------------- + Environment variables +-------------------------------------------------------------------------------- + +Although static libraries are provided, only shared libraries are loaded by +programs at run time. To allow programs to find them all, the environment +variable LD_LIBRARY_PATH must be defined with the path of the EURECOM-NAS/lib +directory. + +> export LD_LIBRARY_PATH=/my-root-directory/EURECOM-NAS/lib:$LD_LIBRARY_PATH + +Where 'my-root-directory' is the absolute path to the directory where is +located the EURECOM-NAS directory. + +By default UEprocess reads UE's and USIM non-volatile data from files +located in the directory from where the program was started. If not found in +the current directory, UEprocess search files into the directories defined +by USIM_DIR and NVRAM_DIR environment variables. + +So if the UEprocess application is not started from the EURECOM-NAS/bin +directory, the environment variables USIM_DIR and NVRAM_DIR must be defined +with the path of the EURECOM-NAS/bin directory. + +> export USIM_DIR=/my-root-directory/EURECOM-NAS/bin +> export NVRAM_DIR=/my-root-directory/EURECOM-NAS/bin + +-------------------------------------------------------------------------------- + Application settings +-------------------------------------------------------------------------------- + +UserProcess, UEprocess and NetworkProcess applications can be runned locally +on the same host or distributed on several remote machines. + + + +-------------------------------+ + | UserProcess | + | (pseudo Connection Manager) | + +-------------------------------+ + ^ + | /dev/ttyUSBx + | or UDP + AT commands v + +-------------------------------+ + | UEprocess | + | (NAS protocol) | + +-------------------------------+ + ^ + | UDP + NAS messages v + +-------------------------------+ + | Networkprocess | + | (core network simulator) | + +-------------------------------+ + + +UEprocess communicates with UserProcess in two different ways: + + - using tty device file when together connected via USB-to-serial + adaptor cable + + - using UDP socket through the Internet Protocol + +UEprocess connects itself to NetworkProcess using UDP socket only. + +-------------------------------------------------------------------------------- + How to run the EURECOM LTE emulation application ? +-------------------------------------------------------------------------------- + +Every executables can be started in any order. + +Each executable has an usage menu. + +> EURECOM-NAS/bin/UserProcess --help +Usage: EURECOM-NAS/bin/UserProcess [-host <host>] [-port <port>] [-dev <devpath>] [-params <params>] + <host> Remote hostname (localhost) + <port> Remote port number (10000) + <devpath> Device pathname (NULL) + <params> Device attribute parameters (NULL) + +> EURECOM-NAS/bin/UEprocess --help +Usage: EURECOM-NAS/bin/UEprocess [-ueid <ueid>] [-trace <mask>] [-uhost <uhost>] [-nhost <nhost>] [-uport <uport>] [-nport <nport>] [-dev <devpath>] [-params <params>] + <ueid> UE identifier (1) + <mask> Logging trace level (0) + <uhost> User app layer's hostname (localhost) + <nhost> Network layer's hostname (localhost) + <uport> User app layer's port number (10000) + <nport> Network layer's port number (12000) + <devpath> Device pathname (NULL) + <params> Device attribute parameters (NULL) +Version: exported - 2013-05-30 18:49:43 + +> EURECOM-NAS/bin/NetworkProcess --help +Usage: EURECOM-NAS/bin/NetworkProcess [-host <host>] [-port <port>] + <host> Remote hostname (localhost) + <port> Remote port number (12000) + +-------------------------------------------------------------------------------- + Receiving AT commands via serial-USB +-------------------------------------------------------------------------------- + +Assuming that UserProcess connects to USB0 and UEprocess connects to USB1 +(they can connect to the same USB device number if they are running on +different hosts). + +1 - Configure and export environment variables: + +> export LD_LIBRARY_PATH=/my-root-directory/EURECOM-NAS/lib:$LD_LIBRARY_PATH +> export USIM_DIR=/my-root-directory/EURECOM-NAS/bin +> export NVRAM_DIR=/my-root-directory/EURECOM-NAS/bin + +2 - Start the pseudo Connection Manager to send AT commands to / receive + responses from USB0 at 9600 bauds rate: + +> ./EURECOM-NAS/bin/UserProcess -dev /dev/ttyUSB0 -params 9600 + +3 - Start the NAS protocol emulation to receive AT command from / send + responses to USB1 at 9600 bauds rate and send/receive NAS messages + to/from the network simulator using default localhost and port number + (1200): + +> ./EURECOM-NAS/bin/UEprocess -trace 2f -dev /dev/ttyUSB1 -params 9600 + +4 - Start the network simulation to send/receive NAS messages to/from the + NAS protocol emulation using default localhost and port number (1200): + +> ./EURECOM-NAS/bin/NetworkProcess + +-------------------------------------------------------------------------------- + Receiving AT commands via UDP +-------------------------------------------------------------------------------- + +1 - Configure and export environment variables: + +> export LD_LIBRARY_PATH=/my-root-directory/EURECOM-NAS/lib:$LD_LIBRARY_PATH +> export USIM_DIR=/my-root-directory/EURECOM-NAS/bin +> export NVRAM_DIR=/my-root-directory/EURECOM-NAS/bin + +2 - Start the pseudo Connection Manager to send AT commands to / receive + responses from the localhost using default port number (10000): + +> ./EURECOM-NAS/bin/UserProcess + +3 - Start the NAS protocol emulation to receive AT command from / send + responses to the localhost using default port number (10000) and + send/receive NAS messages to/from the network simulator using default + localhost and port number (1200): + +> ./EURECOM-NAS/bin/UEprocess -trace 2f + +4 - Start the network simulation to send/receive NAS messages to/from the + NAS protocol emulation using default localhost and port number (1200): + +> ./EURECOM-NAS/bin/NetworkProcess + +-------------------------------------------------------------------------------- + Application output +-------------------------------------------------------------------------------- + +UEprocess displays information related to parsing and execution of AT commands +and NAS procedures with following severity levels: + +DEBUG: Used for debug purpose (displayed in green color) +INFO: Informational trace +WARNING: Warning message (displayed in blue color) +ERROR: Error message (displayed in red color) +FUNC: Function's calling tree information at runtime +DUMP: Hex dump of all user and network messages + +The severity level is selected with the command line parameter -trace <sev> +where <sev> is a bitmask of the following hexadecimal values: + +00 - No trace (default) +01 - DEBUG +02 - INFO +04 - WARNING +08 - ERROR +0f - DEBUG + INFO + WARNING + ERROR +10 - FUNC +20 - DUMP +2f - DEBUG + INFO + WARNING + ERROR + DUMP + +-------------------------------------------------------------------------------- + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.c b/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.c new file mode 100644 index 0000000000..b599e2024b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.c @@ -0,0 +1,162 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network_parser.c + +Version 0.1 + +Date 2012/11/05 + +Product Network Simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the Network Simulator process + +*****************************************************************************/ + +#include "network_parser.h" + +#include "util/parser.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * Identifiers of the Network Simulator command line options + */ +enum +{ + NETWORK_PARSER_HOST, /* Remote hostname */ + NETWORK_PARSER_PORT, /* Remote port number */ + NETWORK_PARSER_NB_OPTIONS +}; + +/* ------------------------------------------------------------------- + * Definition of the internal Network Simulator command line structure + * ------------------------------------------------------------------- + * The command line is defined with a name (default is "NetworkProcess" + * but it will be replaced by the command name actually used at + * runtime), a number of options and the list of options. + * An option is defined with a name, an argument following the name, + * the usage displayed by the usage function and a default value. + */ +static parser_command_line_t networkParserCommandLine = { + "NetworkProcess", /* Command name */ + NETWORK_PARSER_NB_OPTIONS, /* Number of options */ + { /* Command line options */ + {"-host", "<host>", "Remote hostname\t\t", NETWORK_PARSER_DEFAULT_REMOTE_HOSTNAME}, + {"-port", "<port>", "Remote port number\t", NETWORK_PARSER_DEFAULT_REMOTE_PORT_NUMBER}, + } +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: network_parser_print_usage() ** + ** ** + ** Description: Displays the command line options used to run the Network ** + ** Simulator process ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline void network_parser_print_usage(void) +{ + parser_print_usage(&networkParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: network_parser_get_options() ** + ** ** + ** Description: Gets the command line options used to run the Network ** + ** Simulator process ** + ** ** + ** Inputs: argc: Number of options ** + ** argv: Pointer to the list of options ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline int network_parser_get_options(int argc, const char** argv) +{ + return parser_get_options(argc, argv, &networkParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: network_parser_get_nb_options() ** + ** ** + ** Description: Returns the number of the command line options used to ** + ** run the Network Simulator process ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Number of command line options ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline int network_parser_get_nb_options(void) +{ + return networkParserCommandLine.nb_options; +} + +/**************************************************************************** + ** ** + ** Name: network_parser_get_host() ** + ** ** + ** Description: Returns the value of the remote hostname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the remote hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* network_parser_get_host(void) +{ + return networkParserCommandLine.options[NETWORK_PARSER_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: network_parser_get_port() ** + ** ** + ** Description: Returns the value of the remote port number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the remote port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +inline const char* network_parser_get_port(void) +{ + return networkParserCommandLine.options[NETWORK_PARSER_PORT].pvalue; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.h b/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.h new file mode 100644 index 0000000000..a9a9b7678d --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/network/network_parser.h @@ -0,0 +1,54 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network_parser.h + +Version 0.1 + +Date 2012/11/05 + +Product Network simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the Network Simulator process + +*****************************************************************************/ + +#ifndef __NETWORK_PARSER_H__ +#define __NETWORK_PARSER_H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* The default remote hostname the Network Simulator must connect to */ +#define NETWORK_PARSER_DEFAULT_REMOTE_HOSTNAME "localhost" + +/* The default port number used for the internet service delivered by the + * remote hostname */ +#define NETWORK_PARSER_DEFAULT_REMOTE_PORT_NUMBER "12000" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void network_parser_print_usage(void); +int network_parser_get_options(int argc, const char** argv); + +int network_parser_get_nb_options(void); +const char* network_parser_get_host(void); +const char* network_parser_get_port(void); + +#endif /* __NETWORK_PARSER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/network/network_simulator.c b/openair-cn/NAS/EURECOM-NAS/tst/network/network_simulator.c new file mode 100644 index 0000000000..a74a17ebb4 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/network/network_simulator.c @@ -0,0 +1,1375 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source network_simulator.c + +Version 0.1 + +Date 09/10/2012 + +Product Network simulator + +Subsystem Network simulator main process + +Author Frederic Maurel + +Description Implements the network simulator running at the network + side for NAS_UE testing purpose. + +*****************************************************************************/ + +#include "network_parser.h" + +#include "include/commonDef.h" +#include "util/socket.h" +#include "util/timer.h" +#include "api/network/as_message.h" +#include "api/network/nas_message.h" +#include "emm/msg/emm_cause.h" +#include "esm/msg/esm_cause.h" + +#include "util/log.h" + +#include <stdio.h> // printf, perror +#include <errno.h> // errno +#include <netdb.h> // gai_strerror +#include <stdlib.h> // exit, malloc, rand +#include <signal.h> // sigaction +#include <string.h> // memset, memcpy +#include <unistd.h> // sleep + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * ----------------------------------------------------------------------------- + * Constants + * ----------------------------------------------------------------------------- + */ + +/* Tracking area code */ +#define DEFAULT_TAC 0xCAFE // two byte in hexadecimal format + +/* Cell identity */ +#define DEFAULT_CI 0x01020304 // four byte in hexadecimal format + +/* Reference signal received power */ +#define DEFAULT_RSRP 27 + +/* Reference signal received quality */ +#define DEFAULT_RSRQ 55 + +/* Data bit rates */ +#define BIT_RATE_64K 0x40 +#define BIT_RATE_128K 0x48 +#define BIT_RATE_512K 0x78 +#define BIT_RATE_1024K 0x87 + +/* Eurecom's Access Point Name */ +static const OctetString EURECOM_APN = { + 14, (uint8_t*)("www.eurecom.fr") +}; + +/* PDN IP address */ +//static uint8_t FIRST_PDN_IPV4_ADDRESS[] = {0x0A, 0x03, 0x02, 0x3C}; /* 10.3.2.60 */ +static uint8_t FIRST_PDN_IPV4_ADDRESS[] = { /* 192.168.02.60 */ + 0xC0, 0xA8, 0x02, 0x3C}; +static uint8_t FIRST_PDN_IPV6_ADDRESS[] = { /* FE80::221:70FF:C0A8:023C/64 */ + 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}; +static uint8_t FIRST_PDN_IPV4V6_ADDRESS[] = { /* 192.168.02.60, FE80::221:70FF:C0A8:023C/64 */ + 0xC0, 0xA8, 0x02, 0x3C, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x02, 0x3C}; +static const OctetString FIRST_IPV4_PDN = {4, FIRST_PDN_IPV4_ADDRESS}; +static const OctetString FIRST_IPV6_PDN = {8, FIRST_PDN_IPV6_ADDRESS}; +static const OctetString FIRST_IPV4V6_PDN = {12, FIRST_PDN_IPV4V6_ADDRESS}; + +/* Other PDN IP address */ +//static uint8_t OTHER_PDN_IPV4_ADDRESS[] = {0x0A, 0x01, 0x20, 0x37}; /* 10.1.32.55 */ +static uint8_t OTHER_PDN_IPV4_ADDRESS[] = { /* 192.168.12.187 */ + 0xC0, 0xA8, 0x0C, 0xBB}; +static uint8_t OTHER_PDN_IPV6_ADDRESS[] = { /* FE80::221:70FF:C0A8:CBB/64 */ + 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}; +static uint8_t OTHER_PDN_IPV4V6_ADDRESS[] = { /* 192.168.12.187, FE80::221:70FF:C0A8:0CBB/64 */ + 0xC0, 0xA8, 0x0C, 0xBB, 0x02, 0x21, 0x70, 0xFF, 0xC0, 0xA8, 0x0C, 0xBB}; +static const OctetString OTHER_IPV4_PDN = {4, OTHER_PDN_IPV4_ADDRESS}; +static const OctetString OTHER_IPV6_PDN = {8, OTHER_PDN_IPV6_ADDRESS}; +static const OctetString OTHER_IPV4V6_PDN = {12, OTHER_PDN_IPV4V6_ADDRESS}; + +/* XXX - Random wait time */ +#define SLEEP_TIME 1 + +/* + * ----------------------------------------------------------------------------- + * Macros + * ----------------------------------------------------------------------------- + */ + +#define PRINT_PLMN_DIGIT(d) if ((d) != 0xf) printf("%u", (d)) +#define PRINT_PLMN(plmn) \ + PRINT_PLMN_DIGIT((plmn).MCCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MCCdigit3); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit1); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit2); \ + PRINT_PLMN_DIGIT((plmn).MNCdigit3) + +/* + * ----------------------------------------------------------------------------- + * Variables + * ----------------------------------------------------------------------------- + */ + +/* + * String buffer used to send/receive messages to/from the network + */ +#define NETWORK_SIMULATOR_BUFFER_SIZE 1024 +static char _network_simulator_buffer [NETWORK_SIMULATOR_BUFFER_SIZE]; + +/* + * The connection endpoint used for communication with the network + */ +static socket_id_t * _network_simulator_sid; + +/* + * String buffer used to encode/decode ESM messages + */ +#define NETWORK_SIMULATOR_ESM_BUFFER_SIZE 1024 +static uint8_t _network_simulator_esm_buffer[NETWORK_SIMULATOR_ESM_BUFFER_SIZE]; + +/* + * Messages counter + */ +static unsigned int _network_simulator_msg_recv = 0; +static unsigned int _network_simulator_msg_sent = 0; + +/* + * EPS bearer identity + */ +static unsigned int _network_simulator_ebi = EPS_BEARER_IDENTITY_FIRST; + +/* + * Network IP version capability + */ +static const enum { + NETWORK_IPV4 = 0, + NETWORK_IPV6, + NETWORK_IPV4V6, + NETWORK_IP_MAX +} _network_simulator_ip_version = NETWORK_IPV4V6; +static const OctetString* _network_simulator_pdn[NETWORK_IP_MAX][2] = { + /* IPv4 network capability */ + {&FIRST_IPV4_PDN, &OTHER_IPV4_PDN}, + /* IPv6 network capability */ + {&FIRST_IPV6_PDN, &OTHER_IPV6_PDN}, + /* IPv4v6 network capability */ + {&FIRST_IPV4V6_PDN, &OTHER_IPV4V6_PDN}, +}; + +/* + * ----------------------------------------------------------------------------- + * Functions + * ----------------------------------------------------------------------------- + */ + +static int _set_signal_handler(int signal, void (handler)(int)); +static void _signal_handler(int signal_number); +static int _process_message(int msgID, const as_message_t* req); +static int _assign_pdn_address(int ue_pdn_type, int is_initial, int* pdn_type, OctetString* pdn); + +/* Functions used to process messages received from the Access Stratum */ +static int _process_cell_info_req(const cell_info_req_t* req, cell_info_cnf_t* rsp); +static int _process_establish_req(const nas_establish_req_t* req, nas_establish_cnf_t* rsp); +static int _process_ul_info_transfer_req(const ul_info_transfer_req_t* req, ul_info_transfer_cnf_t* cnf, dl_info_transfer_ind_t* ind); + +/* Functions used to process EMM NAS messages */ +static int _process_emm_msg(EMM_msg* msg); +static int _process_attach_request(const attach_request_msg* msg, EMM_msg* rsp, const plmn_t *plmn); +static int _process_attach_complete(const attach_complete_msg* msg); + +/* Functions used to process ESM NAS messages */ +static int _process_esm_msg(ESM_msg* msg); +static int _process_pdn_connectivity_request(const pdn_connectivity_request_msg* msg, ESM_msg* rsp); +static int _process_pdn_disconnect_request(const pdn_disconnect_request_msg* msg, ESM_msg* rsp); +static int _process_activate_default_eps_bearer_context_accept(const activate_default_eps_bearer_context_accept_msg* msg); +static int _process_activate_default_eps_bearer_context_reject(const activate_default_eps_bearer_context_reject_msg* msg); +static int _process_deactivate_eps_bearer_context_accept(const deactivate_eps_bearer_context_accept_msg* msg); + +static void _dump_buffer(const Byte_t* buffer, size_t len) +{ + for (int i = 0; i < len; i++) { + if ( (i%16) == 0 ) printf("\n\t"); + printf("%.2hx ", buffer[i]); + } + printf("\n\n"); +} + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +int main (int argc, const char* argv[]) +{ + /* + * Get the command line options + */ + if ( network_parser_get_options(argc, argv) != RETURNok ) + { + network_parser_print_usage(); + exit(EXIT_FAILURE); + } + const char* host = network_parser_get_host(); + const char* port = network_parser_get_port(); + + log_init(0x2f); + + /* + * Initialize the communication channel to the NAS sublayer + */ + _network_simulator_sid = socket_udp_open(SOCKET_SERVER, host, port); + if (_network_simulator_sid == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + printf("ERROR\t: socket_udp_open() failed: %s\n", error); + exit(EXIT_FAILURE); + } + printf("INFO\t: The Network Simulator is now connected to %s/%s (%d)\n", + host, port, socket_get_fd(_network_simulator_sid)); + + /* + * Set up signal handler + */ + (void) _set_signal_handler(SIGINT, _signal_handler); + (void) _set_signal_handler(SIGTERM, _signal_handler); + + /* + * Network simulator main loop + */ + while (TRUE) + { + as_message_t msg; + + /* Receive message from the NAS */ + int rbytes = socket_recv(_network_simulator_sid, _network_simulator_buffer, + NETWORK_SIMULATOR_BUFFER_SIZE); + if (rbytes == RETURNerror) { + perror("ERROR\t: socket_recv() failed"); + continue; + } + _network_simulator_buffer[rbytes] = '\0'; + + _network_simulator_msg_recv += 1; + + /* Decode the received message */ + int msg_id = as_message_decode(_network_simulator_buffer, &msg, rbytes); + + /* Process the received message */ + int len = _process_message(msg_id, &msg); + if (len > 0) { + /* XXX - Sleep a random interval of time before continuing */ + sleep(rand()%SLEEP_TIME); + /* Send the response message to the NAS sublayer */ + int sbytes = socket_send(_network_simulator_sid, _network_simulator_buffer, len); + if (sbytes == RETURNerror) { + perror("ERROR\t: socket_send() failed"); + continue; + } + _network_simulator_msg_sent += 1; + } + + printf("\nINFO\t: %d messages received, %d messages sent\n", + _network_simulator_msg_recv, _network_simulator_msg_sent); + } + + /* + * Termination cleanup + */ + printf("INFO\t: Closing network socket %d\n", socket_get_fd(_network_simulator_sid)); + socket_close(_network_simulator_sid); + + printf("INFO\t: Network simulator exited\n"); + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * Signal handler setup function + */ +static int _set_signal_handler(int signal, void (handler)(int)) +{ + struct sigaction act; + + /* Initialize signal set */ + (void) memset (&act, 0, sizeof (act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + /* Initialize signal handler */ + act.sa_handler = handler; + if ( sigaction (signal, &act, 0) < 0 ) { + return RETURNerror; + } + + return RETURNok; +} + +/* + * Signal handler + */ +static void _signal_handler(int signal_number) +{ + printf("\nWARNING\t: Signal %d received\n", signal_number); + printf("INFO\t: Closing network socket %d\n", socket_get_fd(_network_simulator_sid)); + socket_close(_network_simulator_sid); + printf("INFO\t: Network simulator exited\n"); + exit(EXIT_SUCCESS); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to process messages received from the Access Stratum + * ----------------------------------------------------------------------------- + */ +/* + * Process messages received from the AS sublayer + */ +static int _process_message(int msgID, const as_message_t* req) +{ + as_message_t rsp; + int bytes = 0; + + memset(&rsp, 0, sizeof(as_message_t)); + + switch (msgID) + { + case AS_CELL_INFO_REQ: + /* Process cell information request */ + rsp.msgID = _process_cell_info_req(&req->msg.cell_info_req, + &rsp.msg.cell_info_cnf); + break; + + case AS_NAS_ESTABLISH_REQ: + /* Process NAS signalling connection establishment request */ + rsp.msgID = _process_establish_req(&req->msg.nas_establish_req, + &rsp.msg.nas_establish_cnf); + break; + + case AS_UL_INFO_TRANSFER_REQ: + /* Process Uplink information transfer request */ + rsp.msgID = _process_ul_info_transfer_req(&req->msg.ul_info_transfer_req, + &rsp.msg.ul_info_transfer_cnf, + &rsp.msg.dl_info_transfer_ind); + break; + + default: + fprintf(stderr, "WARNING\t: Message type %d is not valid\n", msgID); + break; + } + + if (rsp.msgID == AS_NAS_RELEASE_IND) { + /* NAS signalling connection release */ + rsp.msg.nas_release_ind.cause = AS_DETACH; + printf("\nINFO\t: Send NAS connection release indication: cause = %d\n", + rsp.msg.nas_release_ind.cause); + } + + if (rsp.msgID > 0) { + /* Encode response message */ + bytes = as_message_encode(_network_simulator_buffer, &rsp, + NETWORK_SIMULATOR_BUFFER_SIZE); + } + + return (bytes); +} + +/* + * Process cell information request message + */ +static int _process_cell_info_req(const cell_info_req_t* req, + cell_info_cnf_t* rsp) +{ + printf("\nINFO\t: Received cell selection request: plmnID = "); + PRINT_PLMN(req->plmnID); + printf(", rat = 0x%x\n", req->rat); + + /* Setup cell information confirm message */ + //rsp->errCode = AS_FAILURE; + rsp->errCode = AS_SUCCESS; + rsp->tac = DEFAULT_TAC; + rsp->cellID = DEFAULT_CI; + rsp->rat = AS_EUTRAN; + rsp->rsrp = DEFAULT_RSRP; + rsp->rsrq = DEFAULT_RSRQ; + printf("\nINFO\t: Send cell selection confirm: errCode = %s (%d), " + "tac = 0x%.4x, cellID = 0x%.8x, rat = 0x%x\n", + (rsp->errCode != AS_SUCCESS)? "FAILURE" : "SUCCESS", rsp->errCode, + rsp->tac, rsp->cellID, rsp->rat); + + return (AS_CELL_INFO_CNF); +} + +/* + * Process NAS signalling connection establishment request + */ +static int _process_establish_req(const nas_establish_req_t* req, + nas_establish_cnf_t* rsp) +{ + int rc = RETURNerror; + + printf("\nINFO\t: Received NAS connection establish request: plmnID = "); + PRINT_PLMN(req->plmnID); + printf(", S-TMSI = MMEcode <0x%.2x> M-TMSI <0x%.4x>", + req->s_tmsi.MMEcode, req->s_tmsi.m_tmsi); + printf(", cause = %d, type = %d\n", req->cause, req->type); + + const as_nas_info_t* nas_msg = &req->initialNasMsg; + printf("INFO\t: Initial NAS message (length = %d)\n", nas_msg->length); + _dump_buffer(nas_msg->data, nas_msg->length); + + /* Decode dedicated NAS information data */ + nas_message_t l3_msg; + rc = nas_message_decode((char*)nas_msg->data, &l3_msg, nas_msg->length); + if (rc < 0) { + /* Transmission failure */ + printf("ERROR\t: Failed to decode NAS message (rc=%d)", rc); + rsp->errCode = AS_FAILURE; + return (AS_NAS_ESTABLISH_CNF); + } + + printf("INFO\t: L3 NAS message = 0x%.2x\n", l3_msg.plain.emm.header.message_type); + printf("INFO\t: Protocol Discriminator = %d\n", l3_msg.header.protocol_discriminator); + printf("INFO\t: Security Header Type = %d\n", l3_msg.header.security_header_type); + printf("INFO\t: EMM message: "); + + switch (l3_msg.plain.emm.header.message_type) + { + case ATTACH_REQUEST: + rc = _process_attach_request(&l3_msg.plain.emm.attach_request, + &l3_msg.plain.emm, + &req->plmnID); + break; + + default: + printf("ERROR\t: L3 NAS message 0x%x is not valid\n", + l3_msg.plain.emm.header.message_type); + break; + } + + static int _establish_req_no_response_counter = 0; + if (_establish_req_no_response_counter > 0) { + sleep(rand()%SLEEP_TIME); + _establish_req_no_response_counter -=1; + /* XXX - Return no any response to initial NAS message request */ + return (0); + } + + + if (rc != RETURNerror) { + int bytes = nas_message_encode(_network_simulator_buffer, &l3_msg, + NETWORK_SIMULATOR_BUFFER_SIZE); + + static int _establish_req_failure_counter = 0; + if (_establish_req_failure_counter > 0) { + sleep(rand()%SLEEP_TIME); + _establish_req_failure_counter -= 1; + /* XXX - Return transmission failure indication */ + bytes = 0; + } + + if (bytes > 0) { + /* Setup signalling connection establishment confirm message */ + rsp->errCode = AS_SUCCESS; + rsp->nasMsg.data = (Byte_t*)malloc(bytes * sizeof(Byte_t)); + if (rsp->nasMsg.data) { + rsp->nasMsg.length = bytes; + memcpy((char*)(rsp->nasMsg.data), _network_simulator_buffer, bytes); + } + } + else { + /* Transmission failure */ + rsp->errCode = AS_FAILURE; + } + printf("\nINFO\t: Send NAS connection establish confirm: errCode = %s (%d)\n", + (rsp->errCode != AS_SUCCESS)? "FAILURE" : "SUCCESS", rsp->errCode); + if (rsp->nasMsg.length > 0) { + printf("INFO\t: NAS message %s (0x%x) (length = %d)\n", + (l3_msg.plain.emm.header.message_type == ATTACH_ACCEPT)? "ATTACH_ACCEPT" : + (l3_msg.plain.emm.header.message_type == ATTACH_REJECT)? "ATTACH_REJECT" : + "Unknown NAS message", l3_msg.plain.emm.header.message_type, + rsp->nasMsg.length); + _dump_buffer(rsp->nasMsg.data, rsp->nasMsg.length); + } + /* NAS signalling connection confirm */ + rc = AS_NAS_ESTABLISH_CNF; + } + else { + /* NAS signalling connection release */ + printf("\nINFO\t: Send NAS connection release indication\n"); + rc = AS_NAS_RELEASE_IND; + } + + return (rc); +} + +/* + * Process Uplink information transfer request + */ +static int _process_ul_info_transfer_req(const ul_info_transfer_req_t* req, + ul_info_transfer_cnf_t* cnf, + dl_info_transfer_ind_t* ind) +{ + int rc = RETURNerror; + int bytes; + + ESM_msg esm_msg; + memset(&esm_msg, 0, sizeof(ESM_msg)); + + printf("\nINFO\t: Received uplink information transfer request: "); + printf("S-TMSI = MMEcode <0x%.2x> M-TMSI <0x%.4x>\n", + req->s_tmsi.MMEcode, req->s_tmsi.m_tmsi); + + const as_nas_info_t* nas_msg = &req->nasMsg; + printf("INFO\t: NAS message (length = %d)\n", nas_msg->length); + _dump_buffer(nas_msg->data, nas_msg->length); + + /* Decode NAS information data */ + nas_message_t l3_msg; + rc = nas_message_decode((char*)nas_msg->data, &l3_msg, nas_msg->length); + if (rc < 0) { + /* Transmission failure */ + printf("ERROR\t: Failed to decode NAS message (rc=%d)", rc); + cnf->errCode = AS_FAILURE; + return (AS_UL_INFO_TRANSFER_CNF); + } + + if (l3_msg.header.protocol_discriminator != EPS_SESSION_MANAGEMENT_MESSAGE) { + bytes = _process_emm_msg(&l3_msg.plain.emm); + } else { + bytes = _process_esm_msg(&l3_msg.plain.esm); + } + + if (bytes < 0) { + /* Transmission failure indication */ + cnf->errCode = AS_FAILURE; + printf("\nINFO\t: Return transmission failure indication: errCode = %s (%d)\n", + (cnf->errCode != AS_SUCCESS)? "FAILURE" : "SUCCESS", cnf->errCode); + return (AS_UL_INFO_TRANSFER_CNF); + } + else if (bytes > 0) { + /* Some data has to be sent back to the UE */ + ind->nasMsg.data = (Byte_t*)malloc(bytes * sizeof(Byte_t)); + if (ind->nasMsg.data) { + ind->nasMsg.length = bytes; + strncpy((char*)ind->nasMsg.data, + (char*)_network_simulator_esm_buffer, bytes); + } + /* Downlink data transfer indication */ + printf("INFO\t: Send downlink data transfer indication\n"); + return (AS_DL_INFO_TRANSFER_IND); + } + else { + /* Data successfully delivered */ + cnf->errCode = AS_SUCCESS; + printf("\nINFO\t: Send uplink data transfer confirm: errCode = %s (%d)\n", + (cnf->errCode != AS_SUCCESS)? "FAILURE" : "SUCCESS", cnf->errCode); + return (AS_UL_INFO_TRANSFER_CNF); + } +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to process EMM NAS messages + * ----------------------------------------------------------------------------- + */ + +static int _process_emm_msg(EMM_msg* msg) +{ + int bytes = -1; + + printf("INFO\t: EMM message id = 0x%.2x\n", msg->header.message_type); + printf("INFO\t: Protocol Discriminator = %d\n", msg->header.protocol_discriminator); + printf("INFO\t: Security Header Type = %d\n", msg->header.security_header_type); + printf("INFO\t: EMM message: "); + + switch (msg->header.message_type) + { + case ATTACH_COMPLETE: + bytes = _process_attach_complete(&msg->attach_complete); + break; + + default: + printf("ERROR\t: EMM message 0x%x is not valid\n", + msg->header.message_type); + break; + } + + return (bytes); +} + +/* + * Process Attach Request EMM message + */ +static int _process_attach_request(const attach_request_msg* msg, EMM_msg* rsp, + const plmn_t *plmn) +{ + int rc = RETURNerror; + int bytes = 0; + + printf("Attach Request\n"); + printf("INFO\t:\tProtocolDiscriminator\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tSecurityHeaderType\t= %d\n", msg->securityheadertype); + printf("INFO\t:\tMessageType\t\t= 0x%.2x\n", msg->messagetype); + printf("INFO\t:\tEpsAttachType\t\t= %d\n", msg->epsattachtype); + printf("INFO\t:\tNasKeySetIdentifier\t= [%d][%d]\n", + msg->naskeysetidentifier.tsc, + msg->naskeysetidentifier.naskeysetidentifier); + + printf("INFO\t:\tEpsMobileIdentity\n"); + if (msg->oldgutiorimsi.guti.typeofidentity == EPS_MOBILE_IDENTITY_GUTI) { + const GutiEpsMobileIdentity_t* guti = &msg->oldgutiorimsi.guti; + printf("INFO\t:\t oddeven\t\t= %d\n", guti->oddeven); + printf("INFO\t:\t typeofidentity\t= %d (GUTI)\n", guti->typeofidentity); + printf("INFO\t:\t PLMN\t\t= %d%d%d %d%d%.x\n", + guti->mccdigit1, guti->mccdigit2, guti->mccdigit3, + guti->mncdigit1, guti->mncdigit2, guti->mncdigit3); + printf("INFO\t:\t mmegroupid\t\t= 0x%.4x\n", guti->mmegroupid); + printf("INFO\t:\t mmecode\t\t= 0x%.2x\n", guti->mmecode); + printf("INFO\t:\t mtmsi\t\t= 0x%.8x\n", guti->mtmsi); + } else if (msg->oldgutiorimsi.imsi.typeofidentity == EPS_MOBILE_IDENTITY_IMSI) { + const ImeiEpsMobileIdentity_t* imsi = &msg->oldgutiorimsi.imsi; + printf("INFO\t:\t oddeven\t= %d\n", imsi->oddeven); + printf("INFO\t:\t typeofidentity\t= %d (IMSI)\n", imsi->typeofidentity); + printf("INFO\t:\t digit1\t= %d\n", imsi->digit1); + printf("INFO\t:\t digit2\t= %d\n", imsi->digit2); + printf("INFO\t:\t digit3\t= %d\n", imsi->digit3); + printf("INFO\t:\t digit4\t= %d\n", imsi->digit4); + printf("INFO\t:\t digit5\t= %d\n", imsi->digit5); + printf("INFO\t:\t digit6\t= %d\n", imsi->digit6); + printf("INFO\t:\t digit7\t= %d\n", imsi->digit7); + printf("INFO\t:\t digit8\t= %d\n", imsi->digit8); + printf("INFO\t:\t digit9\t= %d\n", imsi->digit9); + printf("INFO\t:\t digit10\t= %d\n", imsi->digit10); + printf("INFO\t:\t digit11\t= %d\n", imsi->digit11); + printf("INFO\t:\t digit12\t= %d\n", imsi->digit12); + printf("INFO\t:\t digit13\t= %d\n", imsi->digit13); + printf("INFO\t:\t digit14\t= %d\n", imsi->digit14); + printf("INFO\t:\t digit15\t= %d\n", imsi->digit15); + } else if (msg->oldgutiorimsi.imei.typeofidentity == EPS_MOBILE_IDENTITY_IMEI) { + const ImeiEpsMobileIdentity_t* imei = &msg->oldgutiorimsi.imei; + printf("INFO\t:\t oddeven\t= %d\n", imei->oddeven); + printf("INFO\t:\t typeofidentity\t= %d (IMEI)\n", imei->typeofidentity); + printf("INFO\t:\t digit1\t= %d\n", imei->digit1); + printf("INFO\t:\t digit2\t= %d\n", imei->digit2); + printf("INFO\t:\t digit3\t= %d\n", imei->digit3); + printf("INFO\t:\t digit4\t= %d\n", imei->digit4); + printf("INFO\t:\t digit5\t= %d\n", imei->digit5); + printf("INFO\t:\t digit6\t= %d\n", imei->digit6); + printf("INFO\t:\t digit7\t= %d\n", imei->digit7); + printf("INFO\t:\t digit8\t= %d\n", imei->digit8); + printf("INFO\t:\t digit9\t= %d\n", imei->digit9); + printf("INFO\t:\t digit10\t= %d\n", imei->digit10); + printf("INFO\t:\t digit11\t= %d\n", imei->digit11); + printf("INFO\t:\t digit12\t= %d\n", imei->digit12); + printf("INFO\t:\t digit13\t= %d\n", imei->digit13); + printf("INFO\t:\t digit14\t= %d\n", imei->digit14); + printf("INFO\t:\t digit15\t= %d\n", imei->digit15); + } + + printf("INFO\t:\tUeNetworkCapability\n"); + printf("INFO\t:\t eea = %d\n", msg->uenetworkcapability.eea); + printf("INFO\t:\t eia = %d\n", msg->uenetworkcapability.eia); + printf("INFO\t:\t uea = %d\n", msg->uenetworkcapability.uea); + printf("INFO\t:\t ucs2 = %d\n", msg->uenetworkcapability.ucs2); + printf("INFO\t:\t uia = %d\n", msg->uenetworkcapability.uia); + printf("INFO\t:\t spare = %d\n", msg->uenetworkcapability.spare); + printf("INFO\t:\t csfb = %d\n", msg->uenetworkcapability.csfb); + printf("INFO\t:\t lpp = %d\n", msg->uenetworkcapability.lpp); + printf("INFO\t:\t lcs = %d\n", msg->uenetworkcapability.lcs); + printf("INFO\t:\t srvcc = %d\n", msg->uenetworkcapability.srvcc); + printf("INFO\t:\t nf = %d\n", msg->uenetworkcapability.nf); + + printf("INFO\t: ESM message container (length = %d)\n", + msg->esmmessagecontainer.esmmessagecontainercontents.length); + _dump_buffer(msg->esmmessagecontainer.esmmessagecontainercontents.value, + msg->esmmessagecontainer.esmmessagecontainercontents.length); + + /* Decode ESM message container */ + ESM_msg esm_msg; + rc = esm_msg_decode(&esm_msg, msg->esmmessagecontainer.esmmessagecontainercontents.value, msg->esmmessagecontainer.esmmessagecontainercontents.length); + + if (rc < 0) { + /* Reject attach request cause = EMM_CAUSE_PROTOCOL_ERROR */ + printf("ERROR\t: Failed to decode ESM message (rc=%d)", rc); + rc = RETURNerror; + } + else { + printf("INFO\t: L3 ESM message id = 0x%.2x\n", esm_msg.header.message_type); + printf("INFO\t: Protocol Discriminator = %d\n", esm_msg.header.protocol_discriminator); + printf("INFO\t: EPS Bearer Identity = %d\n", esm_msg.header.eps_bearer_identity); + printf("INFO\t: Procedure Transaction Identity = %d\n", esm_msg.header.procedure_transaction_identity); + printf("INFO\t: ESM message: "); + + /* Process ESM message */ + switch (esm_msg.header.message_type) + { + case PDN_CONNECTIVITY_REQUEST: + rc = _process_pdn_connectivity_request(&esm_msg.pdn_connectivity_request, &esm_msg); + break; + + default: + printf("ERROR\t: Received ESM message 0x%x is not valid\n", + esm_msg.header.message_type); + break; + } + } + + /* Setup EMM response message */ + memset(rsp, 0, sizeof(EMM_msg)); + rsp->header.protocol_discriminator = EPS_MOBILITY_MANAGEMENT_MESSAGE; + rsp->header.security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED; + + switch (rc) + { + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST: + rsp->header.message_type = ATTACH_ACCEPT; + break; + + case PDN_CONNECTIVITY_REJECT: + rsp->header.message_type = ATTACH_REJECT; + break; + + default: + if (rc != RETURNerror) { + printf("ERROR\t: ESM message 0x%x to be sent is not valid\n", rc); + } + break; + } + + /* Encode ESM response message */ + if (rc != RETURNerror) { + bytes = esm_msg_encode(&esm_msg, _network_simulator_esm_buffer, + NETWORK_SIMULATOR_ESM_BUFFER_SIZE); + } + + if (rsp->header.message_type != ATTACH_REJECT) { + /* Setup Attach Accept EMM message */ + attach_accept_msg* accept = &rsp->attach_accept; + accept->epsattachresult = EPS_ATTACH_RESULT_EPS; + accept->t3412value.unit = GPRS_TIMER_UNIT_0S; + accept->tailist.typeoflist = 1; /* list of TACs belonging to one PLMN, + * with consecutive TAC values */ + accept->tailist.numberofelements = 4; + accept->tailist.mccdigit1 = plmn->MCCdigit1; + accept->tailist.mccdigit2 = plmn->MCCdigit2; + accept->tailist.mccdigit3 = plmn->MCCdigit3; + accept->tailist.mncdigit1 = plmn->MNCdigit1; + accept->tailist.mncdigit2 = plmn->MNCdigit2; + accept->tailist.mncdigit3 = plmn->MNCdigit3; + accept->tailist.tac = DEFAULT_TAC; + accept->esmmessagecontainer.esmmessagecontainercontents.length = bytes; + accept->esmmessagecontainer.esmmessagecontainercontents.value = _network_simulator_esm_buffer; + } + else { + /* Setup Attach Reject EMM message */ + attach_reject_msg* reject = &rsp->attach_reject; + if (bytes > 0) { + reject->emmcause = EMM_CAUSE_ESM_FAILURE; + reject->presencemask = ATTACH_REJECT_ESM_MESSAGE_CONTAINER_PRESENT; + reject->esmmessagecontainer.esmmessagecontainercontents.length = bytes; + reject->esmmessagecontainer.esmmessagecontainercontents.value = _network_simulator_esm_buffer; + } + else { + reject->emmcause = EMM_CAUSE_PROTOCOL_ERROR; + //reject->emmcause = EMM_CAUSE_ILLEGAL_UE; + //reject->emmcause = EMM_CAUSE_ILLEGAL_ME; + //reject->emmcause = EMM_CAUSE_EPS_NOT_ALLOWED; + //reject->emmcause = EMM_CAUSE_PLMN_NOT_ALLOWED; + //reject->emmcause = EMM_CAUSE_NOT_AUTHORIZED_IN_PLMN; + //reject->emmcause = EMM_CAUSE_TA_NOT_ALLOWED; + //reject->emmcause = EMM_CAUSE_ROAMING_NOT_ALLOWED; + //reject->emmcause = EMM_CAUSE_EPS_NOT_ALLOWED_IN_PLMN; + //reject->emmcause = EMM_CAUSE_NO_SUITABLE_CELLS; + //reject->emmcause = EMM_CAUSE_CONGESTION; + //reject->emmcause = EMM_CAUSE_CSG_NOT_AUTHORIZED; + } + } + + static int _attach_request_release_counter = 0; + if (_attach_request_release_counter > 0) { + sleep(rand()%SLEEP_TIME); + _attach_request_release_counter -= 1; + /* XXX - Return NAS signalling connection release indication */ + return (RETURNerror); + } + return (RETURNok); +} + +/* + * Process Attach Complete EMM message + */ +static int _process_attach_complete(const attach_complete_msg* msg) +{ + int bytes = -1; + + printf("Attach Complete\n"); + printf("INFO\t: ESM message container (length = %d)\n", + msg->esmmessagecontainer.esmmessagecontainercontents.length); + _dump_buffer(msg->esmmessagecontainer.esmmessagecontainercontents.value, + msg->esmmessagecontainer.esmmessagecontainercontents.length); + + /* Decode ESM message container */ + ESM_msg esm_msg; + bytes = esm_msg_decode(&esm_msg, msg->esmmessagecontainer.esmmessagecontainercontents.value, msg->esmmessagecontainer.esmmessagecontainercontents.length); + if (bytes < 0) { + /* Transmission failure */ + printf("ERROR\t: Transmission failure\n"); + return (bytes); + } + + printf("INFO\t: ESM message id = 0x%.2x\n", esm_msg.header.message_type); + printf("INFO\t: Protocol Discriminator = %d\n", esm_msg.header.protocol_discriminator); + printf("INFO\t: EPS Bearer Identity = %d\n", esm_msg.header.eps_bearer_identity); + printf("INFO\t: Procedure Transaction Identity = %d\n", esm_msg.header.procedure_transaction_identity); + printf("INFO\t: ESM message: "); + + switch (esm_msg.header.message_type) + { + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + bytes = _process_activate_default_eps_bearer_context_accept( + &esm_msg.activate_default_eps_bearer_context_accept); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + bytes = _process_activate_default_eps_bearer_context_reject( + &esm_msg.activate_default_eps_bearer_context_reject); + break; + + default: + printf("ERROR\t: ESM message 0x%x is not valid\n", esm_msg.header.message_type); + break; + } + + static int _attach_complete_failure_counter = 0; + if (_attach_complete_failure_counter > 0) { + sleep(rand()%SLEEP_TIME); + _attach_complete_failure_counter -= 1; + /* XXX - Return transmission failure indication */ + return (-1); + } + return (bytes); +} + +/* + * ----------------------------------------------------------------------------- + * Functions used to process ESM NAS messages + * ----------------------------------------------------------------------------- + */ + +static int _process_esm_msg(ESM_msg* msg) +{ + int bytes = 0; + int rc = RETURNerror; + + ESM_msg rsp; + + printf("INFO\t: ESM message id = 0x%.2x\n", msg->header.message_type); + printf("INFO\t: Protocol Discriminator = %d\n", msg->header.protocol_discriminator); + printf("INFO\t: EPS Bearer Identity = %d\n", msg->header.eps_bearer_identity); + printf("INFO\t: Procedure Transaction Identity = %d\n", msg->header.procedure_transaction_identity); + printf("INFO\t: ESM message: "); + + switch (msg->header.message_type) + { + case PDN_CONNECTIVITY_REQUEST: + rc = _process_pdn_connectivity_request(&msg->pdn_connectivity_request, + &rsp); + break; + + case PDN_DISCONNECT_REQUEST: + rc = _process_pdn_disconnect_request(&msg->pdn_disconnect_request, + &rsp); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_ACCEPT: + rc = _process_activate_default_eps_bearer_context_accept( + &msg->activate_default_eps_bearer_context_accept); + break; + + case ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REJECT: + rc = _process_activate_default_eps_bearer_context_reject( + &msg->activate_default_eps_bearer_context_reject); + break; + + case DEACTIVATE_EPS_BEARER_CONTEXT_ACCEPT: + rc = _process_deactivate_eps_bearer_context_accept( + &msg->deactivate_eps_bearer_context_accept); + break; + + default: + printf("ERROR\t: ESM message 0x%x is not valid\n", + msg->header.message_type); + break; + } + + if (rc > 0) { + /* Encode ESM response message */ + bytes = esm_msg_encode(&rsp, _network_simulator_esm_buffer, + NETWORK_SIMULATOR_ESM_BUFFER_SIZE); + printf("\nINFO\t: Send NAS message %s (0x%x) (length = %d)\n", + (rsp.header.message_type == PDN_CONNECTIVITY_REJECT)? "PDN_CONNECTIVITY_REJECT" : + (rsp.header.message_type == PDN_DISCONNECT_REJECT)? "PDN_DISCONNECT_REJECT" : + (rsp.header.message_type == ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST)? "ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST" : + (rsp.header.message_type == DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST)? "DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST" : + "Unknown NAS message", rsp.header.message_type, bytes); + _dump_buffer(_network_simulator_esm_buffer, bytes); + } + + return (bytes); +} + +/* + * Process PDN Connectivity Request ESM message + */ +static int _process_pdn_connectivity_request(const pdn_connectivity_request_msg* msg, ESM_msg* rsp) +{ + int pti = msg->proceduretransactionidentity; + + /* Get the APN if any */ + OctetString apn = {0, NULL}; + if (msg->presencemask & PDN_CONNECTIVITY_REQUEST_ACCESS_POINT_NAME_PRESENT) { + const OctetString* apn_value = &msg->accesspointname.accesspointnamevalue; + apn.value = (uint8_t*)malloc(apn_value->length * sizeof(uint8_t)); + if (apn.value != NULL) { + apn.length = apn_value->length; + apn.value = (uint8_t*)strncpy((char*)apn.value, (char*)apn_value->value, apn.length); + apn.value[apn.length] = '\0'; + } + } + /* Get the PDN type */ + int requested_pdn_type = msg->pdntype; + + printf("PDN Connectivity Request\n"); + printf("INFO\t:\tProtocolDiscriminator\t\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tEpsBearerIdentity\t\t= %d\n", msg->epsbeareridentity); + printf("INFO\t:\tProcedureTransactionIdentity\t= %d\n", msg->proceduretransactionidentity); + printf("INFO\t:\tMessageType\t\t\t= 0x%.2x\n", msg->messagetype); + printf("INFO\t:\tRequestType\t\t\t= %d\n", msg->requesttype); + printf("INFO\t:\tPdnType\t\t\t\t= %d\n", msg->pdntype); + if (apn.length > 0) { + printf("INFO\t:\taccesspointname\t\t\t= %s\n", apn.value); + } + + memset(rsp, 0, sizeof(ESM_msg)); + + rsp->header.protocol_discriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + if (_network_simulator_ebi > EPS_BEARER_IDENTITY_LAST) { + _network_simulator_ebi = EPS_BEARER_IDENTITY_FIRST; + } + rsp->header.eps_bearer_identity = _network_simulator_ebi++; + rsp->header.procedure_transaction_identity = pti; + + static int _pdn_connectivity_reject_counter = 0; + if (_pdn_connectivity_reject_counter > 0) { + sleep(rand()%SLEEP_TIME); + _pdn_connectivity_reject_counter -= 1; + /* XXX - Setup PDN connectivity Reject message */ + pdn_connectivity_reject_msg* reject = &rsp->pdn_connectivity_reject; + reject->messagetype = PDN_CONNECTIVITY_REJECT; + reject->esmcause = ESM_CAUSE_PROTOCOL_ERROR; + } + else if ( (_network_simulator_ip_version != NETWORK_IPV4V6) && + (_network_simulator_ip_version != requested_pdn_type) ) { + /* Setup PDN connectivity Reject message */ + pdn_connectivity_reject_msg* reject = &rsp->pdn_connectivity_reject; + reject->messagetype = PDN_CONNECTIVITY_REJECT; + if (_network_simulator_ip_version != NETWORK_IPV4) { + reject->esmcause = ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED; + } + else { + reject->esmcause = ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED; + } + } + else { + int pdn_type; + int esm_cause; + /* Setup Activate Default EPS Bearer Request message */ + activate_default_eps_bearer_context_request_msg* request = &rsp->activate_default_eps_bearer_context_request; + request->messagetype = ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST; + request->epsqos.qci = 3; /* GBR bearer for playback video */ + request->epsqos.bitRatesPresent = 1; + request->epsqos.bitRates.maxBitRateForUL = BIT_RATE_128K; /* 128K */ + request->epsqos.bitRates.maxBitRateForDL = BIT_RATE_1024K; /* 1M */ + request->epsqos.bitRates.guarBitRateForUL = BIT_RATE_64K; /* 64K */ + request->epsqos.bitRates.guarBitRateForDL = BIT_RATE_512K; /* 512K */ + /* Assign PDN address */ + if (apn.length > 0) { + request->accesspointname.accesspointnamevalue = apn; + esm_cause = _assign_pdn_address(requested_pdn_type, FALSE, &pdn_type, + &request->pdnaddress.pdnaddressinformation); + } + else { + request->accesspointname.accesspointnamevalue = EURECOM_APN; + esm_cause = _assign_pdn_address(requested_pdn_type, TRUE, &pdn_type, + &request->pdnaddress.pdnaddressinformation); + } + request->pdnaddress.pdntypevalue = pdn_type; + if (esm_cause != ESM_CAUSE_SUCCESS) { + /* Set ESM cause */ + request->presencemask |= ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_ESM_CAUSE_PRESENT; + request->esmcause = esm_cause; + } + + } + + return (rsp->header.message_type); +} + +/* + * Process PDN Disconnect Request ESM message + */ +static int _process_pdn_disconnect_request(const pdn_disconnect_request_msg* msg, ESM_msg* rsp) +{ + int pti = msg->proceduretransactionidentity; + int ebi = msg->linkedepsbeareridentity; + + printf("PDN Disconnect Request\n"); + printf("INFO\t:\tProtocolDiscriminator\t\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tEpsBearerIdentity\t\t= %d\n", msg->epsbeareridentity); + printf("INFO\t:\tProcedureTransactionIdentity\t= %d\n", msg->proceduretransactionidentity); + printf("INFO\t:\tMessageType\t\t\t= 0x%.2x\n", msg->messagetype); + printf("INFO\t:\tLinkedEpsBearerIdentity\t= %d\n", msg->linkedepsbeareridentity); + + memset(rsp, 0, sizeof(ESM_msg)); + + rsp->header.protocol_discriminator = EPS_SESSION_MANAGEMENT_MESSAGE; + rsp->header.eps_bearer_identity = ebi; + rsp->header.procedure_transaction_identity = pti; + + static int _pdn_disconnect_reject_counter = 0; + if (_pdn_disconnect_reject_counter > 0) { + sleep(rand()%SLEEP_TIME); + _pdn_disconnect_reject_counter -= 1; + /* XXX - Setup PDN Disconnect Reject message */ + pdn_disconnect_reject_msg* reject = &rsp->pdn_disconnect_reject; + reject->epsbeareridentity = EPS_BEARER_IDENTITY_UNASSIGNED; + reject->messagetype = PDN_DISCONNECT_REJECT; + reject->esmcause = ESM_CAUSE_PROTOCOL_ERROR; + } + else { + /* Setup Deactivate EPS Bearer Request message */ + deactivate_eps_bearer_context_request_msg* request = &rsp->deactivate_eps_bearer_context_request; + request->messagetype = DEACTIVATE_EPS_BEARER_CONTEXT_REQUEST; + request->esmcause = ESM_CAUSE_REGULAR_DEACTIVATION; + } + + return (rsp->header.message_type); +} + +/* + * Process Activate Default EPS Bearer Context Accept ESM message + */ +static int _process_activate_default_eps_bearer_context_accept(const activate_default_eps_bearer_context_accept_msg* msg) +{ + printf("Activate Default EPS Bearer Context Accept\n"); + printf("INFO\t:\tProtocolDiscriminator\t\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tEpsBearerIdentity\t\t= %d\n", msg->epsbeareridentity); + printf("INFO\t:\tProcedureTransactionIdentity\t= %d\n", msg->proceduretransactionidentity); + printf("INFO\t:\tMessageType\t\t\t= 0x%.2x\n", msg->messagetype); + + return (0); +} + +/* + * Process Activate Default EPS Bearer Context Reject ESM message + */ +static int _process_activate_default_eps_bearer_context_reject(const activate_default_eps_bearer_context_reject_msg* msg) +{ + printf("Activate Default EPS Bearer Context Reject\n"); + printf("INFO\t:\tProtocolDiscriminator\t\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tEpsBearerIdentity\t\t= %d\n", msg->epsbeareridentity); + printf("INFO\t:\tProcedureTransactionIdentity\t= %d\n", msg->proceduretransactionidentity); + printf("INFO\t:\tMessageType\t\t\t= 0x%.2x\n", msg->messagetype); + printf("INFO\t:\tESM cause\t\t\t= %d\n", msg->esmcause); + + return (0); +} + +/* + * Process Deactivate EPS Bearer Context Accept ESM message + */ +static int _process_deactivate_eps_bearer_context_accept(const deactivate_eps_bearer_context_accept_msg* msg) +{ + printf("Deactivate EPS Bearer Context Accept\n"); + printf("INFO\t:\tProtocolDiscriminator\t\t= %d\n", msg->protocoldiscriminator); + printf("INFO\t:\tEpsBearerIdentity\t\t= %d\n", msg->epsbeareridentity); + printf("INFO\t:\tProcedureTransactionIdentity\t= %d\n", msg->proceduretransactionidentity); + printf("INFO\t:\tMessageType\t\t\t= 0x%.2x\n", msg->messagetype); + + return (0); +} + +/* + * Assign PDN address according to the network IP capability + */ +static int _assign_pdn_address(int ue_pdn_type, int is_initial, int* pdn_type, OctetString* pdn) +{ + if (_network_simulator_ip_version == NETWORK_IPV4) { + /* The network supports IPv4 addressing only */ + *pdn_type = PDN_VALUE_TYPE_IPV4; + *pdn = *_network_simulator_pdn[NETWORK_IPV4][is_initial]; + if (ue_pdn_type == PDN_TYPE_IPV4V6) { + /* Return ESM cause code #50 */ + return (ESM_CAUSE_PDN_TYPE_IPV4_ONLY_ALLOWED); + } + } + else if (_network_simulator_ip_version == NETWORK_IPV6) { + /* The network supports IPv6 addressing only */ + *pdn_type = PDN_VALUE_TYPE_IPV6; + *pdn = *_network_simulator_pdn[NETWORK_IPV6][is_initial]; + if (ue_pdn_type == PDN_TYPE_IPV4V6) { + /* Return ESM cause code #51 */ + return (ESM_CAUSE_PDN_TYPE_IPV6_ONLY_ALLOWED); + } + } + else { + /* The network supports either IPv4 or IPv6 addressing */ + if (ue_pdn_type != PDN_TYPE_IPV4) { + /* Assign IPv6 address */ + *pdn_type = PDN_VALUE_TYPE_IPV6; + *pdn = *_network_simulator_pdn[NETWORK_IPV6][is_initial]; + } + else { + /* Assign IPv4 address */ + *pdn_type = PDN_VALUE_TYPE_IPV4; + *pdn = *_network_simulator_pdn[NETWORK_IPV4][is_initial]; + } + if (ue_pdn_type == PDN_TYPE_IPV4V6) { + *pdn_type = PDN_VALUE_TYPE_IPV4V6; + *pdn = *_network_simulator_pdn[NETWORK_IPV4V6][is_initial]; + /* Return ESM cause code #52 */ + //return (ESM_CAUSE_SINGLE_ADDRESS_BEARERS_ONLY_ALLOWED); + } + } + return (ESM_CAUSE_SUCCESS); +} + +/* + 07 41 71 0b f6 02 f8 01 01 02 0f 00 00 00 01 05 + 00 00 00 00 00 00 04 02 01 d0 11 52 02 f8 01 00 + + 07 41 71 0b f6 02 f8 01 01 02 0f 00 00 00 01 05 + 00 00 00 00 00 00 04 02 01 d0 11 52 02 f8 01 00 + 01 e0 + */ + +/* + 04 01 04 10 20 8f 10 00 00 00 0f 00 00 00 01 00 + 00 00 1b 00 00 00 07 41 71 0b f6 02 f8 01 01 02 + 0f 00 00 00 01 05 00 00 00 00 00 00 04 02 01 d0 + 11 + + 04 01 04 10 00 00 0f 00 00 00 01 00 00 00 20 8f + 10 00 1b 00 00 00 07 41 71 0b f6 02 f8 01 01 02 + 0f 00 00 00 01 05 00 00 00 00 00 00 04 02 01 d0 + 11 + + 04 01 04 10 00 00 0f 00 00 00 01 00 00 00 20 8f + 10 00 22 00 00 00 07 41 71 0b f6 02 f8 01 01 02 + 0f 00 00 00 01 05 80 80 00 00 00 00 04 02 01 d0 + 31 52 02 f8 01 00 01 e0 + + 04 01 04 10 00 00 0f 00 00 00 01 00 00 00 20 8f + 10 00 28 00 00 00 17 00 00 00 00 00 17 41 01 0b + f6 02 f8 01 01 02 0f 00 00 00 01 05 80 80 00 00 + 00 00 04 02 02 d0 31 52 02 f8 01 00 01 e0 +*/ +/* + U16 msgID = [04 01] - AS_NAS_ESTABLISH_REQ + U8 cause = [04] - NET_ESTABLISH_CAUSE_MO_SIGNAL + U8 type = [10] - NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL + plmn_t plmnID = [20 8f 10] + Byte_t MCCdigit2:4 = [0] + Byte_t MCCdigit1:4 = [2] + Byte_t MNCdigit3:4 = [f] + Byte_t MCCdigit3:4 = [8] + Byte_t MNCdigit2:4 = [0] + Byte_t MNCdigit1:4 = [1] + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 1b] (27 octets) + U8* initialNasMsg = [07 41 71 0b f6 02 f8 01 01 02 0f 00 00 00 01 05] + [00 00 00 00 00 00 04 02 01 d0 11] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [41] - Attach Request + U8:4 NAS KSI = [7] + U8:4 Attach Type = [1] + EPS Mobile Identity = [0b f6 02 f8 01 01 02 0f 00 00 00 01] + Length = [0b] (11 bytes) + U8:4 = 1111 = [f] + U8:1 oddeven = 0 + U8:3 typeofidentity = 110 = [6] + U8:4 mccdigit2 = [0] + U8:4 mccdigit1 = [2] + U8:4 mncdigit3 = [f] + U8:4 mccdigit3 = [8] + U8:4 mncdigit2 = [0] + U8:4 mncdigit1 = [1] + U16 mmegroupid = [01 02] + U8 mmecode = [0f] + U32 mtmsi = [00 00 00 01] + UE network capability = [05 00 00 00 00 00] + Length = [05] (5 bytes) + U8 eea = [00] + U8 eia = [00] + U8 uea = [00] + U8:1 ucs2 = 0 + U8:7 uia = 0000000 = [00] + U8:3 spare = 000 + U8:1 csfb = 0 + U8:1 lpp = 0 + U8:1 lcs = 0 + U8:1 srvcc = 0 + U8:1 nf = 0 = [00] + + ESM message container = [00 04 02 01 d0 11] + Length = [00 04] (4 bytes) + ESM message = [02 01 d0 31] + U8:4 EPS bearer identity = [0] - Not assigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [01] + U8 ESM message identifier = [d0] - PDN Connectivity Request + U8:4 Pdn type = [1] - IPv4 + U8:4 Request type = [1] - Initial request +*/ + +/* + 06 01 0f 00 00 00 01 00 00 00 07 00 00 00 07 43 + 00 03 52 00 c2 + + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 0d 00 + 00 00 27 00 00 00 00 cf 27 43 00 03 52 00 c2 +*/ +/* + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + + U32 Length = [00 00 00 07] (7 octets) + U8* NasMsg = [07 43 00 03 52 00 c2] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [43] - Attach Complete + + ESM message container = [00 03 52 00 c2] + Length = [00 03] (3 bytes) + ESM message = [52 00 c2] + U8:4 EPS bearer identity = [5] + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [00] - Not assigned + U8 ESM message identifier = [c2] - Activate Default EPS Bearer Context Accept + */ + + +/* + 04 08 01 00 00 00 03 00 00 00 07 44 03 + + U16 msgID = [04 08] - AS_NAS_ESTABLISH_CNF + U8 errCode = [01] - AS_SUCCESS + + U32 Length = [00 00 00 03] (3 octets) + U8* initialNasMsg = [07 44 03] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [44] - Attach Reject + U8 EMM cause = [03] - EMM_CAUSE_ILLEGAL_UE + */ + +/* + 06 01 0f 00 00 00 01 00 00 00 17 00 00 00 02 03 + d0 11 28 11 77 77 77 2e 63 6f 6d 34 69 6e 6e 6f + 76 2e 63 6f 6d + + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + U32 Length = [00 00 00 17] (23 octets) + U8* NasMsg = [02 03 d0 11 28 11 77 77 77 2e 63 6f 6d 34 69 6e 6e 6f 76 2e 63 6f 6d] + U8:4 EPS bearer identity = [0] - Unassigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [03] + U8 ESM message identifier = [d0] - PDN Connectivity Request +*/ + +/* + 07 04 04 00 00 00 52 03 d1 6f + + U16 msgID = [07 04] - AS_DL_INFO_TRANSFER_IND + U32 Length = [04 00 00 00] (4 octets) + U8* NasMsg = [52 03 d1 6f] + U8:4 EPS bearer identity = [5] - EBI5 + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [03] + U8 ESM message identifier = [d1] - PDN Connectivity Reject + U8 ESM cause = [6f] - Protocol error, unspecified +*/ +/* + 04 08 01 00 00 00 0a 00 00 00 07 44 13 78 00 04 + 01 d1 6f 00 + U16 msgID = [04 08] - AS_NAS_ESTABLISH_CNF + U8 errCode = [01] - AS_SUCCESS + + U32 Length = [00 00 00 0a] (10 octets) + U8* initialNasMsg = [07 44 13 78 00 04 01 d1 6f 00] + U8:4 Security header type = [0] - Not protected + U8:4 Protocol discriminator = [7] - EMM message + U8 EMM message identifier = [44] - Attach Reject + U8 EMM cause = [13] - EMM_CAUSE_ESM_FAILURE (19) + TLV = [78 00 04 01 d1 6f 00] + IEI = 78 - ESM container + Length = [00 04] - 4 octets + [01 d1 6f 00] + U8:4 EPS bearer identity = [0] + U8:4 Protocol discriminator = [1] - ESM message +*/ + +/* + 06 01 00 00 00 00 0f 00 00 00 01 00 00 00 04 00 + 00 00 02 03 d2 06 + U16 msgID = [06 01] - AS_UL_INFO_TRANSFER_REQ + as_stmsi_t s_tmsi + U8 MMEcode = [0f] + U32 m_tmsi = [00 00 00 01] + U32 Length = [00 00 00 04] (4 octets) + U8* NasMsg = [02 03 d2 06] + + U8:4 EPS bearer identity = [0] - Unassigned + U8:4 Protocol discriminator = [2] - ESM message + U8 Procedure Transaction Identity = [03] + U8 ESM message identifier = [d2] - PDN Disconnect Request + U8:4 Linked EPS bearer identity = [6] - EPS bearer identity = 6 +*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/user/Makefile b/openair-cn/NAS/EURECOM-NAS/tst/user/Makefile new file mode 100644 index 0000000000..269c8e91c6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/user/Makefile @@ -0,0 +1,48 @@ +include ../../Makerules +include ../../Makefile.inc + +PROJDIR = $(PWD)/../.. + +export LD_RUN_PATH = $(LIBDIR) + +LIBS = -lutil -lpthread -lrt +INCLUDES = -I. -I$(SRCDIR) + +TARGET = UserProcess + +all: $(TARGET) + +%.o: %.c Makefile + $(CC) $(CFLAGS) -c $< -o $@ + +$(TARGET): $(OBJS) + $(CC) $(LDFLAGS) -o $@ $^ $(LIBS) + +clean: + $(RM) $(OBJS) *.bak *~ + +veryclean: clean + $(RM) $(TARGET) + +depend: + makedepend -- ${CFLAGS} -- ${SRCS} + +# DO NOT DELETE THIS LINE -- make depend depends on it. + +user_parser.o: user_parser.h +user_parser.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/parser.h +user_simulator.o: user_parser.h +user_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/include/commonDef.h +user_simulator.o: /usr/include/stdint.h /usr/include/features.h +user_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/socket.h +user_simulator.o: /homes/roux/lte-epc/openair3/OPENAIRMME/NAS/EURECOM-NAS/src/util/device.h +user_simulator.o: /usr/include/stdio.h /usr/include/libio.h +user_simulator.o: /usr/include/_G_config.h /usr/include/wchar.h +user_simulator.o: /usr/include/xlocale.h /usr/include/errno.h +user_simulator.o: /usr/include/netdb.h /usr/include/netinet/in.h +user_simulator.o: /usr/include/endian.h /usr/include/rpc/netdb.h +user_simulator.o: /usr/include/ctype.h /usr/include/stdlib.h +user_simulator.o: /usr/include/alloca.h /usr/include/signal.h +user_simulator.o: /usr/include/time.h /usr/include/string.h +user_simulator.o: /usr/include/pthread.h /usr/include/sched.h +user_simulator.o: /usr/include/poll.h diff --git a/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.c b/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.c new file mode 100644 index 0000000000..3994a1777b --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.c @@ -0,0 +1,202 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_parser.c + +Version 0.1 + +Date 2012/10/09 + +Product User Simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the User Simulator process + +*****************************************************************************/ + +#include "user_parser.h" + +#include "util/parser.h" + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +/* + * Identifiers of the User Simulator command line options + */ +enum +{ + USER_PARSER_HOST, /* Remote hostname */ + USER_PARSER_PORT, /* Remote port number */ + USER_PARSER_DEVPATH, /* Device pathname */ + USER_PARSER_DEVATTR, /* Device attribute parameters */ + USER_PARSER_NB_OPTIONS +}; + +/* ---------------------------------------------------------------- + * Definition of the internal User Simulator command line structure + * ---------------------------------------------------------------- + * The command line is defined with a name (default is "UserProcess" + * but it will be replaced by the command name actually used at + * runtime), a number of options and the list of options. + * An option is defined with a name, an argument following the name, + * the usage displayed by the usage function and a default value. + */ +static parser_command_line_t userParserCommandLine = { + "UserProcess", /* Command name */ + USER_PARSER_NB_OPTIONS, /* Number of options */ + { /* Command line options */ + {"-host", "<host>", "\tRemote hostname\t\t", USER_PARSER_DEFAULT_REMOTE_HOSTNAME}, + {"-port", "<port>", "\tRemote port number\t", USER_PARSER_DEFAULT_REMOTE_PORT_NUMBER}, + {"-dev", "<devpath>", "Device pathname\t\t", "NULL"}, + {"-params", "<params>", "Device attribute parameters", "NULL"}, + } +}; + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/**************************************************************************** + ** ** + ** Name: user_parser_print_usage() ** + ** ** + ** Description: Displays the command line options used to run the User ** + ** Simulator process ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: None ** + ** Others: None ** + ** ** + ***************************************************************************/ +void user_parser_print_usage(void) +{ + parser_print_usage(&userParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_options() ** + ** ** + ** Description: Gets the command line options used to run the User ** + ** Simulator process ** + ** ** + ** Inputs: argc: Number of options ** + ** argv: Pointer to the list of options ** + ** Others: None ** + ** ** + ** Outputs: Return: RETURNerror, RETURNok ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_parser_get_options(int argc, const char** argv) +{ + return parser_get_options(argc, argv, &userParserCommandLine); +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_nb_options() ** + ** ** + ** Description: Returns the number of the command line options used to ** + ** run the User Simulator process ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Number of command line options ** + ** Others: None ** + ** ** + ***************************************************************************/ +int user_parser_get_nb_options(void) +{ + return userParserCommandLine.nb_options; +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_host() ** + ** ** + ** Description: Returns the value of the remote hostname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the remote hostname ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* user_parser_get_host(void) +{ + return userParserCommandLine.options[USER_PARSER_HOST].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_port() ** + ** ** + ** Description: Returns the value of the remote port number ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the remote port number ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* user_parser_get_port(void) +{ + return userParserCommandLine.options[USER_PARSER_PORT].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_devpath() ** + ** ** + ** Description: Returns the value of the device pathname ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the device pathname ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* user_parser_get_devpath(void) +{ + return userParserCommandLine.options[USER_PARSER_DEVPATH].pvalue; +} + +/**************************************************************************** + ** ** + ** Name: user_parser_get_devattr() ** + ** ** + ** Description: Returns the value of the device attribute parameters ** + ** ** + ** Inputs: None ** + ** Others: None ** + ** ** + ** Outputs: Return: Value of the device attribute parameters ** + ** Others: None ** + ** ** + ***************************************************************************/ +const char* user_parser_get_devattr(void) +{ + return userParserCommandLine.options[USER_PARSER_DEVATTR].pvalue; +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + diff --git a/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.h b/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.h new file mode 100644 index 0000000000..cb89de578e --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/user/user_parser.h @@ -0,0 +1,56 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_parser.h + +Version 0.1 + +Date 2012/10/09 + +Product User simulator + +Subsystem Command line parser + +Author Frederic Maurel + +Description Command line parser of the user simulator process + +*****************************************************************************/ + +#ifndef __USER_PARSER_H__ +#define __USER_PARSER__H__ + +/****************************************************************************/ +/********************* G L O B A L C O N S T A N T S *******************/ +/****************************************************************************/ + +/* The default remote hostname the User Simulator must connect to */ +#define USER_PARSER_DEFAULT_REMOTE_HOSTNAME "localhost" + +/* The default port number used for the internet service delivered by the + * remote hostname */ +#define USER_PARSER_DEFAULT_REMOTE_PORT_NUMBER "10000" + +/****************************************************************************/ +/************************ G L O B A L T Y P E S ************************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************** G L O B A L V A R I A B L E S ********************/ +/****************************************************************************/ + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +void user_parser_print_usage(void); +int user_parser_get_options(int argc, const char** argv); + +int user_parser_get_nb_options(void); +const char* user_parser_get_host(void); +const char* user_parser_get_port(void); +const char* user_parser_get_devpath(void); +const char* user_parser_get_devattr(void); + +#endif /* __USER_PARSER_H__*/ diff --git a/openair-cn/NAS/EURECOM-NAS/tst/user/user_simulator.c b/openair-cn/NAS/EURECOM-NAS/tst/user/user_simulator.c new file mode 100644 index 0000000000..9efedeffa6 --- /dev/null +++ b/openair-cn/NAS/EURECOM-NAS/tst/user/user_simulator.c @@ -0,0 +1,301 @@ +/***************************************************************************** + Eurecom OpenAirInterface 3 + Copyright(c) 2012 Eurecom + +Source user_simulator.c + +Version 0.1 + +Date 2012/10/09 + +Product User simulator + +Subsystem User simulator main process + +Author Frederic Maurel + +Description Implements the user simulator running at the user application + layer for NAS testing purpose. + +*****************************************************************************/ + +#include "user_parser.h" + +#include "include/commonDef.h" +#include "util/socket.h" +#include "util/device.h" + +#include <stdio.h> // printf, perror +#include <errno.h> // errno +#include <netdb.h> // gai_strerror +#include <ctype.h> // isspace +#include <stdlib.h> // exit +#include <signal.h> // sigaction +#include <string.h> // memset +#include <pthread.h> +#include <poll.h> + +/****************************************************************************/ +/**************** E X T E R N A L D E F I N I T I O N S ****************/ +/****************************************************************************/ + +/****************************************************************************/ +/******************* L O C A L D E F I N I T I O N S *******************/ +/****************************************************************************/ + +#define USER_SIMULATOR_BUFFER_SIZE 1024 + +/* + * String buffer used to send AT commands to the NAS sublayer + */ +static char _user_simulator_send_buffer [USER_SIMULATOR_BUFFER_SIZE]; + +/* + * String buffer used to receive responses from the NAS sublayer + */ +static char _user_simulator_recv_buffer [USER_SIMULATOR_BUFFER_SIZE]; + +/* + * The connection endpoint used for communication with the + * NAS sublayer (see src/api/user/user_api.c) + */ +static struct { + void* endpoint; + void* (*open) (int, const char*, const char*); + int (*getfd)(const void*); + ssize_t (*recv) (void*, char*, size_t); + ssize_t (*send) (const void*, const char*, size_t); + void (*close)(void*); +} _user_simulator_id; +//static socket_id_t * _user_simulator_sid; + +#define USER_OPEN(a, b, c) _user_simulator_id.open(a, b, c) +#define USER_GETFD() _user_simulator_id.getfd(_user_simulator_id.endpoint) +#define USER_RECV(a, b) _user_simulator_id.recv(_user_simulator_id.endpoint, a, b) +#define USER_SEND(a, b) _user_simulator_id.send(_user_simulator_id.endpoint, a, b) +#define USER_CLOSE() _user_simulator_id.close(_user_simulator_id.endpoint) + +static int _set_signal_handler(int signal, void (handler)(int)); +static void _signal_handler(int signal_number); +static void* _receive_thread(void* arg); + +/****************************************************************************/ +/****************** E X P O R T E D F U N C T I O N S ******************/ +/****************************************************************************/ + +/****************************************************************************/ +int main (int argc, const char* argv[]) +{ + /* + * Get the command line options + */ + if ( user_parser_get_options(argc, argv) != RETURNok ) + { + user_parser_print_usage(); + exit(EXIT_FAILURE); + } + const char* host = user_parser_get_host(); + const char* port = user_parser_get_port(); + const char* devpath = user_parser_get_devpath(); + const char* devattr = user_parser_get_devattr(); + + printf("%s -host %s -port %s -dev %s -params %s\n", + argv[0], host, port, devpath, devattr); + + /* + * Initialize the communication channel to the NAS sublayer + */ + if (devpath) + { + /* Initialize device handlers */ + _user_simulator_id.open = device_open; + _user_simulator_id.getfd = device_get_fd; + _user_simulator_id.recv = device_read; + _user_simulator_id.send = device_write; + _user_simulator_id.close = device_close; + + /* Initialize communication channel */ + _user_simulator_id.endpoint = USER_OPEN(DEVICE, devpath, devattr); + if (_user_simulator_id.endpoint == NULL) { + perror("ERROR\t: Failed to open connection endpoint"); + exit(EXIT_FAILURE); + } + + printf("INFO\t: The User Simulator is now connected to %s (%d)\n", + devpath, USER_GETFD()); + } + else + { + /* Initialize network socket handlers */ + _user_simulator_id.open = socket_udp_open; + _user_simulator_id.getfd = socket_get_fd; + _user_simulator_id.recv = socket_recv; + _user_simulator_id.send = socket_send; + _user_simulator_id.close = socket_close; + + /* Initialize communication channel */ + _user_simulator_id.endpoint = USER_OPEN(SOCKET_CLIENT, host, port); + if (_user_simulator_id.endpoint == NULL) { + const char* error = ( (errno < 0) ? + gai_strerror(errno) : strerror(errno) ); + printf("ERROR\t: Failed to open connection endpoint: %s\n", error); + exit(EXIT_FAILURE); + } + + printf("INFO\t: The User Simulator is now connected to %s/%s (%d)\n", + host, port, USER_GETFD()); + } + + + /* + * Set up signal handler + */ + (void) _set_signal_handler(SIGINT, _signal_handler); + (void) _set_signal_handler(SIGTERM, _signal_handler); + + /* + * Create the receiving thread + */ + pthread_attr_t attr; + pthread_t thread_id; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int rc = pthread_create (&thread_id, &attr, _receive_thread, NULL); + if (rc != 0) { + perror("ERROR\t: pthread_create() failed"); + USER_CLOSE(); + exit(EXIT_FAILURE); + } + + /* + * User simulator main loop + */ + while (TRUE) + { + char c; + int len; + + /* Get the AT command */ + printf("AT command (q to quit) > "); + c = getchar(); + if (c == 'q') break; + if (c == '\n') continue; + + len = 0; + while ( (len < USER_SIMULATOR_BUFFER_SIZE - 1) && (c != '\n') ) { + if (!isspace(c)) { + _user_simulator_send_buffer[len++] = c; + } + c = getchar(); + } + _user_simulator_send_buffer[len++] = '\r'; + _user_simulator_send_buffer[len] = '\0'; + + /* Send the AT command to the NAS sublayer */ + int sbytes = USER_SEND(_user_simulator_send_buffer, len); + if (sbytes == RETURNerror) { + perror("ERROR\t: Failed to send data to the NAS sublayer"); + break; + } + +#if 0 + /* Send the AT command one byte at a time (serial port simulation) */ + const char* pbuffer = _user_simulator_send_buffer; + while (*pbuffer) { + int sbytes = USER_SEND(pbuffer++, 1); + if (sbytes == RETURNerror) { + perror("ERROR\t: Failed to send data to the NAS sublayer"); + break; + } + (void)poll(0, 0, 10); + } +#endif + + (void)poll(0, 0, 100); + } + + /* + * Termination cleanup + */ + printf("INFO\t: Closing user endpoint descriptor %d\n", USER_GETFD()); + USER_CLOSE(); + + printf("INFO\t: User simulator exited\n"); + exit(EXIT_SUCCESS); +} + +/****************************************************************************/ +/********************* L O C A L F U N C T I O N S *********************/ +/****************************************************************************/ + +/* + * Signal handler setup function + */ +static int _set_signal_handler(int signal, void (handler)(int)) +{ + struct sigaction act; + + /* Initialize signal set */ + (void) memset (&act, 0, sizeof (act)); + (void) sigfillset (&act.sa_mask); + (void) sigdelset (&act.sa_mask, SIGHUP); + (void) sigdelset (&act.sa_mask, SIGINT); + (void) sigdelset (&act.sa_mask, SIGTERM); + (void) sigdelset (&act.sa_mask, SIGILL); + (void) sigdelset (&act.sa_mask, SIGTRAP); + (void) sigdelset (&act.sa_mask, SIGIOT); +#ifndef LINUX + (void) sigdelset (&act.sa_mask, SIGEMT); +#endif + (void) sigdelset (&act.sa_mask, SIGFPE); + (void) sigdelset (&act.sa_mask, SIGBUS); + (void) sigdelset (&act.sa_mask, SIGSEGV); + (void) sigdelset (&act.sa_mask, SIGSYS); + + /* Initialize signal handler */ + act.sa_handler = handler; + if ( sigaction (signal, &act, 0) < 0 ) { + return RETURNerror; + } + + return RETURNok; +} + +/* + * Signal handler + */ +static void _signal_handler(int signal_number) +{ + printf("\nWARNING\t: Signal %d received\n", signal_number); + printf("INFO\t: Closing user socket %d\n", USER_GETFD()); + USER_CLOSE(); + printf("INFO\t: User simulator exited\n"); + exit(EXIT_SUCCESS); +} + +/* + * Receiving thread + */ +static void* _receive_thread(void* arg) +{ + while (TRUE) + { + /* Receive AT response from the NAS sublayer */ + int rbytes = USER_RECV(_user_simulator_recv_buffer, + USER_SIMULATOR_BUFFER_SIZE); + if (rbytes != 0) { + if (rbytes == RETURNerror) { + perror("ERROR\t: Failed to receive data from the NAS sublayer"); + break; + } + _user_simulator_recv_buffer[rbytes] = '\0'; + + /* Display AT response */ + printf("%s\n", _user_simulator_recv_buffer); + } + } + + return (NULL); +} + diff --git a/openair-cn/NAS/Makefile.am b/openair-cn/NAS/Makefile.am new file mode 100644 index 0000000000..5a55086bba --- /dev/null +++ b/openair-cn/NAS/Makefile.am @@ -0,0 +1,35 @@ +noinst_LTLIBRARIES = libnas.la + +libnas_la_LDFLAGS = -all-static + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -DNAS_MME \ + -DEPC_BUILD \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/api/user \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/api/mme \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/api/network \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/emm/msg \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/emm/sap \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/emm \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/esm/msg \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/esm/sap/msg \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/esm/sap \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/esm \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/ies \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/include \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/util \ + -I$(top_srcdir)/NAS/EURECOM-NAS/src/ \ + -I$(top_srcdir)/UTILS + +if DISABLE_USE_NAS +libnas_la_SOURCES = \ + nas_main.c +else +include Makefile.inc +libnas_la_SOURCES = \ + nas_main.c \ + $(libnas_SRCS) +endif \ No newline at end of file diff --git a/openair-cn/NAS/Makefile.inc b/openair-cn/NAS/Makefile.inc new file mode 100644 index 0000000000..f1e6d9214e --- /dev/null +++ b/openair-cn/NAS/Makefile.inc @@ -0,0 +1,396 @@ +libnas_api_SRCS = \ + EURECOM-NAS/src/api/mme/mme_api.c \ + EURECOM-NAS/src/api/mme/mme_api.h \ + EURECOM-NAS/src/api/network/nas_message.c \ + EURECOM-NAS/src/api/network/nas_message.h + +libnas_emm_SRCS = \ + EURECOM-NAS/src/emm/Attach.c \ + EURECOM-NAS/src/emm/Authentication.c \ + EURECOM-NAS/src/emm/Detach.c \ + EURECOM-NAS/src/emm/EmmCommon.c \ + EURECOM-NAS/src/emm/EmmCommon.h \ + EURECOM-NAS/src/emm/emmData.h \ + EURECOM-NAS/src/emm/emm_data_ctx.c \ + EURECOM-NAS/src/emm/emm_main.c \ + EURECOM-NAS/src/emm/emm_main.h \ + EURECOM-NAS/src/emm/emm_proc.h \ + EURECOM-NAS/src/emm/EmmStatusHdl.c \ + EURECOM-NAS/src/emm/Identification.c \ + EURECOM-NAS/src/emm/IdleMode.c \ + EURECOM-NAS/src/emm/IdleMode.h \ + EURECOM-NAS/src/emm/LowerLayer.c \ + EURECOM-NAS/src/emm/LowerLayer.h \ + EURECOM-NAS/src/emm/SecurityModeControl.c \ + EURECOM-NAS/src/emm/ServiceRequestHdl.c \ + EURECOM-NAS/src/emm/TrackingAreaUpdate.c + +libnas_emm_msg_SRCS = \ + EURECOM-NAS/src/emm/msg/AttachAccept.c \ + EURECOM-NAS/src/emm/msg/AuthenticationFailure.c \ + EURECOM-NAS/src/emm/msg/CsServiceNotification.c \ + EURECOM-NAS/src/emm/msg/emm_cause.h \ + EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.c \ + EURECOM-NAS/src/emm/msg/IdentityResponse.c \ + EURECOM-NAS/src/emm/msg/SecurityModeReject.h \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.h\ + EURECOM-NAS/src/emm/msg/AttachAccept.h \ + EURECOM-NAS/src/emm/msg/AuthenticationFailure.h \ + EURECOM-NAS/src/emm/msg/CsServiceNotification.h \ + EURECOM-NAS/src/emm/msg/EmmInformation.c \ + EURECOM-NAS/src/emm/msg/ExtendedServiceRequest.h \ + EURECOM-NAS/src/emm/msg/IdentityResponse.h \ + EURECOM-NAS/src/emm/msg/ServiceReject.c \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.c\ + EURECOM-NAS/src/emm/msg/AttachComplete.c \ + EURECOM-NAS/src/emm/msg/AuthenticationReject.c \ + EURECOM-NAS/src/emm/msg/DetachAccept.c \ + EURECOM-NAS/src/emm/msg/EmmInformation.h \ + EURECOM-NAS/src/emm/msg/GutiReallocationCommand.c \ + EURECOM-NAS/src/emm/msg/ServiceReject.h \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateReject.h\ + EURECOM-NAS/src/emm/msg/AttachComplete.h \ + EURECOM-NAS/src/emm/msg/AuthenticationReject.h \ + EURECOM-NAS/src/emm/msg/DetachAccept.h \ + EURECOM-NAS/src/emm/msg/emm_msg.c \ + EURECOM-NAS/src/emm/msg/GutiReallocationCommand.h \ + EURECOM-NAS/src/emm/msg/SecurityModeCommand.c \ + EURECOM-NAS/src/emm/msg/ServiceRequest.c \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.c\ + EURECOM-NAS/src/emm/msg/AttachReject.c \ + EURECOM-NAS/src/emm/msg/AuthenticationRequest.c \ + EURECOM-NAS/src/emm/msg/DetachRequest.c \ + EURECOM-NAS/src/emm/msg/emm_msgDef.h \ + EURECOM-NAS/src/emm/msg/GutiReallocationComplete.c \ + EURECOM-NAS/src/emm/msg/SecurityModeCommand.h \ + EURECOM-NAS/src/emm/msg/ServiceRequest.h \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateRequest.h\ + EURECOM-NAS/src/emm/msg/AttachReject.h \ + EURECOM-NAS/src/emm/msg/AuthenticationRequest.h \ + EURECOM-NAS/src/emm/msg/DetachRequest.h \ + EURECOM-NAS/src/emm/msg/emm_msg.h \ + EURECOM-NAS/src/emm/msg/GutiReallocationComplete.h \ + EURECOM-NAS/src/emm/msg/SecurityModeComplete.c \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.c \ + EURECOM-NAS/src/emm/msg/UplinkNasTransport.c\ + EURECOM-NAS/src/emm/msg/AttachRequest.c \ + EURECOM-NAS/src/emm/msg/AuthenticationResponse.c \ + EURECOM-NAS/src/emm/msg/DownlinkNasTransport.c \ + EURECOM-NAS/src/emm/msg/EmmStatus.c \ + EURECOM-NAS/src/emm/msg/IdentityRequest.c \ + EURECOM-NAS/src/emm/msg/SecurityModeComplete.h \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateAccept.h \ + EURECOM-NAS/src/emm/msg/UplinkNasTransport.h\ + EURECOM-NAS/src/emm/msg/AttachRequest.h \ + EURECOM-NAS/src/emm/msg/AuthenticationResponse.h \ + EURECOM-NAS/src/emm/msg/DownlinkNasTransport.h \ + EURECOM-NAS/src/emm/msg/EmmStatus.h \ + EURECOM-NAS/src/emm/msg/IdentityRequest.h \ + EURECOM-NAS/src/emm/msg/SecurityModeReject.c \ + EURECOM-NAS/src/emm/msg/TrackingAreaUpdateComplete.c + +libnas_emm_sap_SRCS = \ + EURECOM-NAS/src/emm/sap/emm_as.c \ \ + EURECOM-NAS/src/emm/sap/emm_as.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredNoImsi.c \ + EURECOM-NAS/src/emm/sap/emm_reg.c \ + EURECOM-NAS/src/emm/sap/EmmRegisteredUpdateNeeded.c \ + EURECOM-NAS/src/emm/sap/emm_asDef.h \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredNormalService.c \ + EURECOM-NAS/src/emm/sap/emm_regDef.h \ + EURECOM-NAS/src/emm/sap/emm_sap.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredPlmnSearch.c \ + EURECOM-NAS/src/emm/sap/emm_reg.h \ + EURECOM-NAS/src/emm/sap/emm_sap.h \ + EURECOM-NAS/src/emm/sap/emm_as.h \ + EURECOM-NAS/src/emm/sap/emm_esm.c \ + EURECOM-NAS/src/emm/sap/EmmRegisteredAttemptingToUpdate.c \ + EURECOM-NAS/src/emm/sap/emm_send.c \ + EURECOM-NAS/src/emm/sap/EmmCommonProcedureInitiated.c \ + EURECOM-NAS/src/emm/sap/emm_esmDef.h \ + EURECOM-NAS/src/emm/sap/EmmRegistered.c \ + EURECOM-NAS/src/emm/sap/emm_send.h \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredAttachNeeded.c \ + EURECOM-NAS/src/emm/sap/emm_esm.h \ + EURECOM-NAS/src/emm/sap/EmmRegisteredImsiDetachInitiated.c \ + EURECOM-NAS/src/emm/sap/EmmServiceRequestInitiated.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredAttemptingToAttach.c \ + EURECOM-NAS/src/emm/sap/emm_fsm.c \ + EURECOM-NAS/src/emm/sap/EmmRegisteredInitiated.c \ + EURECOM-NAS/src/emm/sap/EmmTrackingAreaUpdatingInitiated.c \ + EURECOM-NAS/src/emm/sap/EmmDeregistered.c \ + EURECOM-NAS/src/emm/sap/emm_fsm.h \ + EURECOM-NAS/src/emm/sap/EmmRegisteredLimitedService.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredInitiated.c \ + EURECOM-NAS/src/emm/sap/EmmNull.c \ + EURECOM-NAS/src/emm/sap/EmmRegisteredNoCellAvailable.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredLimitedService.c \ + EURECOM-NAS/src/emm/sap/emm_recv.c \ + EURECOM-NAS/src/emm/sap/EmmRegisteredNormalService.c \ + EURECOM-NAS/src/emm/sap/EmmDeregisteredNoCellAvailable.c \ + EURECOM-NAS/src/emm/sap/emm_recv.h \ + EURECOM-NAS/src/emm/sap/EmmRegisteredPlmnSearch.c + +libnas_esm_SRCS = \ + EURECOM-NAS/src/esm/esm_ebr_context.c \ + EURECOM-NAS/src/esm/PdnConnectivity.c \ + EURECOM-NAS/src/esm/sap/esm_recv.c \ + EURECOM-NAS/src/esm/sap/esm_send.c \ + EURECOM-NAS/src/esm/sap/esm_sap.c \ + EURECOM-NAS/src/esm/esm_ebr.c \ + EURECOM-NAS/src/esm/EpsBearerContextDeactivation.c \ + EURECOM-NAS/src/esm/DefaultEpsBearerContextActivation.c \ + EURECOM-NAS/src/esm/DedicatedEpsBearerContextActivation.c \ + EURECOM-NAS/src/esm/PdnDisconnect.c \ + EURECOM-NAS/src/esm/EsmStatusHdl.c \ + EURECOM-NAS/src/esm/esm_main.c \ + EURECOM-NAS/src/esm/esm_pt.c \ + EURECOM-NAS/src/esm/esm_proc.h \ + EURECOM-NAS/src/esm/esm_main.h \ + EURECOM-NAS/src/esm/sap/esm_recv.h \ + EURECOM-NAS/src/esm/sap/esm_sap.h \ + EURECOM-NAS/src/esm/sap/esm_send.h \ + EURECOM-NAS/src/esm/sap/esm_sapDef.h \ + EURECOM-NAS/src/esm/esm_ebr_context.h \ + EURECOM-NAS/src/esm/esmData.h \ + EURECOM-NAS/src/esm/esm_pt.h \ + EURECOM-NAS/src/esm/esm_ebr.h \ + EURECOM-NAS/src/esm/esm_ip.c + +libnas_esm_msg_SRCS = \ + EURECOM-NAS/src/esm/msg/EsmInformationRequest.h \ + EURECOM-NAS/src/esm/msg/EsmStatus.h \ + EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.h \ + EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.h \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.h \ + EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.h \ + EURECOM-NAS/src/esm/msg/PdnConnectivityReject.h \ + EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.h \ + EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.h \ + EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.h \ + EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.h \ + EURECOM-NAS/src/esm/msg/PdnDisconnectReject.h \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.h \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.h \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.h \ + EURECOM-NAS/src/esm/msg/esm_msg.h \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.h \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.h \ + EURECOM-NAS/src/esm/msg/EsmInformationResponse.h \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.h \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.h \ + EURECOM-NAS/src/esm/msg/esm_cause.h \ + EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.h \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.h \ + EURECOM-NAS/src/esm/msg/esm_msgDef.h \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextRequest.c \ + EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextRequest.c \ + EURECOM-NAS/src/esm/msg/BearerResourceAllocationReject.c \ + EURECOM-NAS/src/esm/msg/BearerResourceModificationRequest.c \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextRequest.c \ + EURECOM-NAS/src/esm/msg/EsmInformationResponse.c \ + EURECOM-NAS/src/esm/msg/PdnDisconnectReject.c \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextAccept.c \ + EURECOM-NAS/src/esm/msg/PdnDisconnectRequest.c \ + EURECOM-NAS/src/esm/msg/BearerResourceModificationReject.c \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextAccept.c \ + EURECOM-NAS/src/esm/msg/ActivateDedicatedEpsBearerContextReject.c \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextAccept.c \ + EURECOM-NAS/src/esm/msg/DeactivateEpsBearerContextAccept.c \ + EURECOM-NAS/src/esm/msg/esm_msg.c \ + EURECOM-NAS/src/esm/msg/EsmInformationRequest.c \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextRequest.c \ + EURECOM-NAS/src/esm/msg/ModifyEpsBearerContextReject.c \ + EURECOM-NAS/src/esm/msg/EsmStatus.c \ + EURECOM-NAS/src/esm/msg/PdnConnectivityReject.c \ + EURECOM-NAS/src/esm/msg/ActivateDefaultEpsBearerContextReject.c \ + EURECOM-NAS/src/esm/msg/PdnConnectivityRequest.c \ + EURECOM-NAS/src/esm/msg/BearerResourceAllocationRequest.c + +libnas_esm_sap_SRCS = \ + EURECOM-NAS/src/esm/sap/esm_recv.c \ + EURECOM-NAS/src/esm/sap/esm_send.c \ + EURECOM-NAS/src/esm/sap/esm_sap.c + +libnas_ies_SRCS = \ + EURECOM-NAS/src/ies/UeSecurityCapability.c \ + EURECOM-NAS/src/ies/SecurityHeaderType.c \ + EURECOM-NAS/src/ies/RadioPriority.c \ + EURECOM-NAS/src/ies/EpsAttachResult.c \ + EURECOM-NAS/src/ies/ImeisvRequest.c \ + EURECOM-NAS/src/ies/EmergencyNumberList.c \ + EURECOM-NAS/src/ies/SupportedCodecList.c \ + EURECOM-NAS/src/ies/EsmCause.c \ + EURECOM-NAS/src/ies/NetworkName.c \ + EURECOM-NAS/src/ies/AuthenticationResponseParameter.c \ + EURECOM-NAS/src/ies/Cli.c \ + EURECOM-NAS/src/ies/AccessPointName.c \ + EURECOM-NAS/src/ies/DaylightSavingTime.c \ + EURECOM-NAS/src/ies/LcsIndicator.c \ + EURECOM-NAS/src/ies/PagingIdentity.c \ + EURECOM-NAS/src/ies/EpsMobileIdentity.c \ + EURECOM-NAS/src/ies/GutiType.c \ + EURECOM-NAS/src/ies/NasKeySetIdentifier.c \ + EURECOM-NAS/src/ies/CsfbResponse.c \ + EURECOM-NAS/src/ies/PacketFlowIdentifier.c \ + EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.c \ + EURECOM-NAS/src/ies/EpsBearerContextStatus.c \ + EURECOM-NAS/src/ies/MobileIdentity.c \ + EURECOM-NAS/src/ies/AuthenticationFailureParameter.c \ + EURECOM-NAS/src/ies/EpsUpdateResult.c \ + EURECOM-NAS/src/ies/TimeZone.c \ + EURECOM-NAS/src/ies/MessageType.c \ + EURECOM-NAS/src/ies/EmmCause.c \ + EURECOM-NAS/src/ies/MobileStationClassmark2.c \ + EURECOM-NAS/src/ies/AuthenticationParameterRand.c \ + EURECOM-NAS/src/ies/PdnAddress.c \ + EURECOM-NAS/src/ies/MobileStationClassmark3.c \ + EURECOM-NAS/src/ies/ServiceType.c \ + EURECOM-NAS/src/ies/RequestType.c \ + EURECOM-NAS/src/ies/PlmnList.c \ + EURECOM-NAS/src/ies/EpsQualityOfService.c \ + EURECOM-NAS/src/ies/NasMessageContainer.c \ + EURECOM-NAS/src/ies/EsmInformationTransferFlag.c \ + EURECOM-NAS/src/ies/TrafficFlowTemplate.c \ + EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.c \ + EURECOM-NAS/src/ies/NasSecurityAlgorithms.c \ + EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.c \ + EURECOM-NAS/src/ies/ShortMac.c \ + EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.c \ + EURECOM-NAS/src/ies/PTmsiSignature.c \ + EURECOM-NAS/src/ies/ProtocolDiscriminator.c \ + EURECOM-NAS/src/ies/EpsBearerIdentity.c \ + EURECOM-NAS/src/ies/TimeZoneAndTime.c \ + EURECOM-NAS/src/ies/TrackingAreaIdentityList.c \ + EURECOM-NAS/src/ies/QualityOfService.c \ + EURECOM-NAS/src/ies/EpsUpdateType.c \ + EURECOM-NAS/src/ies/PdnType.c \ + EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.c \ + EURECOM-NAS/src/ies/AuthenticationParameterAutn.c \ + EURECOM-NAS/src/ies/EpsAttachType.c \ + EURECOM-NAS/src/ies/IdentityType2.c \ + EURECOM-NAS/src/ies/LcsClientIdentity.c \ + EURECOM-NAS/src/ies/DetachType.c \ + EURECOM-NAS/src/ies/LocationAreaIdentification.c \ + EURECOM-NAS/src/ies/TrackingAreaIdentity.c \ + EURECOM-NAS/src/ies/CipheringKeySequenceNumber.c \ + EURECOM-NAS/src/ies/MsNetworkCapability.c \ + EURECOM-NAS/src/ies/UeNetworkCapability.c \ + EURECOM-NAS/src/ies/ProtocolConfigurationOptions.c \ + EURECOM-NAS/src/ies/AdditionalUpdateType.c \ + EURECOM-NAS/src/ies/TmsiStatus.c \ + EURECOM-NAS/src/ies/EsmMessageContainer.c \ + EURECOM-NAS/src/ies/Nonce.c \ + EURECOM-NAS/src/ies/ProcedureTransactionIdentity.c \ + EURECOM-NAS/src/ies/TransactionIdentifier.c \ + EURECOM-NAS/src/ies/AdditionalUpdateResult.c \ + EURECOM-NAS/src/ies/GprsTimer.c \ + EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.c \ + EURECOM-NAS/src/ies/SsCode.c \ + EURECOM-NAS/src/ies/DrxParameter.c \ + EURECOM-NAS/src/ies/KsiAndSequenceNumber.c \ + EURECOM-NAS/src/ies/EpsBearerContextStatus.h \ + EURECOM-NAS/src/ies/MobileStationClassmark2.h \ + EURECOM-NAS/src/ies/LcsClientIdentity.h \ + EURECOM-NAS/src/ies/ServiceType.h \ + EURECOM-NAS/src/ies/Cli.h \ + EURECOM-NAS/src/ies/GprsTimer.h \ + EURECOM-NAS/src/ies/AuthenticationParameterAutn.h \ + EURECOM-NAS/src/ies/EmmCause.h \ + EURECOM-NAS/src/ies/PdnAddress.h \ + EURECOM-NAS/src/ies/QualityOfService.h \ + EURECOM-NAS/src/ies/LocationAreaIdentification.h \ + EURECOM-NAS/src/ies/EmergencyNumberList.h \ + EURECOM-NAS/src/ies/UeRadioCapabilityInformationUpdateNeeded.h \ + EURECOM-NAS/src/ies/SupportedCodecList.h \ + EURECOM-NAS/src/ies/AuthenticationFailureParameter.h \ + EURECOM-NAS/src/ies/MobileIdentity.h \ + EURECOM-NAS/src/ies/UeNetworkCapability.h \ + EURECOM-NAS/src/ies/ShortMac.h \ + EURECOM-NAS/src/ies/MessageType.h \ + EURECOM-NAS/src/ies/AdditionalUpdateType.h \ + EURECOM-NAS/src/ies/NasMessageContainer.h \ + EURECOM-NAS/src/ies/TrafficFlowAggregateDescription.h \ + EURECOM-NAS/src/ies/NasKeySetIdentifier.h \ + EURECOM-NAS/src/ies/NasSecurityAlgorithms.h \ + EURECOM-NAS/src/ies/GutiType.h \ + EURECOM-NAS/src/ies/EpsMobileIdentity.h \ + EURECOM-NAS/src/ies/EpsUpdateType.h \ + EURECOM-NAS/src/ies/TrackingAreaIdentity.h \ + EURECOM-NAS/src/ies/TimeZoneAndTime.h \ + EURECOM-NAS/src/ies/AccessPointName.h \ + EURECOM-NAS/src/ies/PdnType.h \ + EURECOM-NAS/src/ies/LlcServiceAccessPointIdentifier.h \ + EURECOM-NAS/src/ies/DaylightSavingTime.h \ + EURECOM-NAS/src/ies/PagingIdentity.h \ + EURECOM-NAS/src/ies/CsfbResponse.h \ + EURECOM-NAS/src/ies/LcsIndicator.h \ + EURECOM-NAS/src/ies/EsmInformationTransferFlag.h \ + EURECOM-NAS/src/ies/EsmMessageContainer.h \ + EURECOM-NAS/src/ies/ImeisvRequest.h \ + EURECOM-NAS/src/ies/PTmsiSignature.h \ + EURECOM-NAS/src/ies/SsCode.h \ + EURECOM-NAS/src/ies/EpsAttachResult.h \ + EURECOM-NAS/src/ies/UeSecurityCapability.h \ + EURECOM-NAS/src/ies/TimeZone.h \ + EURECOM-NAS/src/ies/EpsBearerIdentity.h \ + EURECOM-NAS/src/ies/IdentityType2.h \ + EURECOM-NAS/src/ies/LinkedEpsBearerIdentity.h \ + EURECOM-NAS/src/ies/PacketFlowIdentifier.h \ + EURECOM-NAS/src/ies/RadioPriority.h \ + EURECOM-NAS/src/ies/Nonce.h \ + EURECOM-NAS/src/ies/KsiAndSequenceNumber.h \ + EURECOM-NAS/src/ies/RequestType.h \ + EURECOM-NAS/src/ies/ProtocolConfigurationOptions.h \ + EURECOM-NAS/src/ies/AuthenticationResponseParameter.h \ + EURECOM-NAS/src/ies/MobileStationClassmark3.h \ + EURECOM-NAS/src/ies/EpsQualityOfService.h \ + EURECOM-NAS/src/ies/DrxParameter.h \ + EURECOM-NAS/src/ies/EsmCause.h \ + EURECOM-NAS/src/ies/ProcedureTransactionIdentity.h \ + EURECOM-NAS/src/ies/TransactionIdentifier.h \ + EURECOM-NAS/src/ies/ProtocolDiscriminator.h \ + EURECOM-NAS/src/ies/EpsAttachType.h \ + EURECOM-NAS/src/ies/AdditionalUpdateResult.h \ + EURECOM-NAS/src/ies/SecurityHeaderType.h \ + EURECOM-NAS/src/ies/TrafficFlowTemplate.h \ + EURECOM-NAS/src/ies/NetworkName.h \ + EURECOM-NAS/src/ies/PlmnList.h \ + EURECOM-NAS/src/ies/TrackingAreaIdentityList.h \ + EURECOM-NAS/src/ies/DetachType.h \ + EURECOM-NAS/src/ies/AuthenticationParameterRand.h \ + EURECOM-NAS/src/ies/EpsUpdateResult.h \ + EURECOM-NAS/src/ies/MsNetworkCapability.h \ + EURECOM-NAS/src/ies/TmsiStatus.h \ + EURECOM-NAS/src/ies/CipheringKeySequenceNumber.h \ + EURECOM-NAS/src/ies/ApnAggregateMaximumBitRate.h \ + EURECOM-NAS/src/ies/EpsNetworkFeatureSupport.h + +libnas_utils_SRCS = \ + EURECOM-NAS/src/util/nas_log.h \ + EURECOM-NAS/src/util/nas_log.c \ + EURECOM-NAS/src/util/TLVEncoder.h \ + EURECOM-NAS/src/util/TLVEncoder.c \ + EURECOM-NAS/src/util/TLVDecoder.h \ + EURECOM-NAS/src/util/TLVDecoder.c \ + EURECOM-NAS/src/util/OctetString.h \ + EURECOM-NAS/src/util/OctetString.c + +libnas_SRCS = \ + EURECOM-NAS/src/nas_network.c \ + EURECOM-NAS/src/nas_network.h \ + EURECOM-NAS/src/nas_parser.c \ + EURECOM-NAS/src/nas_parser.h \ + EURECOM-NAS/src/nas_proc.c \ + EURECOM-NAS/src/nas_proc.h \ + EURECOM-NAS/src/nas_user.c \ + EURECOM-NAS/src/nas_user.h \ + $(libnas_utils_SRCS) \ + $(libnas_emm_SRCS) \ + $(libnas_emm_msg_SRCS) \ + $(libnas_emm_sap_SRCS) \ + $(libnas_esm_SRCS) \ + $(libnas_esm_msg_SRCS) \ + $(libnas_esm_sap_SRCS) \ + $(libnas_ies_SRCS) \ + $(libnas_api_SRCS) diff --git a/openair-cn/NAS/nas_defs.h b/openair-cn/NAS/nas_defs.h new file mode 100644 index 0000000000..c60a1b6bc6 --- /dev/null +++ b/openair-cn/NAS/nas_defs.h @@ -0,0 +1,6 @@ +#ifndef NAS_DEFS_H_ +#define NAS_DEFS_H_ + +int nas_init(const mme_config_t *mme_config_p); + +#endif /* NAS_DEFS_H_ */ diff --git a/openair-cn/NAS/nas_main.c b/openair-cn/NAS/nas_main.c new file mode 100644 index 0000000000..5f70a7608f --- /dev/null +++ b/openair-cn/NAS/nas_main.c @@ -0,0 +1,108 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "intertask_interface.h" + +#include "nas_defs.h" + +#if !defined(DISABLE_USE_NAS) +# include "nas_proc.h" +# include "emm_main.h" +# include "nas_log.h" +#endif + +#define NAS_ERROR(x, args...) do { fprintf(stderr, "[NAS] [E]"x, ##args); } while(0) +#define NAS_DEBUG(x, args...) do { fprintf(stdout, "[NAS] [D]"x, ##args); } while(0) +#define NAS_WARN(x, args...) do { fprintf(stdout, "[NAS] [W]"x, ##args); } while(0) + +static void *nas_intertask_interface(void *args_p) +{ + intertask_interface_mark_task_ready(TASK_NAS); + + while(1) { + MessageDef *received_message_p; + +next_message: + receive_msg(TASK_NAS, &received_message_p); + switch(received_message_p->header.messageId) { + case NAS_CONNECTION_ESTABLISHMENT_IND: { +#if defined(DISABLE_USE_NAS) + MessageDef *message_p; + nas_attach_req_t *nas_req_p; + s1ap_initial_ue_message_t *transparent; + + NAS_DEBUG("NAS abstraction: Generating NAS ATTACH REQ\n"); + + message_p = alloc_new_message(TASK_NAS, NAS_ATTACH_REQ); + + nas_req_p = &message_p->msg.nas_attach_req; + transparent = &message_p->msg.nas_attach_req.transparent; + + nas_req_p->initial = INITIAL_REQUEST; + sprintf(nas_req_p->imsi, "%14llu", 20834123456789ULL); + + memcpy(transparent, &received_message_p->msg.nas_conn_est_ind.transparent, + sizeof(s1ap_initial_ue_message_t)); + + send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); +#else + nas_establish_ind_t *nas_est_ind_p; + + nas_est_ind_p = &received_message_p->msg.nas_conn_est_ind.nas; + + nas_proc_establish_ind(nas_est_ind_p->UEid, + nas_est_ind_p->tac, + nas_est_ind_p->initialNasMsg.data, + nas_est_ind_p->initialNasMsg.length); +#endif + } break; + case NAS_ATTACH_ACCEPT: { + send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, received_message_p); + goto next_message; + } break; + case NAS_AUTHENTICATION_REQ: { + MessageDef *message_p; + nas_auth_resp_t *nas_resp_p; + + NAS_DEBUG("NAS abstraction: Generating NAS AUTHENTICATION RESPONSE\n"); + + message_p = alloc_new_message(TASK_NAS, NAS_AUTHENTICATION_RESP); + + nas_resp_p = &message_p->msg.nas_auth_resp; + + memcpy(nas_resp_p->imsi, received_message_p->msg.nas_auth_req.imsi, 16); + + send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); + } break; + default: { + NAS_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int nas_init(const mme_config_t *mme_config_p) +{ + NAS_DEBUG("Initializing NAS task interface\n"); +#if !defined(DISABLE_USE_NAS) + nas_log_init(LOG_DEBUG); + emm_main_initialize(); +#endif + + if (intertask_interface_create_task(TASK_NAS, &nas_intertask_interface, + NULL) < 0) { + NAS_ERROR("Create task failed"); + NAS_DEBUG("Initializing NAS task interface: FAILED\n"); + return -1; + } + NAS_DEBUG("Initializing NAS task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/NEWS b/openair-cn/NEWS new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/openair-cn/NEWS @@ -0,0 +1 @@ + diff --git a/openair-cn/OAISIM_MME/Makefile.am b/openair-cn/OAISIM_MME/Makefile.am new file mode 100644 index 0000000000..15ad6c0324 --- /dev/null +++ b/openair-cn/OAISIM_MME/Makefile.am @@ -0,0 +1,43 @@ +if !STANDALONE_EPC +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/GTPV1-U \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/include \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/shared \ + -I$(top_srcdir)/SCTP \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/SGI \ + -I$(top_srcdir)/MME_APP \ + -I$(top_srcdir)/NAS \ + -I$(top_srcdir)/S11 \ + -I$(top_builddir)/S1AP/MESSAGES \ + -I$(top_srcdir)/S1AP \ + -I$(top_srcdir)/S6A \ + -I$(top_srcdir)/SECU \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UDP \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE \ + -I$(top_srcdir)/UTILS/TIMER + +oaisim_mme_LDADD = \ + $(top_builddir)/INTERTASK_INTERFACE/libitti.la \ + $(top_builddir)/NAS/libnas.la \ + $(top_builddir)/S11/libs11.la \ + $(top_builddir)/S1AP/libs1ap.la \ + $(top_builddir)/S6A/libs6a.la \ + $(top_builddir)/SCTP/libsctpserver.la \ + $(top_builddir)/UTILS/TIMER/libtimer.la \ + $(top_builddir)/UTILS/HASHTABLE/libhashtable.la \ + $(top_builddir)/UDP/libudpserver.la \ + $(top_builddir)/MME_APP/libmmeapp.la \ + $(top_builddir)/SECU/libsecu.la \ + $(top_builddir)/UTILS/libutils.la \ + $(top_builddir)/GTPV2-C/nwgtpv2c-0.11/src/libNwGtpv2c.a + +oaisim_mme_SOURCES = \ + oai_mme_log.c \ + oaisim_mme.c + +bin_PROGRAMS = oaisim_mme +endif \ No newline at end of file diff --git a/openair-cn/OAISIM_MME/oai_mme_log.c b/openair-cn/OAISIM_MME/oai_mme_log.c new file mode 100644 index 0000000000..5c22df0116 --- /dev/null +++ b/openair-cn/OAISIM_MME/oai_mme_log.c @@ -0,0 +1,54 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "oaisim_mme.h" +#include "log.h" + +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> + +int oai_mme_log_specific(int log_level) +{ + if (log_level == 1) { + asn_debug = 0; + asn1_xer_print = 1; + fd_g_debug_lvl = INFO; + } else if (log_level == 2) { + asn_debug = 1; + asn1_xer_print = 1; + fd_g_debug_lvl = ANNOYING; + } else { + asn1_xer_print = 0; + asn_debug = 0; + fd_g_debug_lvl = NONE; + } + + return 0; +} diff --git a/openair-cn/OAISIM_MME/oaisim_mme.c b/openair-cn/OAISIM_MME/oaisim_mme.c new file mode 100644 index 0000000000..d3f5d4aa4e --- /dev/null +++ b/openair-cn/OAISIM_MME/oaisim_mme.c @@ -0,0 +1,100 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "assertions.h" +#include "mme_config.h" +#include "gtpv1u_sgw_defs.h" + +#include "signals.h" + +#include "intertask_interface_init.h" + +#include "sctp_primitives_server.h" +#include "udp_primitives_server.h" +#include "s1ap_mme.h" +#include "log.h" +#include "timer.h" +#include "sgw_lite_defs.h" +#include "sgi.h" +#include "mme_app_extern.h" +#include "nas_defs.h" +#include "s11_mme.h" + +/* FreeDiameter headers for support of S6A interface */ +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> +#include "s6a_defs.h" + +#include "oaisim_mme.h" + +int main(int argc, char *argv[]) +{ + /* Initialize signals */ + CHECK_INIT_RETURN(signal_init()); + + /* Parse the command line for options and set the mme_config accordingly. */ + CHECK_INIT_RETURN(config_parse_opt_line(argc, argv, &mme_config)); + + /* Calling each layer init function */ + CHECK_INIT_RETURN(log_init(&mme_config, oai_mme_log_specific)); + CHECK_INIT_RETURN(intertask_interface_init(&mme_config, THREAD_MAX, + MESSAGES_ID_MAX, threads_name, + messages_info, + messages_definition_xml)); + CHECK_INIT_RETURN(timer_init(&mme_config)); + + CHECK_INIT_RETURN(nas_init(&mme_config)); + CHECK_INIT_RETURN(sctp_init(&mme_config)); + CHECK_INIT_RETURN(udp_init(&mme_config)); + CHECK_INIT_RETURN(s11_mme_init(&mme_config)); + CHECK_INIT_RETURN(s1ap_mme_init(&mme_config)); +// if (sgi_init(&mme_config) < 0) return -1; +// if (gtpv1u_init(&mme_config) < 0) return -1; + CHECK_INIT_RETURN(mme_app_init(&mme_config)); + + CHECK_INIT_RETURN(s6a_init(&mme_config)); +// if (sgw_lite_init(&mme_config) < 0) return -1; + + /* Handle signals here */ + while(1) { + signal_handle(); + } + + return 0; +} diff --git a/openair-cn/OAISIM_MME/oaisim_mme.h b/openair-cn/OAISIM_MME/oaisim_mme.h new file mode 100644 index 0000000000..ce3a3d0c6b --- /dev/null +++ b/openair-cn/OAISIM_MME/oaisim_mme.h @@ -0,0 +1,33 @@ +/** @mainpage + + @section intro Introduction + + openair-mme project tends to provide an implementation of LTE core network. + + @section scope Scope + + + @section design Design Philosophy + + Included protocol stacks: + - SCTP RFC#### + - S1AP 3GPP TS 36.413 R10.5 + - S11 abstraction between MME and S-GW + - 3GPP TS 23.401 R10.5 + - nw-gtpv1u for s1-u (http://amitchawre.net/) + - freeDiameter project (http://www.freediameter.net/) 3GPP TS 29.272 R10.5 + + @section applications Applications and Usage + + Please use the script to start LTE epc in root src directory + + */ + +#ifndef OAISIM_MME_H_ +#define OAISIM_MME_H_ + +int main(int argc, char *argv[]); + +int oai_mme_log_specific(int log_level); + +#endif /* OAISIM_MME_H_ */ diff --git a/openair-cn/OAI_EPC/Makefile.am b/openair-cn/OAI_EPC/Makefile.am new file mode 100644 index 0000000000..cf3d363bd9 --- /dev/null +++ b/openair-cn/OAI_EPC/Makefile.am @@ -0,0 +1,43 @@ +if STANDALONE_EPC +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/GTPV1-U \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/include \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/shared \ + -I$(top_srcdir)/SCTP \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/SGI \ + -I$(top_srcdir)/MME_APP \ + -I$(top_srcdir)/NAS \ + -I$(top_builddir)/S1AP/MESSAGES \ + -I$(top_srcdir)/S1AP \ + -I$(top_srcdir)/S6A \ + -I$(top_srcdir)/SECU \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UDP \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE \ + -I$(top_srcdir)/UTILS/TIMER + +oai_epc_LDADD = \ + $(top_builddir)/GTPV1-U/libgtpv1u.la \ + $(top_builddir)/GTPV2-C/nwgtpv2c-0.11/src/libNwGtpv2c.a \ + $(top_builddir)/INTERTASK_INTERFACE/libitti.la \ + $(top_builddir)/SGI/libsgi.la \ + $(top_builddir)/NAS/libnas.la \ + $(top_builddir)/S6A/libs6a.la \ + $(top_builddir)/SGW-LITE/libsgw_lite.la \ + $(top_builddir)/SCTP/libsctpserver.la \ + $(top_builddir)/UTILS/HASHTABLE/libhashtable.la \ + $(top_builddir)/UDP/libudpserver.la \ + $(top_builddir)/MME_APP/libmmeapp.la \ + $(top_builddir)/SECU/libsecu.la \ + $(top_builddir)/UTILS/libutils.la \ + $(top_builddir)/S1AP/libs1ap.la + +oai_epc_SOURCES = \ + oai_epc_log.c \ + oai_epc.c + +bin_PROGRAMS = oai_epc +endif diff --git a/openair-cn/OAI_EPC/oai_epc.c b/openair-cn/OAI_EPC/oai_epc.c new file mode 100644 index 0000000000..ea2aa9a17e --- /dev/null +++ b/openair-cn/OAI_EPC/oai_epc.c @@ -0,0 +1,105 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! @file oai_epc.c + * @brief Entry point for EPC environement gathering MME, S-GW and P-GW in + * a single executable + */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "mme_config.h" +#include "gtpv1u_sgw_defs.h" + +#include "assertions.h" +#include "signals.h" + +#include "intertask_interface_init.h" + +#include "sctp_primitives_server.h" +#include "udp_primitives_server.h" +#include "s1ap_mme.h" +#include "log.h" +#include "timer.h" +#include "sgw_lite_defs.h" +#include "sgi.h" +#include "mme_app_extern.h" +#include "nas_defs.h" + +/* FreeDiameter headers for support of S6A interface */ +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> +#include "s6a_defs.h" + +#include "oai_epc.h" + +int main(int argc, char *argv[]) +{ + /* Initialize signals. Note that signals should be initialized before + * other threads are created as it will block signals for child threads. + */ + CHECK_INIT_RETURN(signal_init()); + + /* Parse the command line for options and set the mme_config accordingly. */ + CHECK_INIT_RETURN(config_parse_opt_line(argc, argv, &mme_config) < 0); + + /* Calling each layer init function */ + CHECK_INIT_RETURN(log_init(&mme_config, oai_epc_log_specific)); + CHECK_INIT_RETURN(intertask_interface_init(THREAD_MAX, MESSAGES_ID_MAX, + threads_name, messages_info, + messages_definition_xml)); + + CHECK_INIT_RETURN(nas_init(&mme_config)); + CHECK_INIT_RETURN(sctp_init(&mme_config)); + CHECK_INIT_RETURN(udp_init(&mme_config)); + CHECK_INIT_RETURN(s1ap_mme_init(&mme_config)); + CHECK_INIT_RETURN(sgi_init(&mme_config)); + CHECK_INIT_RETURN(gtpv1u_init(&mme_config)); + CHECK_INIT_RETURN(mme_app_init(&mme_config)); + + CHECK_INIT_RETURN(s6a_init(&mme_config)); + + CHECK_INIT_RETURN(sgw_lite_init(&mme_config)); + + /* Handle signals here */ + while(1) { + signal_handle(); + } + + return 0; +} diff --git a/openair-cn/OAI_EPC/oai_epc.h b/openair-cn/OAI_EPC/oai_epc.h new file mode 100644 index 0000000000..d627f2bf11 --- /dev/null +++ b/openair-cn/OAI_EPC/oai_epc.h @@ -0,0 +1,33 @@ +/** @mainpage + + @section intro Introduction + + openair-mme project tends to provide an implementation of LTE core network. + + @section scope Scope + + + @section design Design Philosophy + + Included protocol stacks: + - SCTP RFC#### + - S1AP 3GPP TS 36.413 R10.5 + - S11 abstraction between MME and S-GW + - 3GPP TS 23.401 R10.5 + - nw-gtpv1u for s1-u (http://amitchawre.net/) + - freeDiameter project (http://www.freediameter.net/) 3GPP TS 29.272 R10.5 + + @section applications Applications and Usage + + Please use the script to start LTE epc in root src directory + + */ + +#ifndef OAI_EPC_H_ +#define OAI_EPC_H_ + +int oai_epc_log_specific(int log_level); + +int main(int argc, char *argv[]); + +#endif /* OAI_EPC_H_ */ diff --git a/openair-cn/OAI_EPC/oai_epc_log.c b/openair-cn/OAI_EPC/oai_epc_log.c new file mode 100644 index 0000000000..9f34e35a33 --- /dev/null +++ b/openair-cn/OAI_EPC/oai_epc_log.c @@ -0,0 +1,54 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "oai_epc.h" +#include "log.h" + +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> + +int oai_epc_log_specific(int log_level) +{ + if (log_level == 1) { + asn_debug = 0; + asn1_xer_print = 1; + fd_g_debug_lvl = INFO; + } else if (log_level == 2) { + asn_debug = 1; + asn1_xer_print = 1; + fd_g_debug_lvl = ANNOYING; + } else { + asn1_xer_print = 0; + asn_debug = 0; + fd_g_debug_lvl = NONE; + } + + return 0; +} diff --git a/openair-cn/OAI_SGW/Makefile.am b/openair-cn/OAI_SGW/Makefile.am new file mode 100644 index 0000000000..d76e2ec9e7 --- /dev/null +++ b/openair-cn/OAI_SGW/Makefile.am @@ -0,0 +1,34 @@ +if !STANDALONE_EPC +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/GTPV1-U \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/include \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/shared \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/S11 \ + -I$(top_srcdir)/SGI \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UDP \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE \ + -I$(top_srcdir)/UTILS/TIMER + +oai_sgw_LDADD = \ + $(top_builddir)/GTPV1-U/libgtpv1u.la \ + $(top_builddir)/INTERTASK_INTERFACE/libitti.la \ + $(top_builddir)/S11/libs11.la \ + $(top_builddir)/GTPV2-C/nwgtpv2c-0.11/src/libNwGtpv2c.a \ + $(top_builddir)/SGI/libsgi.la \ + $(top_builddir)/SGW-LITE/libsgw_lite.la \ + $(top_builddir)/UTILS/TIMER/libtimer.la \ + $(top_builddir)/UTILS/HASHTABLE/libhashtable.la \ + $(top_builddir)/UDP/libudpserver.la \ + $(top_builddir)/SECU/libsecu.la \ + $(top_builddir)/UTILS/libutils.la + +oai_sgw_SOURCES = \ + oai_sgw_log.c \ + oai_sgw.c + +bin_PROGRAMS = oai_sgw +endif \ No newline at end of file diff --git a/openair-cn/OAI_SGW/oai_sgw.c b/openair-cn/OAI_SGW/oai_sgw.c new file mode 100644 index 0000000000..8ab322a04e --- /dev/null +++ b/openair-cn/OAI_SGW/oai_sgw.c @@ -0,0 +1,85 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "assertions.h" +#include "mme_config.h" + +#include "signals.h" + +#include "intertask_interface_init.h" + +#include "udp_primitives_server.h" +#include "log.h" +#include "timer.h" +#include "s11_sgw.h" +#include "sgw_lite_defs.h" +#include "gtpv1u_sgw_defs.h" +#include "sgi.h" + +#include "oai_sgw.h" + +int main(int argc, char *argv[]) +{ + /* Initialize signals */ + CHECK_INIT_RETURN(signal_init()); + + /* Parse the command line for options and set the mme_config accordingly. */ + CHECK_INIT_RETURN(config_parse_opt_line(argc, argv, &mme_config)); + + /* Calling each layer init function */ + CHECK_INIT_RETURN(log_init(&mme_config, oai_sgw_log_specific)); + CHECK_INIT_RETURN(intertask_interface_init(THREAD_MAX, MESSAGES_ID_MAX, + threads_name, messages_info, + messages_definition_xml)); + + CHECK_INIT_RETURN(udp_init(&mme_config)); + CHECK_INIT_RETURN(s11_sgw_init(&mme_config)); + CHECK_INIT_RETURN(gtpv1u_init(&mme_config)); + CHECK_INIT_RETURN(sgi_init(&mme_config)); + + CHECK_INIT_RETURN(sgw_lite_init(&mme_config)); + + /* Handle signals here */ + while(1) { + signal_handle(); + } + + return 0; +} diff --git a/openair-cn/OAI_SGW/oai_sgw.h b/openair-cn/OAI_SGW/oai_sgw.h new file mode 100644 index 0000000000..d5fdc03ddc --- /dev/null +++ b/openair-cn/OAI_SGW/oai_sgw.h @@ -0,0 +1,38 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef OAI_SGW_H_ +#define OAI_SGW_H_ + +int main(int argc, char *argv[]); + +int oai_sgw_log_specific(int log_level); + +#endif /* OAI_SGW_H_ */ diff --git a/openair-cn/OAI_SGW/oai_sgw_log.c b/openair-cn/OAI_SGW/oai_sgw_log.c new file mode 100644 index 0000000000..ca5e171fc6 --- /dev/null +++ b/openair-cn/OAI_SGW/oai_sgw_log.c @@ -0,0 +1,37 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "oai_sgw.h" +#include "log.h" + +int oai_sgw_log_specific(int log_level) +{ + return 0; +} diff --git a/openair-cn/README b/openair-cn/README new file mode 100644 index 0000000000..08c7575eb9 --- /dev/null +++ b/openair-cn/README @@ -0,0 +1,128 @@ +=============================================================================== +***************************** OAISIM_MME v0.3 ********************************* +=============================================================================== + +MME + P-GW + S-GW implementation of 3GPP standard. + +|-----| |------| +| MME | ----- | eNBs | +|-----| |------| + +Controle plane: + + eNB MME HSS + + |----------------------------| + | MME Application layer | + |----------------------------| + |------------| |-------------| |-------------| |--------------| + | NAS | | AUC |--| Mysql | --- | Database | + |------------| |-------------| |-------------| |--------------| +|------------| |------------| |------------| |--------------| |------------------------------| +| RRC | - | S1AP layer | ------ | S1AP layer | | S6A/Diameter | ------ | S6A/Diameter | +|------------| |------------| |------------| |--------------| |------------------------------| + |------------| |------------------------------| |------------------------------| + | SCTP layer | ------ | SCTP layer | ------ | SCTP layer | + |------------| |------------------------------| |------------------------------| + + +Non-UE associated control plane goes directly from S1AP to MME application layer. + +User plane: + + eNB MME + +|------------| |------------| +| PDCP | | MAL | +|------------| |------------| +|------------| |------------| +| S1-U | ------ | S1-U | +|------------| |------------| +|------------| |------------| +| GTPV1-U | ------ | GTPV1-U | +|------------| |------------| +|------------| |------------| +| UDP layer | ------ | UDP layer | +|------------| |------------| + +Current development: + +- NAS layer: under development +- S1AP layer: compliant with 3GPP TS36.413-8a0 and TS36.413-980 and TS35.413-a50 +- SCTP layer: SEQ_PACKET socket types + +For now the MME is able to register new eNBs on SCTP layer, +and handles S1 Setup request, Initial UE message, UplinkNASTransport on +S1AP layer. + +The MME needs some libraries and tools: +- libsctp-dev (SCTP support) +- libpthread-dev +- asn1c utility (patched with Aligned PER support, see README in +S1AP/MESSAGES/ASN1) +- flex +- bison + +To install the dependencies: +sudo apt-get install libsctp-dev libpthread-dev flex bison g++ gcc make -y +A script is present in S6A/freediameter to install required packages for +S6A interface over diameter + +install_openvswitch1.9.0.bash +cd S6A/freediameter/README + +Compilations steps for use with oaisim 4G emulation environment: +./autogen.sh or autoreconf -i --force --install +mkdir objs && cd objs +../configure [options] +make + +Compilations steps for oaisim_mme use alone: +./autogen.sh +./configure [options] +make + +Current options supported for configure: +--enable-r8: disable R9 and R10 S1AP messages updates +--enable-r9: disable R10 updates +code build switch: UPDATE_RELEASE_9 and UPDATE_RELEASE_10 +NOTE: Release 10 is enabled by default +--enable-standalone-epc: all-in-one package, MME, S-GW and P-GW are compiled in a single +executable and S11 interface is not used; messages are exchanged internally, +linking MME applicative layer to S+P-GW applicative layer + +How to run EPC environnement ? + +If you avec enabled the standalone option +the package is called oai_epc in the OAI_EPC directory. + +If you have decided to use the S11 interface, +two executables should be run on different machines + +* oai_sgw in OAI_SGW +* oaisim_mme in OAISIM_MME + +For example to rum mme: +./OAISIM_MME/oaisim_mme [options] +Avalaible options: +-h: print help +-v: enable verbosity level [1-2] +-V: print current executable version and return + +Before any commit: +make maintainer-clean + +MME SCTP port for S1AP messages is 36412 +SGW and eNB GTP-u port is 2152 +SGW and MME GTP-c port is 2123 + +-------- Adding new files to build system -------- +1) When adding a new file to compile, edit the Makefile.am of the corresponding + directory. +2) Execute ./autogen.sh +3) make +WARNING: do not edit directly Makefiles and Makefile.in, they are re-generated by + autoconf/automake. + +Bugs: +report any bug to openair_admin@eurecom.fr diff --git a/openair-cn/S11/Makefile.am b/openair-cn/S11/Makefile.am new file mode 100644 index 0000000000..18fa144126 --- /dev/null +++ b/openair-cn/S11/Makefile.am @@ -0,0 +1,20 @@ +noinst_LTLIBRARIES = libs11.la + +libs11_la_LDFLAGS = -all-static + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/GTPV2-C/nwgtpv2c-0.11/shared \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UTILS + +libs11_la_SOURCES = \ + s11_common.c s11_common.h \ + s11_ie_formatter.c s11_ie_formatter.h \ + s11_mme_task.c s11_mme.h \ + s11_sgw.c s11_sgw.h \ + s11_mme_session_manager.c s11_mme_session_manager.h \ + s11_sgw_session_manager.c s11_sgw_session_manager.h \ + s11_sgw_bearer_manager.c s11_sgw_bearer_manager.h \ No newline at end of file diff --git a/openair-cn/S11/s11_common.c b/openair-cn/S11/s11_common.c new file mode 100644 index 0000000000..9b3a4e39a2 --- /dev/null +++ b/openair-cn/S11/s11_common.c @@ -0,0 +1,18 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "NwGtpv2c.h" + +#include "s11_common.h" + +NwRcT s11_ie_indication_generic(NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T *ieValue, + void *arg) +{ + S11_DEBUG("Received IE Parse Indication for of type %u, length %u, " + "instance %u!\n", ieType, ieLength, ieInstance); + return NW_OK; +} diff --git a/openair-cn/S11/s11_common.h b/openair-cn/S11/s11_common.h new file mode 100644 index 0000000000..fcb0ae078e --- /dev/null +++ b/openair-cn/S11/s11_common.h @@ -0,0 +1,15 @@ +#ifndef S11_COMMON_H_ +#define S11_COMMON_H_ + +#define S11_DEBUG(x, args...) fprintf(stdout, "[S11] [D]"x, ##args) +#define S11_INFO(x, args...) fprintf(stdout, "[S11] [I]"x, ##args) +#define S11_WARN(x, args...) fprintf(stdout, "[S11] [W]"x, ##args) +#define S11_ERROR(x, args...) fprintf(stderr, "[S11] [E]"x, ##args) + +NwRcT s11_ie_indication_generic(NwU8T ieType, + NwU8T ieLength, + NwU8T ieInstance, + NwU8T *ieValue, + void *arg); + +#endif /* S11_COMMON_H_ */ diff --git a/openair-cn/S11/s11_ie_formatter.c b/openair-cn/S11/s11_ie_formatter.c new file mode 100644 index 0000000000..5f8024395b --- /dev/null +++ b/openair-cn/S11/s11_ie_formatter.c @@ -0,0 +1,1081 @@ + +#include <stdio.h> +#include <stdint.h> +#include "assertions.h" +#include "conversions.h" + +#include "sgw_lite_messages_types.h" + +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" + +#include "s11_common.h" +#include "s11_ie_formatter.h" + +NwRcT s11_imsi_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + Imsi_t *imsi; + uint8_t i; + uint8_t mask = 0x0F; + uint8_t imsi_length = 2 * ieLength; + + DevAssert(arg != NULL); + imsi = (Imsi_t *)arg; + + for (i = 0; i < ieLength * 2; i++) { + if (mask == 0x0F) { + imsi->digit[i] = (ieValue[i / 2] & (mask)); + } else { + imsi->digit[i] = (ieValue[i / 2] & (mask)) >> 4; + } + imsi->digit[i] += '0'; + mask = ~mask; + } + + if (imsi->digit[imsi_length - 1] == (0x0f + '0')) { + imsi->digit[imsi_length - 1] = 0; + imsi_length--; + } + + imsi->length = imsi_length; + + S11_DEBUG("\t- IMSI length %d\n", imsi->length); + S11_DEBUG("\t- value %*s\n", imsi->length, imsi->digit); + + return NW_OK; +} + +int s11_imsi_ie_set(NwGtpv2cMsgHandleT *msg, const Imsi_t *imsi) +{ + uint8_t *temp = NULL; + uint8_t imsi_length, i; + NwRcT rc; + + DevAssert(msg != NULL); + DevAssert(imsi != NULL); + + /* In case of odd/even imsi */ + imsi_length = imsi->length % 2 == 0 ? imsi->length / 2 : imsi->length / 2 + 1; + + temp = calloc(imsi_length, sizeof(uint8_t)); + + DevAssert(temp != NULL); + + for (i = 0; i < imsi->length; i++) { + temp[i / 2] |= ((imsi->digit[i] - '0') & 0x0F) << (i % 2 ? 4 : 0); + } + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_IMSI, imsi_length, 0, temp); + DevAssert(NW_OK == rc); + + free(temp); + + return 0; +} + +NwRcT s11_msisdn_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + Msisdn_t *msisdn; + uint8_t i; + uint8_t mask = 0x0F; + uint8_t msisdn_length = 2 * ieLength; + + DevAssert(arg != NULL); + msisdn = (Msisdn_t *)arg; + + for (i = 0; i < ieLength * 2; i++) { + if (mask == 0x0F) { + msisdn->digit[i] = (ieValue[i / 2] & (mask)); + } else { + msisdn->digit[i] = (ieValue[i / 2] & (mask)) >> 4; + } + msisdn->digit[i] += '0'; + mask = ~mask; + } + + if (msisdn->digit[msisdn_length - 1] == (0x0f + '0')) { + msisdn->digit[msisdn_length - 1] = 0; + msisdn_length--; + } + + msisdn->length = msisdn_length; + + S11_DEBUG("\t- MSISDN length %d\n", msisdn->length); + S11_DEBUG("\t- value %*s\n", msisdn->length, (char *)msisdn->digit); + + return NW_OK; +} + +NwRcT s11_mei_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + Mei_t *mei = (Mei_t *)arg; + + DevAssert(mei != NULL); + + + + return NW_OK; +} + +NwRcT s11_pdn_type_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + pdn_type_t *pdn_type = (pdn_type_t *)arg; + + DevAssert(pdn_type != NULL); + + if (*ieValue == 1) { + /* Only IPv4 */ + *pdn_type = IPv4; + } else if (*ieValue == 2) { + /* Only IPv6 */ + *pdn_type = IPv6; + } else if (*ieValue == 3) { + /* IPv4 and/or IPv6 */ + *pdn_type = IPv4_AND_v6; + } else { + S11_ERROR("Received unknown value for PDN Type: %u\n", *ieValue); + return NW_GTPV2C_IE_INCORRECT; + } + + S11_DEBUG("\t- PDN type %u\n", *pdn_type); + + return NW_OK; +} + +int s11_pdn_type_ie_set(NwGtpv2cMsgHandleT *msg, const pdn_type_t *pdn_type) +{ + NwRcT rc; + uint8_t value; + + DevAssert(pdn_type != NULL); + DevAssert(msg != NULL); + + switch (*pdn_type) { + case IPv4: + value = 1; + break; + case IPv6: + value = 2; + break; + case IPv4_AND_v6: + case IPv4_OR_v6: + value = 3; + break; + default: + S11_ERROR("Invalid PDN type received: %d\n", *pdn_type); + return -1; + } + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_PDN_TYPE, 1, 0, (NwU8T*)&value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_rat_type_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + rat_type_t *rat_type = (rat_type_t *)arg; + + DevAssert(rat_type != NULL); + + switch (*ieValue) { + case 1: + *rat_type = RAT_UTRAN; + break; + case 2: + *rat_type = RAT_GERAN; + break; + case 3: + *rat_type = RAT_WLAN; + break; + case 4: + *rat_type = RAT_GAN; + break; + case 5: + *rat_type = RAT_HSPA_EVOLUTION; + break; + case 6: + *rat_type = RAT_EUTRAN; + break; + default: + S11_ERROR("Can't map GTP RAT type %u to EPC definition\n" + "\tCheck TS.29.274 #8.17 for possible values\n", *ieValue); + return NW_GTPV2C_IE_INCORRECT; + } + + S11_DEBUG("\t- RAT type (%d): %d\n", *ieValue, *rat_type); + + return NW_OK; +} + +int s11_rat_type_ie_set(NwGtpv2cMsgHandleT *msg, const rat_type_t *rat_type) +{ + NwRcT rc; + uint8_t value; + + DevAssert(rat_type != NULL); + DevAssert(msg != NULL); + + switch (*rat_type) { + case RAT_UTRAN: + value = 1; + break; + case RAT_GERAN: + value = 2; + break; + case RAT_WLAN: + value = 3; + break; + case RAT_GAN: + value = 4; + break; + case RAT_HSPA_EVOLUTION: + value = 5; + break; + case RAT_EUTRAN: + value = 6; + break; + default: + S11_ERROR("Can't map RAT type %d to GTP RAT type\n" + "\tCheck TS.29.274 #8.17 for possible values\n", *rat_type); + return -1; + } + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_RAT_TYPE, 1, 0, (NwU8T*)&value); + DevAssert(NW_OK == rc); + + return 0; +} + +int s11_ebi_ie_set(NwGtpv2cMsgHandleT *msg, const unsigned ebi) +{ + NwRcT rc; + uint8_t value = 0; + + value = ebi & 0x0F; + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_EBI, 1, 0, + &value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_ebi_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + uint8_t *ebi = (uint8_t *)arg; + + DevAssert(ebi != NULL); + + *ebi = ieValue[0] & 0x0F; + + S11_DEBUG("\t- EBI %u\n", *ebi); + + return NW_OK; +} + +NwRcT s11_cause_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + SGWCause_t *cause = (SGWCause_t *)arg; + + DevAssert(cause != NULL); + + *cause = ieValue[0]; + + S11_DEBUG("\t- Cause %u\n", *cause); + + return NW_OK; +} + +int s11_cause_ie_set(NwGtpv2cMsgHandleT *msg, + const gtp_cause_t *cause) +{ + NwRcT rc; + uint8_t value[6]; + + DevAssert(msg != NULL); + DevAssert(cause != NULL); + + value[0] = cause->cause_value; + value[1] = ((cause->pce & 0x1) << 2) | ((cause->bce & 0x1) << 1) | (cause->cs & 0x1); + if (cause->offending_ie_type != 0) { + value[2] = cause->offending_ie_type; + value[3] = (cause->offending_ie_length & 0xFF00) >> 8; + value[4] = cause->offending_ie_length & 0x00FF; + value[5] = cause->offending_ie_instance & 0x0F; + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_CAUSE, 6, 0, value); + } else { + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_CAUSE, 2, 0, value); + } + + DevAssert(NW_OK == rc); + + return rc == NW_OK ? 0 : -1; +} + +NwRcT s11_bearer_context_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + bearer_to_create_t *bearer_to_create = (bearer_to_create_t *)arg; + uint8_t read = 0; + NwRcT rc; + + DevAssert(bearer_to_create != NULL); + + while (ieLength > read) { + NwGtpv2cIeTlvT *ie_p; + + ie_p = (NwGtpv2cIeTlvT*)&ieValue[read]; + + switch (ie_p->t) { + case NW_GTPV2C_IE_EBI: + rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_to_create->eps_bearer_id); + DevAssert(NW_OK == rc); + break; + case NW_GTPV2C_IE_BEARER_LEVEL_QOS: + break; + default: + S11_ERROR("Received unexpected IE %u\n", ie_p->t); + return NW_GTPV2C_IE_INCORRECT; + } + + read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT)); + } + + return NW_OK; +} + +int s11_bearer_context_to_create_ie_set( + NwGtpv2cMsgHandleT *msg, const bearer_to_create_t *bearer_to_create) +{ + NwRcT rc; + + DevAssert(msg != NULL); + DevAssert(bearer_to_create != NULL); + + /* Start section for grouped IE: bearer context to create */ + rc = nwGtpv2cMsgGroupedIeStart(*msg, NW_GTPV2C_IE_BEARER_CONTEXT, + NW_GTPV2C_IE_INSTANCE_ZERO); + DevAssert(NW_OK == rc); + + s11_ebi_ie_set(msg, bearer_to_create->eps_bearer_id); + + /* End section for grouped IE: bearer context to create */ + rc = nwGtpv2cMsgGroupedIeEnd(*msg); + DevAssert(NW_OK == rc); + return 0; +} + +NwRcT s11_bearer_context_to_modifiy_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + bearer_context_to_modify_t *bearer_to_modify = (bearer_context_to_modify_t *)arg; + uint8_t read = 0; + NwRcT rc; + + DevAssert(bearer_to_modify != NULL); + + while (ieLength > read) { + NwGtpv2cIeTlvT *ie_p; + + ie_p = (NwGtpv2cIeTlvT*)&ieValue[read]; + + switch (ie_p->t) { + case NW_GTPV2C_IE_EBI: + rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_to_modify->eps_bearer_id); + DevAssert(NW_OK == rc); + break; + case NW_GTPV2C_IE_FTEID: + rc = s11_fteid_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_to_modify->s1_eNB_fteid); + break; + default: + S11_ERROR("Received unexpected IE %u\n", ie_p->t); + return NW_GTPV2C_IE_INCORRECT; + } + + read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT)); + } + + return NW_OK; +} + +NwRcT s11_bearer_context_created_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + bearer_context_created_t *bearer_created = (bearer_context_created_t *)arg; + uint8_t read = 0; + NwRcT rc; + + DevAssert(bearer_created != NULL); + + while (ieLength > read) { + NwGtpv2cIeTlvT *ie_p; + + ie_p = (NwGtpv2cIeTlvT*)&ieValue[read]; + + switch (ie_p->t) { + case NW_GTPV2C_IE_EBI: + rc = s11_ebi_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_created->eps_bearer_id); + DevAssert(NW_OK == rc); + break; + case NW_GTPV2C_IE_FTEID: + rc = s11_fteid_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_created->s1u_sgw_fteid); + break; + case NW_GTPV2C_IE_CAUSE: + rc = s11_cause_ie_get(ie_p->t, ie_p->l, ie_p->i, + &ieValue[read + sizeof(NwGtpv2cIeTlvT)], + &bearer_created->cause); + break; + default: + S11_ERROR("Received unexpected IE %u\n", ie_p->t); + return NW_GTPV2C_IE_INCORRECT; + } + + read += (ntohs(ie_p->l) + sizeof(NwGtpv2cIeTlvT)); + } + return NW_OK; +} + +int s11_bearer_context_created_ie_set( + NwGtpv2cMsgHandleT *msg, const bearer_context_created_t *bearer) +{ + NwRcT rc; + + DevAssert(msg != NULL); + DevAssert(bearer != NULL); + + /* Start section for grouped IE: bearer context created */ + rc = nwGtpv2cMsgGroupedIeStart(*msg, NW_GTPV2C_IE_BEARER_CONTEXT, + NW_GTPV2C_IE_INSTANCE_ZERO); + DevAssert(NW_OK == rc); + + s11_ebi_ie_set(msg, bearer->eps_bearer_id); + + rc = nwGtpv2cMsgAddIeCause(*msg, NW_GTPV2C_IE_INSTANCE_ZERO, bearer->cause, + 0, 0, 0); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgAddIeFteid(*msg, NW_GTPV2C_IE_INSTANCE_ZERO, + bearer->s1u_sgw_fteid.interface_type, + bearer->s1u_sgw_fteid.teid, + bearer->s1u_sgw_fteid.ipv4 ? htonl(bearer->s1u_sgw_fteid.ipv4_address) : 0, + bearer->s1u_sgw_fteid.ipv6 ? (NwU8T*)bearer->s1u_sgw_fteid.ipv6_address : NULL); + DevAssert(NW_OK == rc); + + /* End section for grouped IE: bearer context created */ + rc = nwGtpv2cMsgGroupedIeEnd(*msg); + DevAssert(NW_OK == rc); + + return 0; +} + +/* This IE shall be included in the E-UTRAN initial attach, + * PDP Context Activation and UE Requested PDN connectivity procedures. + * This IE denotes the most stringent restriction as required + * by any already active bearer context. If there are no already active bearer + * contexts, this value is set to the least restrictive type. + */ +int s11_apn_restriction_ie_set( + NwGtpv2cMsgHandleT *msg, const uint8_t apn_restriction) +{ + NwRcT rc; + + DevAssert(msg != NULL); + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_APN_RESTRICTION, 1, 0, + (NwU8T *)&apn_restriction); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_serving_network_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + ServingNetwork_t *serving_net = (ServingNetwork_t *)arg; + + DevAssert(serving_net != NULL); + + serving_net->mcc[1] = (ieValue[0] & 0xF0) >> 4; + serving_net->mcc[0] = (ieValue[0] & 0x0F); + serving_net->mcc[2] = (ieValue[1] & 0x0F); + if ((ieValue[1] & 0xF0) == 0xF0) { + /* Two digits MNC */ + serving_net->mnc[0] = 0; + serving_net->mnc[2] = (ieValue[2] & 0xF0) >> 4; + serving_net->mnc[1] = (ieValue[2] & 0x0F); + } else { + serving_net->mnc[0] = (ieValue[1] & 0xF0) >> 4; + serving_net->mnc[2] = (ieValue[2] & 0xF0) >> 4; + serving_net->mnc[1] = (ieValue[2] & 0x0F); + } + + S11_DEBUG("\t- Serving network %d.%d\n", + serving_net->mcc[0] * 100 + serving_net->mcc[1] * 10 + + serving_net->mcc[2], + serving_net->mnc[0] * 100 + serving_net->mnc[1] * 10 + + serving_net->mnc[2]); + + return NW_OK; +} + +int s11_serving_network_ie_set( + NwGtpv2cMsgHandleT *msg, + const ServingNetwork_t *serving_network) +{ + NwRcT rc; + uint8_t value[3]; + + DevAssert(msg != NULL); + DevAssert(serving_network != NULL); + + /* MCC Decimal | MCC Hundreds */ + value[0] = ((serving_network->mcc[1] & 0x0F) << 4) | + (serving_network->mcc[2] & 0x0F); + value[1] = serving_network->mcc[0] & 0x0F; + + if ((serving_network->mnc[0] & 0xF) == 0xF) { + /* Only two digits */ + value[1] |= 0xF0; + value[2] = ((serving_network->mnc[2] & 0x0F) << 4) | + (serving_network->mnc[1] & 0x0F); + } else { + value[1] |= (serving_network->mnc[2] & 0x0F) << 4; + value[2] = ((serving_network->mnc[1] & 0x0F) << 4) | + (serving_network->mnc[0] & 0x0F); + } + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_SERVING_NETWORK, 3, 0, value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_fteid_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + uint8_t offset = 0; + FTeid_t *fteid = (FTeid_t *)arg; + + DevAssert(fteid != NULL); + + fteid->ipv4 = (ieValue[0] & 0x80) >> 7; + fteid->ipv6 = (ieValue[0] & 0x40) >> 6; + + fteid->interface_type = ieValue[0] & 0x1F; + S11_DEBUG("\t- F-TEID type %d\n", fteid->interface_type); + + /* Copy the TEID or GRE key */ + fteid->teid = ntoh_int32_buf(&ieValue[1]); + + S11_DEBUG("\t- TEID/GRE %08x\n", fteid->teid); + + if (fteid->ipv4 == 1) { + /* IPv4 present: copy the 4 bytes */ + memcpy(&fteid->ipv4_address, &ieValue[5], 4); + offset = 4; + + S11_DEBUG("\t- IPv4 addr "IPV4_ADDR"\n", + IPV4_ADDR_FORMAT(fteid->ipv4_address)); + } + + if (fteid->ipv6 == 1) { + char ipv6_ascii[40]; + /* IPv6 present: copy the 16 bytes + * WARNING: if Ipv4 is present, 4 bytes of offset should be applied + */ + memcpy(fteid->ipv6_address, &ieValue[5 + offset], 16); + + inet_ntop(AF_INET6, fteid->ipv6_address, ipv6_ascii, 40); + S11_DEBUG("\t- IPv6 addr %s\n", ipv6_ascii); + } + + return NW_OK; +} + +NwRcT s11_paa_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + uint8_t offset = 0; + PAA_t *paa = (PAA_t *)arg; + + DevAssert(paa != NULL); + + paa->pdn_type = ieValue[0] & 0x07; + S11_DEBUG("\t- PAA type %d\n", paa->pdn_type); + if (paa->pdn_type & 0x2) { + char ipv6_ascii[40]; + /* IPv6 present: copy the 16 bytes + * WARNING: if both ipv4 and ipv6 are present, + * 17 bytes of offset should be applied for ipv4 + * NOTE: an ipv6 prefix length is prepend + * NOTE: in Rel.8 the prefix length has a default value of /64 + */ + paa->ipv6_prefix_length = ieValue[1]; + memcpy(paa->ipv6_address, &ieValue[2], 16); + + inet_ntop(AF_INET6, paa->ipv6_address, ipv6_ascii, 40); + S11_DEBUG("\t- IPv6 addr %s/%u\n", ipv6_ascii, paa->ipv6_prefix_length); + } + if (paa->pdn_type == 3) { + offset = 17; + } + if (paa->pdn_type & 0x1) { + memcpy(paa->ipv4_address, &ieValue[1 + offset], 4); + + S11_DEBUG("\t- IPv4 addr "IPV4_ADDR"\n", + paa->ipv4_address[0], paa->ipv4_address[1], + paa->ipv4_address[2], paa->ipv4_address[3]); + } + paa->pdn_type -= 1; + return NW_OK; +} + +int s11_paa_ie_set(NwGtpv2cMsgHandleT *msg, const PAA_t *paa) +{ + /* ipv4 address = 4 + ipv6 address = 16 + ipv6 prefix length = 1 + * + pdn_type = 1 + * = maximum of 22 bytes + */ + uint8_t temp[22]; + uint8_t pdn_type; + uint8_t offset = 0; + NwRcT rc; + + DevAssert(paa != NULL); + + pdn_type = paa->pdn_type + 1; + + temp[offset] = pdn_type; + offset++; + + if (pdn_type & 0x2) { + /* If ipv6 or ipv4v6 present */ + temp[1] = paa->ipv6_prefix_length; + memcpy(&temp[2], paa->ipv6_address, 16); + offset += 17; + } + + if (pdn_type & 0x1) { + memcpy(&temp[offset], paa->ipv4_address, 4); + offset += 4; + } + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_PAA, offset, 0, + temp); + DevAssert(NW_OK == rc); + + return 0; +} + +/* The encoding of the APN shall follow the Name Syntax defined in RFC 2181, + * RFC 1035 and RFC 1123. The APN consists of one or more labels. Each label + * is coded as a one octet length field followed by that number of octets + * coded as 8 bit ASCII characters. Following RFC 1035 the labels shall consist + * only of the alphabetic characters (A-Z and a-z), digits (0-9) + * and the hyphen (-). + */ +NwRcT s11_apn_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + uint8_t read = 1; + uint8_t word_length; + char *apn = (char *)arg; + + DevAssert(apn != NULL); + + DevCheck(ieLength <= APN_MAX_LENGTH, ieLength, APN_MAX_LENGTH, 0); + + word_length = ieValue[0]; + + while (read < ieLength) { + if (word_length > 0) { + apn[read - 1] = ieValue[read]; + word_length--; + } else { + /* This is not an alphanumeric character */ + word_length = ieValue[read]; + /* Replace the length attribute by '.' */ + apn[read - 1] = '.'; + } + + read ++; + } + apn[read - 1] = '\0'; + + S11_DEBUG("\t- APN %s\n", apn); + + return NW_OK; +} + +int s11_apn_ie_set(NwGtpv2cMsgHandleT *msg, const char *apn) +{ + NwRcT rc; + uint8_t *value; + uint8_t apn_length; + uint8_t offset = 0; + uint8_t *last_size; + uint8_t word_length = 0; + + DevAssert(apn != NULL); + DevAssert(msg != NULL); + + apn_length = strlen(apn); + + value = calloc(apn_length + 1, sizeof(uint8_t)); + last_size = &value[0]; + + while (apn[offset]) { + /* We replace the . by the length of the word */ + if (apn[offset] == '.') { + *last_size = word_length; + word_length = 0; + last_size = &value[offset + 1]; + } else { + word_length++; + value[offset + 1] = apn[offset]; + } + offset++; + } + + *last_size = word_length; + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_APN, apn_length + 1, 0, value); + DevAssert(NW_OK == rc); + + free(value); + + return 0; +} + +NwRcT s11_ambr_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + ambr_t *ambr = (ambr_t *)arg; + + DevAssert(ambr != NULL); + + ambr->br_ul = ntoh_int32_buf(&ieValue[0]); + ambr->br_dl = ntoh_int32_buf(&ieValue[4]); + + S11_DEBUG("\t- AMBR UL %u\n", ambr->br_ul); + S11_DEBUG("\t- AMBR DL %u\n", ambr->br_dl); + + return NW_OK; +} + +NwRcT s11_uli_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + Uli_t *uli = (Uli_t *)arg; + + DevAssert(uli != NULL); + + uli->present = ieValue[0]; + + if (uli->present & ULI_CGI) { + + } + return NW_OK; +} + +int s11_bearer_qos_ie_set(NwGtpv2cMsgHandleT *msg, const BearerQOS_t *bearer_qos) +{ + NwRcT rc; + uint8_t value[18]; + + DevAssert(msg != NULL); + DevAssert(bearer_qos != NULL); + + value[0] = (bearer_qos->pci << 6) | (bearer_qos->pl << 2) | (bearer_qos->pvi); + value[1] = bearer_qos->qci; + + /* TODO: check endianness */ + memcpy(&value[2], &bearer_qos->mbr.br_ul, 4); + memcpy(&value[6], &bearer_qos->mbr.br_dl, 4); + memcpy(&value[10], &bearer_qos->gbr.br_ul, 4); + memcpy(&value[14], &bearer_qos->gbr.br_dl, 4); + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_BEARER_LEVEL_QOS, 18, 0, value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_ip_address_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + gtp_ip_address_t *ip_address = (gtp_ip_address_t *)arg; + + DevAssert(ip_address != NULL); + + if (ieLength == 4) { + /* This is an IPv4 Address */ + ip_address->present = GTP_IP_ADDR_v4; + memcpy(ip_address->address.v4, ieValue, 4); + } else if (ieLength == 16) { + /* This is an IPv6 Address */ + ip_address->present = GTP_IP_ADDR_v6; + memcpy(ip_address->address.v6, ieValue, 16); + } else { + /* Length doesn't lie in possible values */ + return NW_GTPV2C_IE_INCORRECT; + } + return NW_OK; +} + +int s11_ip_address_ie_set(NwGtpv2cMsgHandleT *msg, + const gtp_ip_address_t *ip_address) +{ + return 0; +} + +NwRcT s11_delay_value_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + DelayValue_t *delay_value = (DelayValue_t *)arg; + + DevAssert(arg != NULL); + + if (ieLength != 1) { + return NW_GTPV2C_IE_INCORRECT; + } + + *delay_value = ieValue[0]; + + S11_DEBUG("\t - Delay Value %u\n", *delay_value); + + return NW_OK; +} + +int s11_delay_value_ie_set(NwGtpv2cMsgHandleT *msg, + const DelayValue_t *delay_value) +{ + uint8_t value; + NwRcT rc; + + DevAssert(msg != NULL); + DevAssert(delay_value != NULL); + + value = *delay_value; + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_DELAY_VALUE, 1, 0, (NwU8T*)&value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_ue_time_zone_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + UETimeZone_t *ue_time_zone = (UETimeZone_t *)arg; + + DevAssert(ue_time_zone != NULL); + + if (ieLength != 2) { + return NW_GTPV2C_IE_INCORRECT; + } + + ue_time_zone->time_zone = ieValue[0]; + ue_time_zone->daylight_saving_time = ieValue[1] & 0x03; + + S11_DEBUG("\t - Time Zone %u\n", ue_time_zone->time_zone); + S11_DEBUG("\t - Daylight SVT %u\n", ue_time_zone->daylight_saving_time); + + return NW_OK; +} + +int s11_ue_time_zone_ie_set(NwGtpv2cMsgHandleT *msg, + const UETimeZone_t *ue_time_zone) +{ + uint8_t value[2]; + NwRcT rc; + + DevAssert(msg != NULL); + DevAssert(ue_time_zone != NULL); + + value[0] = ue_time_zone->time_zone; + value[1] = ue_time_zone->daylight_saving_time; + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_UE_TIME_ZONE, 2, 0, value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_target_identification_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + target_identification_t *target_identification = (target_identification_t *)arg; + + DevAssert(target_identification != NULL); + + target_identification->target_type = ieValue[0]; + switch (target_identification->target_type) { + case TARGET_ID_RNC_ID: + { + target_identification->target_id.rnc_id.lac = (ieValue[4] << 8) | + ieValue[5]; + target_identification->target_id.rnc_id.rac = ieValue[6]; + if (ieLength == 11) { + /* Extended RNC id */ + target_identification->target_id.rnc_id.rnc_id = (ieValue[7] << 24) | + (ieValue[8] << 16) | (ieValue[9] << 8) | (ieValue[10]); + } else if (ieLength == 9) { + /* Normal RNC id */ + target_identification->target_id.rnc_id.rnc_id = (ieValue[7] << 8) | + ieValue[8]; + } else { + /* This case is not possible */ + return NW_GTPV2C_IE_INCORRECT; + } + S11_DEBUG("\t\t- LAC 0x%04x\n", target_identification->target_id.rnc_id.lac); + S11_DEBUG("\t\t- RAC 0x%02x\n", target_identification->target_id.rnc_id.rac); + S11_DEBUG("\t\t- RNC 0x%08x\n", target_identification->target_id.rnc_id.rnc_id); + } break; + case TARGET_ID_MACRO_ENB_ID: { + if (ieLength != 9) { + return NW_GTPV2C_IE_INCORRECT; + } + target_identification->target_id.macro_enb_id.enb_id = ((ieValue[4] & 0x0F) << 16) | + (ieValue[5] << 8) | ieValue[6]; + target_identification->target_id.macro_enb_id.tac = (ieValue[7] << 8) | ieValue[8]; + S11_DEBUG("\t\t- ENB Id 0x%06x\n", target_identification->target_id.macro_enb_id.enb_id); + S11_DEBUG("\t\t- TAC 0x%04x\n", target_identification->target_id.macro_enb_id.tac); + } break; + case TARGET_ID_HOME_ENB_ID: { + if (ieLength != 10) { + return NW_GTPV2C_IE_INCORRECT; + } + target_identification->target_id.home_enb_id.enb_id = ((ieValue[4] & 0x0F) << 14) | + (ieValue[5] << 16) | (ieValue[6] << 8) | ieValue[7]; + target_identification->target_id.home_enb_id.tac = (ieValue[8] << 8) | ieValue[9]; + S11_DEBUG("\t\t- ENB Id 0x%07x\n", target_identification->target_id.home_enb_id.enb_id); + S11_DEBUG("\t\t- TAC 0x%04x\n", target_identification->target_id.home_enb_id.tac); + } break; + default: + return NW_GTPV2C_IE_INCORRECT; + } + + return NW_OK; +} + +NwRcT s11_bearer_flags_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + bearer_flags_t *bearer_flags = (bearer_flags_t *)arg; + + DevAssert(arg != NULL); + + if (ieLength != 1) { + return NW_GTPV2C_IE_INCORRECT; + } + + bearer_flags->ppc = ieValue[0] & 0x01; + bearer_flags->vb = ieValue[0] & 0x02; + + return NW_OK; +} + +int s11_bearer_flags_ie_set(NwGtpv2cMsgHandleT *msg, + const bearer_flags_t *bearer_flags) +{ + NwRcT rc; + uint8_t value; + + DevAssert(msg != NULL); + DevAssert(bearer_flags != NULL); + + value = (bearer_flags->vb << 1) | bearer_flags->ppc; + + rc = nwGtpv2cMsgAddIe(*msg, NW_GTPV2C_IE_BEARER_FLAGS, 1, 0, (NwU8T*)&value); + DevAssert(NW_OK == rc); + + return 0; +} + +NwRcT s11_indication_flags_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + indication_flags_t *indication_flags = (indication_flags_t*)arg; + + DevAssert(indication_flags != NULL); + + if (ieLength < 3) { + return NW_GTPV2C_IE_INCORRECT; + } + + *indication_flags = ieValue[0] | (ieValue[1] << 8) | (ieValue[2] << 16); + + S11_DEBUG("\t- Indication Flags %06x\n", *indication_flags); + + return NW_OK; +} + +NwRcT s11_fqcsid_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg) +{ + FQ_CSID_t *fq_csid = (FQ_CSID_t *)arg; + + DevAssert(fq_csid != NULL); + + fq_csid->node_id_type = (ieValue[0] & 0xF0) >> 4; + S11_DEBUG("\t- FQ-CSID type %u\n", fq_csid->node_id_type); + + /* NOTE: Values of Number of CSID other than 1 are only employed in the + * Delete PDN Connection Set Request and Response. + */ + if ((ieValue[0] & 0x0F) != 1) { + return NW_GTPV2C_IE_INCORRECT; + } + switch (fq_csid->node_id_type) { + case GLOBAL_UNICAST_IPv4: { + if (ieLength != 7) { + return NW_GTPV2C_IE_INCORRECT; + } + fq_csid->node_id.unicast_ipv4 = (ieValue[1] << 24) | + (ieValue[2] << 16) | (ieValue[3] << 8) | (ieValue[4]); + fq_csid->csid = (ieValue[5] << 8) | ieValue[6]; + + S11_DEBUG("\t- v4 address ["IPV4_ADDR"]\n", + IPV4_ADDR_FORMAT(fq_csid->node_id.unicast_ipv4)); + } break; + case GLOBAL_UNICAST_IPv6: { + char ipv6[40]; + if (ieLength != 19) { + return NW_GTPV2C_IE_INCORRECT; + } + memcpy(fq_csid->node_id.unicast_ipv6, &ieValue[1], 16); + fq_csid->csid = (ieValue[17] << 8) | ieValue[18]; + + /* Convert the ipv6 to printable string */ + inet_ntop(AF_INET6, fq_csid->node_id.unicast_ipv6, ipv6, 40); + + S11_DEBUG("\t- v6 address [%s]\n", fq_csid->node_id.unicast_ipv6); + } break; + default: + return NW_GTPV2C_IE_INCORRECT; + } + + S11_DEBUG("\t- CSID 0x%04x\n", fq_csid->csid); + return NW_OK; +} diff --git a/openair-cn/S11/s11_ie_formatter.h b/openair-cn/S11/s11_ie_formatter.h new file mode 100644 index 0000000000..568ebdbc8e --- /dev/null +++ b/openair-cn/S11/s11_ie_formatter.h @@ -0,0 +1,209 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S11_IE_FORMATTER_H_ +#define S11_IE_FORMATTER_H_ + +/* Imsi Information Element + * 3GPP TS.29.274 #8.3 + * NOTE: Imsi is TBCD coded + * octet 5 | Number digit 2 | Number digit 1 | + * octet n+4 | Number digit m | Number digit m-1 | + */ +NwRcT s11_imsi_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_imsi_ie_set(NwGtpv2cMsgHandleT *msg, const Imsi_t *imsi); + +NwRcT s11_msisdn_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* PDN Type Information Element + * 3GPP TS 29.274 #8.34 + * PDN type: + * * 1 = IPv4 + * * 2 = IPv6 + * * 3 = IPv4v6 + */ +NwRcT s11_pdn_type_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_pdn_type_ie_set(NwGtpv2cMsgHandleT *msg, const pdn_type_t *pdn_type); + +/* RAT type Information Element + * WARNING: the RAT type used in MME and S/P-GW is not the same as the one + * for S11 interface defined in 3GPP TS 29.274 #8.17. + */ +NwRcT s11_rat_type_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_rat_type_ie_set(NwGtpv2cMsgHandleT *msg, const rat_type_t *rat_type); + +/* EPS Bearer Id Information Element + * 3GPP TS 29.274 #8.8 + */ +NwRcT s11_ebi_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_ebi_ie_set(NwGtpv2cMsgHandleT *msg, const unsigned ebi); + +/* Bearer Contexts to Create Information Element as part of Create Session Request + * 3GPP TS 29.274 Table 7.2.1-2. + */ +NwRcT s11_bearer_context_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_bearer_context_to_create_ie_set( + NwGtpv2cMsgHandleT *msg, const bearer_to_create_t *bearer_to_create); + +NwRcT s11_bearer_context_to_modifiy_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* EPS Bearer Id Information Element + * 3GPP TS 29.274 #8.8 + * ebi is 4 bits long + */ +int s11_ebi_ie_set(NwGtpv2cMsgHandleT *msg, const unsigned ebi); + +/* Cause Information Element */ +NwRcT s11_cause_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_cause_ie_set(NwGtpv2cMsgHandleT *msg, + const gtp_cause_t *cause); + +/* Bearer Context Created grouped Information Element */ +NwRcT s11_bearer_context_created_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_bearer_context_created_ie_set( + NwGtpv2cMsgHandleT *msg, const bearer_context_created_t *bearer); + +/* Serving Network Information Element + * 3GPP TS 29.274 #8.18 + */ +NwRcT s11_serving_network_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_serving_network_ie_set( + NwGtpv2cMsgHandleT *msg, + const ServingNetwork_t *serving_network); + +NwRcT s11_fteid_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* PDN Address Allocation Information Element */ +NwRcT s11_paa_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_paa_ie_set(NwGtpv2cMsgHandleT *msg, const PAA_t *paa); + +/* Access Point Name Information Element + * 3GPP TS 29.274 #8.6 + * NOTE: The APN field is not encoded as a dotted string as commonly used in + * documentation. + * The encoding of the APN field follows 3GPP TS 23.003 subclause 9.1 + */ +NwRcT s11_apn_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_apn_ie_set(NwGtpv2cMsgHandleT *msg, const char *apn); + +NwRcT s11_ambr_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +NwRcT s11_mei_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +NwRcT s11_uli_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* APN restrtiction Information Element */ +int s11_apn_restriction_ie_set( + NwGtpv2cMsgHandleT *msg, const uint8_t apn_restriction); + +/* Bearer level Qos Information Element + * 3GPP TS 29.274 #8.15 + */ +int s11_bearer_qos_ie_set(NwGtpv2cMsgHandleT *msg, const BearerQOS_t *bearer_qos); + +/* IP address Information Element + * 3GPP TS 29.274 #8.9 + */ +NwRcT s11_ip_address_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_ip_address_ie_set(NwGtpv2cMsgHandleT *msg, + const gtp_ip_address_t *ip_address); + +/* Delay Value Information Element + * 3GPP TS 29.274 #8.27 + */ +NwRcT s11_delay_value_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_delay_value_ie_set(NwGtpv2cMsgHandleT *msg, + const DelayValue_t *delay_value); + +/* UE Time Zone Information Element + * 3GPP TS 29.274 #8.44 + */ +NwRcT s11_ue_time_zone_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_ue_time_zone_ie_set(NwGtpv2cMsgHandleT *msg, + const UETimeZone_t *ue_time_zone); + +/* Target Identification Information Element + * 3GPP TS 29.274 #8.51 + */ +NwRcT s11_target_identification_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* Bearer Flags Information Element + * 3GPP TS 29.274 #8.32 + */ +NwRcT s11_bearer_flags_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +int s11_bearer_flags_ie_set(NwGtpv2cMsgHandleT *msg, + const bearer_flags_t *bearer_flags); + +NwRcT s11_indication_flags_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +/* FQ-CSID Information Element + * 3GPP TS 29.274 #8.62 + */ + +NwRcT s11_fqcsid_ie_get( + NwU8T ieType, NwU8T ieLength, NwU8T ieInstance, NwU8T *ieValue, void *arg); + +#endif /* S11_IE_FORMATTER_H_ */ diff --git a/openair-cn/S11/s11_mme.h b/openair-cn/S11/s11_mme.h new file mode 100644 index 0000000000..b3d9f702eb --- /dev/null +++ b/openair-cn/S11/s11_mme.h @@ -0,0 +1,6 @@ +#ifndef S11_MME_H_ +#define S11_MME_H_ + +int s11_mme_init(const mme_config_t *mme_config); + +#endif /* S11_MME_H_ */ diff --git a/openair-cn/S11/s11_mme_peer_manager.c b/openair-cn/S11/s11_mme_peer_manager.c new file mode 100644 index 0000000000..8fb9787828 --- /dev/null +++ b/openair-cn/S11/s11_mme_peer_manager.c @@ -0,0 +1,4 @@ +#include <stdlib.h> +#include <stdio.h> + + diff --git a/openair-cn/S11/s11_mme_session_manager.c b/openair-cn/S11/s11_mme_session_manager.c new file mode 100644 index 0000000000..51255e3d69 --- /dev/null +++ b/openair-cn/S11/s11_mme_session_manager.c @@ -0,0 +1,177 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "assertions.h" +#include "intertask_interface.h" + +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" + +#include "s11_common.h" +#include "s11_mme_session_manager.h" +#include "s11_ie_formatter.h" + +int s11_mme_create_session_request(NwGtpv2cStackHandleT *stack_p, + SgwCreateSessionRequest *create_session_p) +{ + NwGtpv2cUlpApiT ulp_req; + + NwRcT rc; + uint8_t restart_counter = 0; + + DevAssert(stack_p != NULL); + DevAssert(create_session_p != NULL); + + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + + ulp_req.apiType = NW_GTPV2C_ULP_API_INITIAL_REQ; + + /* Prepare a new Create Session Request msg */ + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_CREATE_SESSION_REQ, + create_session_p->teid, + 0, + &(ulp_req.hMsg)); + + ulp_req.apiInfo.initialReqInfo.peerIp = create_session_p->peer_ip; + ulp_req.apiInfo.initialReqInfo.teidLocal = create_session_p->sender_fteid_for_cp.teid; + + /* Add recovery if contacting the peer for the first time */ + rc = nwGtpv2cMsgAddIe((ulp_req.hMsg), NW_GTPV2C_IE_RECOVERY, 1, 0, + (NwU8T*)&restart_counter); + DevAssert(NW_OK == rc); + + /* Putting the information Elements */ + s11_imsi_ie_set(&(ulp_req.hMsg), &create_session_p->imsi); + s11_rat_type_ie_set(&(ulp_req.hMsg), &create_session_p->rat_type); + s11_pdn_type_ie_set(&(ulp_req.hMsg), &create_session_p->pdn_type); + + /* Sender F-TEID for Control Plane (MME S11) */ + rc = nwGtpv2cMsgAddIeFteid((ulp_req.hMsg), NW_GTPV2C_IE_INSTANCE_ZERO, + S11_MME_GTP_C, + create_session_p->sender_fteid_for_cp.teid, + create_session_p->sender_fteid_for_cp.ipv4 ? + create_session_p->sender_fteid_for_cp.ipv4_address : 0, + create_session_p->sender_fteid_for_cp.ipv6 ? + create_session_p->sender_fteid_for_cp.ipv6_address : NULL); + /* The P-GW TEID should be present on the S11 interface. + * In case of an initial attach it should be set to 0... + */ + rc = nwGtpv2cMsgAddIeFteid((ulp_req.hMsg), NW_GTPV2C_IE_INSTANCE_ONE, + S5_S8_PGW_GTP_C, + create_session_p->pgw_address_for_cp.teid, + create_session_p->pgw_address_for_cp.ipv4 ? + create_session_p->pgw_address_for_cp.ipv4_address : 0, + create_session_p->pgw_address_for_cp.ipv6 ? + create_session_p->pgw_address_for_cp.ipv6_address : NULL); + + s11_apn_ie_set(&(ulp_req.hMsg), create_session_p->apn); + + s11_serving_network_ie_set(&(ulp_req.hMsg), &create_session_p->serving_network); + + s11_bearer_context_to_create_ie_set( + &(ulp_req.hMsg), &create_session_p->bearer_to_create); + + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + return 0; +} + +int s11_mme_handle_create_session_response(NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc = NW_OK; + NwU8T offendingIeType, offendingIeInstance; + NwU16T offendingIeLength; + + SgwCreateSessionResponse *create_session_resp_p; + MessageDef *message_p; + + NwGtpv2cMsgParserT *pMsgParser; + + DevAssert(stack_p != NULL); + + message_p = alloc_new_message(TASK_S11, SGW_CREATE_SESSION_RESPONSE); + + create_session_resp_p = &message_p->msg.sgwCreateSessionResponse; + + /* Create a new message parser */ + rc = nwGtpv2cMsgParserNew(*stack_p, NW_GTP_CREATE_SESSION_RSP, + s11_ie_indication_generic, + NULL, &pMsgParser); + DevAssert(NW_OK == rc); + + /* Cause IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_CAUSE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_cause_ie_get, + &create_session_resp_p->cause); + DevAssert(NW_OK == rc); + + /* Sender FTEID for CP IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_FTEID, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_fteid_ie_get, + &create_session_resp_p->s11_sgw_teid); + DevAssert(NW_OK == rc); + + /* Sender FTEID for PGW S5/S8 IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_FTEID, + NW_GTPV2C_IE_INSTANCE_ONE, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_fteid_ie_get, + &create_session_resp_p->s5_s8_pgw_teid); + DevAssert(NW_OK == rc); + + /* PAA IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_PAA, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_paa_ie_get, + &create_session_resp_p->paa); + DevAssert(NW_OK == rc); + + /* Bearer Contexts Created IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_BEARER_CONTEXT, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_bearer_context_created_ie_get, + &create_session_resp_p->bearer_context_created); + DevAssert(NW_OK == rc); + + /* Run the parser */ + rc = nwGtpv2cMsgParserRun(pMsgParser, + (pUlpApi->hMsg), + &offendingIeType, + &offendingIeInstance, + &offendingIeLength); + if (rc != NW_OK) + { + /* TODO: handle this case */ + free(message_p); + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return -1; + } + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); +} diff --git a/openair-cn/S11/s11_mme_session_manager.h b/openair-cn/S11/s11_mme_session_manager.h new file mode 100644 index 0000000000..c85b1fa714 --- /dev/null +++ b/openair-cn/S11/s11_mme_session_manager.h @@ -0,0 +1,44 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S11_MME_SESSION_MANAGER_H_ +#define S11_MME_SESSION_MANAGER_H_ + +/* @brief Create a new Create Session Request and send it to provided S-GW. + */ +int s11_mme_create_session_request(NwGtpv2cStackHandleT *stack_p, + SgwCreateSessionRequest *create_session_p); + +/* @brief Handle a Create Session Response received from S-GW. + */ +int s11_mme_handle_create_session_response(NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi); + +#endif /* S11_MME_SESSION_MANAGER_H_ */ diff --git a/openair-cn/S11/s11_mme_task.c b/openair-cn/S11/s11_mme_task.c new file mode 100644 index 0000000000..bb0fe20189 --- /dev/null +++ b/openair-cn/S11/s11_mme_task.c @@ -0,0 +1,304 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> + +#include "assertions.h" + +#include "mme_config.h" +#include "intertask_interface.h" + +#include "timer.h" + +#include "NwLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cMsg.h" + +#include "s11_mme.h" +#include "s11_mme_session_manager.h" + +#define S11_DEBUG(x, args...) fprintf(stdout, "[S11] [D]"x, ##args) +#define S11_INFO(x, args...) fprintf(stdout, "[S11] [I]"x, ##args) +#define S11_WARN(x, args...) fprintf(stdout, "[S11] [W]"x, ##args) +#define S11_ERROR(x, args...) fprintf(stderr, "[S11] [E]"x, ##args) + +static NwGtpv2cStackHandleT s11_mme_stack_handle; + +static +NwRcT s11_mme_log_wrapper(NwGtpv2cLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr) +{ + S11_DEBUG("%s\n", logStr); + return NW_OK; +} + +static +NwRcT s11_mme_ulp_process_stack_req_cb( + NwGtpv2cUlpHandleT hUlp, NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc = NW_OK; + int ret = 0; + + DevAssert(pUlpApi != NULL); + + switch(pUlpApi->apiType) + { + case NW_GTPV2C_ULP_API_TRIGGERED_RSP_IND: + S11_DEBUG("Received triggered response indication\n"); + switch (pUlpApi->apiInfo.triggeredRspIndInfo.msgType) + { + case NW_GTP_CREATE_SESSION_RSP: + ret = s11_mme_handle_create_session_response( + &s11_mme_stack_handle, pUlpApi); + break; + default: + S11_WARN("Received unhandled message type %d\n", + pUlpApi->apiInfo.triggeredRspIndInfo.msgType); + break; + } + break; + default: + break; + } + + return ret == 0 ? NW_OK : NW_FAILURE; +} + +static +NwRcT s11_mme_send_udp_msg( + NwGtpv2cUdpHandleT udpHandle, + NwU8T *buffer, + NwU32T buffer_len, + NwU32T peerIpAddr, + NwU32T peerPort) +{ + // Create and alloc new message + MessageDef *message_p; + udp_data_req_t *udp_data_req_p; + int ret = 0; + + message_p = alloc_new_message(TASK_S11, UDP_DATA_REQ); + + udp_data_req_p = &message_p->msg.udp_data_req; + + udp_data_req_p->peer_address = peerIpAddr; + udp_data_req_p->peer_port = peerPort; + udp_data_req_p->buffer = buffer; + udp_data_req_p->buffer_length = buffer_len; + + ret = send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); + + return ((ret == 0) ? NW_OK : NW_FAILURE); +} + +static +NwRcT s11_mme_start_timer_wrapper( + NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void *timeoutArg, + NwGtpv2cTimerHandleT *hTmr) +{ + long timer_id; + int ret = 0; + + if (tmrType == NW_GTPV2C_TMR_TYPE_REPETITIVE) { + ret = timer_setup(timeoutSec, + timeoutUsec, + TASK_S11, + INSTANCE_DEFAULT, + TIMER_PERIODIC, + timeoutArg, + &timer_id); + } else { + ret = timer_setup(timeoutSec, + timeoutUsec, + TASK_S11, + INSTANCE_DEFAULT, + TIMER_ONE_SHOT, + timeoutArg, + &timer_id); + } + + *hTmr = (NwGtpv2cTimerHandleT)timer_id; + + return ((ret == 0) ? NW_OK : NW_FAILURE); +} + +static +NwRcT s11_mme_stop_timer_wrapper( + NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT tmrHandle) +{ + long timer_id; + + timer_id = (long)tmrHandle; + + return ((timer_remove(timer_id) == 0) ? NW_OK : NW_FAILURE); +} + +static void *s11_mme_thread(void *args) +{ + intertask_interface_mark_task_ready(TASK_S11); + while(1) { + MessageDef *received_message_p = NULL; + receive_msg(TASK_S11, &received_message_p); + assert(received_message_p != NULL); + + switch(received_message_p->header.messageId) { + case SGW_CREATE_SESSION_REQUEST: { + s11_mme_create_session_request( + &s11_mme_stack_handle, + &received_message_p->msg.sgwCreateSessionRequest); + } break; + case UDP_DATA_IND: { + /* We received new data to handle from the UDP layer */ + NwRcT rc; + udp_data_ind_t *udp_data_ind; + + udp_data_ind = &received_message_p->msg.udp_data_ind; + + rc = nwGtpv2cProcessUdpReq(s11_mme_stack_handle, + udp_data_ind->buffer, + udp_data_ind->buffer_length, + udp_data_ind->peer_port, + udp_data_ind->peer_address); + + DevAssert(rc == NW_OK); + } break; + case TIMER_HAS_EXPIRED: { + S11_DEBUG("Processing timeout for timer_id 0x%lx and arg %p\n", + received_message_p->msg.timer_has_expired.timer_id, + received_message_p->msg.timer_has_expired.arg); + DevAssert(nwGtpv2cProcessTimeout( + received_message_p->msg.timer_has_expired.arg) == NW_OK); + } break; + default: { + S11_ERROR("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } + break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +static int s11_send_init_udp(char *address, uint16_t port_number) +{ + MessageDef *message_p; + + message_p = alloc_new_message(TASK_S11, UDP_INIT); + if (message_p == NULL) { + return -1; + } + + message_p->msg.udp_init.port = port_number; + //LG message_p->msg.udpInit.address = "0.0.0.0"; //ANY address + message_p->msg.udp_init.address = address; + + S11_DEBUG("Tx UDP_INIT IP addr %s\n", message_p->msg.udp_init.address); + + return send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); +} + +int s11_mme_init(const mme_config_t *mme_config_p) +{ + int ret = 0; + NwGtpv2cUlpEntityT ulp; + NwGtpv2cUdpEntityT udp; + NwGtpv2cTimerMgrEntityT tmrMgr; + NwGtpv2cLogMgrEntityT logMgr; + + struct in_addr addr; + char *s11_address_str = NULL; + + S11_DEBUG("Initializing S11 interface\n"); + + if (nwGtpv2cInitialize(&s11_mme_stack_handle) != NW_OK) { + S11_ERROR("Failed to initialize gtpv2-c stack\n"); + goto fail; + } + + /* Set ULP entity */ + ulp.hUlp = (NwGtpv2cUlpHandleT)NULL; + ulp.ulpReqCallback = s11_mme_ulp_process_stack_req_cb; + DevAssert(NW_OK == nwGtpv2cSetUlpEntity(s11_mme_stack_handle, &ulp)); + + /* Set UDP entity */ + udp.hUdp = (NwGtpv2cUdpHandleT)NULL; + udp.udpDataReqCallback = s11_mme_send_udp_msg; + DevAssert(NW_OK == nwGtpv2cSetUdpEntity(s11_mme_stack_handle, &udp)); + + /* Set Timer entity */ + tmrMgr.tmrMgrHandle = (NwGtpv2cTimerMgrHandleT)NULL; + tmrMgr.tmrStartCallback = s11_mme_start_timer_wrapper; + tmrMgr.tmrStopCallback = s11_mme_stop_timer_wrapper; + DevAssert(NW_OK == nwGtpv2cSetTimerMgrEntity(s11_mme_stack_handle, &tmrMgr)); + + logMgr.logMgrHandle = 0; + logMgr.logReqCallback = s11_mme_log_wrapper; + DevAssert(NW_OK == nwGtpv2cSetLogMgrEntity(s11_mme_stack_handle, &logMgr)); + + if (intertask_interface_create_task(TASK_S11, &s11_mme_thread, NULL) < 0) { + S11_ERROR("gtpv1u phtread_create: %s\n", strerror(errno)); + goto fail; + } + + DevAssert(NW_OK == nwGtpv2cSetLogLevel(s11_mme_stack_handle, + NW_LOG_LEVEL_DEBG)); + + config_read_lock(&mme_config); + addr.s_addr = mme_config.ipv4.mme_ip_address_for_S11; + config_unlock(&mme_config); + + s11_address_str = inet_ntoa(addr); + + DevAssert(s11_address_str != NULL); + + s11_send_init_udp(s11_address_str, 2123); + + S11_DEBUG("Initializing S11 interface: DONE\n"); + + return ret; + +fail: + S11_DEBUG("Initializing S11 interface: FAILURE\n"); + return -1; +} diff --git a/openair-cn/S11/s11_sgw.c b/openair-cn/S11/s11_sgw.c new file mode 100644 index 0000000000..c5c56bfb84 --- /dev/null +++ b/openair-cn/S11/s11_sgw.c @@ -0,0 +1,330 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> + +#include "assertions.h" +#include "queue.h" + +#include "mme_config.h" +#include "intertask_interface.h" + +#include "timer.h" + +#include "NwLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" + +#include "sgw_lite_ie_defs.h" + +#include "s11_common.h" +#include "s11_sgw.h" +#include "s11_sgw_bearer_manager.h" +#include "s11_sgw_session_manager.h" + +static NwGtpv2cStackHandleT s11_sgw_stack_handle; + +/* ULP callback for the GTPv2-C stack */ +static +NwRcT s11_sgw_ulp_process_stack_req_cb( + NwGtpv2cUlpHandleT hUlp, NwGtpv2cUlpApiT *pUlpApi) +{ + int ret = 0; + + DevAssert(pUlpApi != NULL); + + switch (pUlpApi->apiType) + { + case NW_GTPV2C_ULP_API_INITIAL_REQ_IND: + S11_DEBUG("Received initial req indication\n"); + switch (pUlpApi->apiInfo.initialReqIndInfo.msgType) + { + case NW_GTP_CREATE_SESSION_REQ: + ret = s11_sgw_handle_create_session_request( + &s11_sgw_stack_handle, pUlpApi); + break; + case NW_GTP_MODIFY_BEARER_REQ: + ret = s11_sgw_handle_modify_bearer_request( + &s11_sgw_stack_handle, pUlpApi); + break; + case NW_GTP_DELETE_SESSION_REQ: + ret = s11_sgw_handle_delete_session_request( + &s11_sgw_stack_handle, pUlpApi); + break; + default: + S11_WARN("Received unhandled message type %d\n", + pUlpApi->apiInfo.initialReqIndInfo.msgType); + break; + } + break; + default: + S11_ERROR("Received unknown stack req message %d\n", + pUlpApi->apiType); + break; + } + + return ret == -1 ? NW_FAILURE : NW_OK; +} + +static +NwRcT s11_sgw_send_udp_msg( + NwGtpv2cUdpHandleT udpHandle, + NwU8T *buffer, + NwU32T buffer_len, + NwU32T peerIpAddr, + NwU32T peerPort) +{ + // Create and alloc new message + MessageDef *message_p; + udp_data_req_t *udp_data_req_p; + int ret = 0; + + message_p = alloc_new_message(TASK_S11, UDP_DATA_REQ); + + udp_data_req_p = &message_p->msg.udp_data_req; + + udp_data_req_p->peer_address = peerIpAddr; + udp_data_req_p->peer_port = peerPort; + udp_data_req_p->buffer = buffer; + udp_data_req_p->buffer_length = buffer_len; + + ret = send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); + + return ret == 0 ? NW_OK : NW_FAILURE; +} + +static +NwRcT s11_sgw_log_wrapper(NwGtpv2cLogMgrHandleT hLogMgr, + NwU32T logLevel, + NwCharT* file, + NwU32T line, + NwCharT* logStr) +{ + S11_DEBUG("%s\n", logStr); + return NW_OK; +} + +static +NwRcT s11_sgw_start_timer_wrapper( + NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwU32T timeoutSec, + NwU32T timeoutUsec, + NwU32T tmrType, + void *timeoutArg, + NwGtpv2cTimerHandleT *hTmr) +{ + long timer_id; + int ret = 0; + + if (tmrType == NW_GTPV2C_TMR_TYPE_REPETITIVE) { + ret = timer_setup(timeoutSec, + timeoutUsec, + TASK_S11, + INSTANCE_DEFAULT, + TIMER_PERIODIC, + timeoutArg, + &timer_id); + } else { + ret = timer_setup(timeoutSec, + timeoutUsec, + TASK_S11, + INSTANCE_DEFAULT, + TIMER_ONE_SHOT, + timeoutArg, + &timer_id); + } + + return ret == 0 ? NW_OK : NW_FAILURE; +} + +static +NwRcT s11_sgw_stop_timer_wrapper( + NwGtpv2cTimerMgrHandleT tmrMgrHandle, + NwGtpv2cTimerHandleT tmrHandle) +{ + int ret; + long timer_id; + + timer_id = (long)tmrHandle; + + ret = timer_remove(timer_id); //TODO + + return ret == 0 ? NW_OK : NW_FAILURE; +} + +static void *s11_sgw_thread(void *args) +{ + intertask_interface_mark_task_ready(TASK_S11); + while(1) { + MessageDef *received_message_p = NULL; + receive_msg(TASK_S11, &received_message_p); + assert(received_message_p != NULL); + + switch(received_message_p->header.messageId) { + case UDP_DATA_IND: { + /* We received new data to handle from the UDP layer */ + NwRcT rc; + udp_data_ind_t *udp_data_ind; + + udp_data_ind = &received_message_p->msg.udp_data_ind; + + S11_DEBUG("Processing new data indication from UDP\n"); + + rc = nwGtpv2cProcessUdpReq(s11_sgw_stack_handle, + udp_data_ind->buffer, + udp_data_ind->buffer_length, + udp_data_ind->peer_port, + udp_data_ind->peer_address); + + DevAssert(rc == NW_OK); + } break; + case SGW_CREATE_SESSION_RESPONSE: { + S11_DEBUG("Received create session response from S-PGW APP\n"); + s11_sgw_handle_create_session_response( + &s11_sgw_stack_handle, + &received_message_p->msg.sgwCreateSessionResponse); + } break; + case SGW_MODIFY_BEARER_RESPONSE: { + S11_DEBUG("Received modify bearer response from S-PGW APP\n"); + s11_sgw_handle_modify_bearer_response( + &s11_sgw_stack_handle, + &received_message_p->msg.sgwModifyBearerResponse); + } break; + case SGW_DELETE_SESSION_RESPONSE: { + S11_DEBUG("Received delete session response from S-PGW APP\n"); + s11_sgw_handle_delete_session_response( + &s11_sgw_stack_handle, + &received_message_p->msg.sgwDeleteSessionResponse); + } break; + case TIMER_HAS_EXPIRED: { + S11_DEBUG("Processing timeout for timer_id 0x%lx and arg %p\n", + received_message_p->msg.timer_has_expired.timer_id, + received_message_p->msg.timer_has_expired.arg); + DevAssert(nwGtpv2cProcessTimeout(received_message_p->msg.timer_has_expired.arg) == NW_OK); + } break; + default: { + S11_ERROR("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } + break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +static int s11_send_init_udp(char *address, uint16_t port_number) +{ + MessageDef *message_p; + + message_p = alloc_new_message(TASK_S11, UDP_INIT); + if (message_p == NULL) { + return -1; + } + + message_p->msg.udp_init.port = port_number; + //LG message_p->msg.udpInit.address = "0.0.0.0"; //ANY address + message_p->msg.udp_init.address = address; + + S11_DEBUG("Tx UDP_INIT IP addr %s\n", message_p->msg.udp_init.address); + + return send_msg_to_task(TASK_UDP, INSTANCE_DEFAULT, message_p); +} + +int s11_sgw_init(const mme_config_t *mme_config_p) +{ + int ret = 0; + NwGtpv2cUlpEntityT ulp; + NwGtpv2cUdpEntityT udp; + NwGtpv2cTimerMgrEntityT tmrMgr; + NwGtpv2cLogMgrEntityT logMgr; + struct in_addr addr; + char *s11_address_str = NULL; + + S11_DEBUG("Initializing S11 interface\n"); + + if (nwGtpv2cInitialize(&s11_sgw_stack_handle) != NW_OK) { + S11_ERROR("Failed to initialize gtpv2-c stack\n"); + goto fail; + } + + /* Set ULP entity */ + ulp.hUlp = (NwGtpv2cUlpHandleT)NULL; + ulp.ulpReqCallback = s11_sgw_ulp_process_stack_req_cb; + DevAssert(NW_OK == nwGtpv2cSetUlpEntity(s11_sgw_stack_handle, &ulp)); + + /* Set UDP entity */ + udp.hUdp = (NwGtpv2cUdpHandleT)NULL; + udp.udpDataReqCallback = s11_sgw_send_udp_msg; + DevAssert(NW_OK == nwGtpv2cSetUdpEntity(s11_sgw_stack_handle, &udp)); + + /* Set Timer entity */ + tmrMgr.tmrMgrHandle = (NwGtpv2cTimerMgrHandleT)NULL; + tmrMgr.tmrStartCallback = s11_sgw_start_timer_wrapper; + tmrMgr.tmrStopCallback = s11_sgw_stop_timer_wrapper; + DevAssert(NW_OK == nwGtpv2cSetTimerMgrEntity(s11_sgw_stack_handle, &tmrMgr)); + + logMgr.logMgrHandle = 0; + logMgr.logReqCallback = s11_sgw_log_wrapper; + + DevAssert(NW_OK == nwGtpv2cSetLogMgrEntity(s11_sgw_stack_handle, &logMgr)); + + if (intertask_interface_create_task(TASK_S11, &s11_sgw_thread, NULL) < 0) { + S11_ERROR("gtpv1u phtread_create: %s\n", strerror(errno)); + goto fail; + } + + DevAssert(NW_OK == nwGtpv2cSetLogLevel(s11_sgw_stack_handle, + NW_LOG_LEVEL_DEBG)); + + config_read_lock(&mme_config); + addr.s_addr = mme_config.ipv4.sgw_ip_address_for_S11; + config_unlock(&mme_config); + + s11_address_str = inet_ntoa(addr); + + DevAssert(s11_address_str != NULL); + + s11_send_init_udp(s11_address_str, 2123); + + S11_DEBUG("Initializing S11 interface: DONE\n"); + + return ret; + +fail: + S11_DEBUG("Initializing S11 interface: FAILURE\n"); + return -1; +} diff --git a/openair-cn/S11/s11_sgw.h b/openair-cn/S11/s11_sgw.h new file mode 100644 index 0000000000..8e9d2ddbc0 --- /dev/null +++ b/openair-cn/S11/s11_sgw.h @@ -0,0 +1,6 @@ +#ifndef S11_SGW_H_ +#define S11_SGW_H_ + +int s11_sgw_init(const mme_config_t *mme_config); + +#endif /* S11_SGW_H_ */ diff --git a/openair-cn/S11/s11_sgw_bearer_manager.c b/openair-cn/S11/s11_sgw_bearer_manager.c new file mode 100644 index 0000000000..95185c9e9b --- /dev/null +++ b/openair-cn/S11/s11_sgw_bearer_manager.c @@ -0,0 +1,208 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "assertions.h" +#include "intertask_interface.h" +#include "queue.h" + +#include "NwLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" + +#include "sgw_lite_ie_defs.h" + +#include "s11_common.h" +#include "s11_sgw_bearer_manager.h" +#include "s11_ie_formatter.h" + +int s11_sgw_handle_modify_bearer_request(NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc = NW_OK; + NwU8T offendingIeType, offendingIeInstance; + NwU16T offendingIeLength; + + SgwModifyBearerRequest *modify_bearer_request_p; + MessageDef *message_p; + + NwGtpv2cMsgParserT *pMsgParser; + + DevAssert(stack_p != NULL); + + message_p = alloc_new_message(TASK_S11, SGW_MODIFY_BEARER_REQUEST); + + modify_bearer_request_p = &message_p->msg.sgwModifyBearerRequest; + + modify_bearer_request_p->trxn = (void *)pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + modify_bearer_request_p->teid = nwGtpv2cMsgGetTeid(pUlpApi->hMsg); + + /* Create a new message parser */ + rc = nwGtpv2cMsgParserNew(*stack_p, + NW_GTP_MODIFY_BEARER_REQ, + s11_ie_indication_generic, + NULL, + &pMsgParser); + DevAssert(NW_OK == rc); + + /* Indication Flags IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_INDICATION, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_indication_flags_ie_get, + &modify_bearer_request_p->indication_flags); + DevAssert(NW_OK == rc); + + /* MME-FQ-CSID IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_FQ_CSID, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_fqcsid_ie_get, + &modify_bearer_request_p->mme_fq_csid); + DevAssert(NW_OK == rc); + + /* RAT Type IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_RAT_TYPE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_rat_type_ie_get, + &modify_bearer_request_p->rat_type); + DevAssert(NW_OK == rc); + + /* Delay Value IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_DELAY_VALUE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_delay_value_ie_get, + &modify_bearer_request_p->delay_dl_packet_notif_req); + DevAssert(NW_OK == rc); + + /* Bearer Context to be modified IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, + NW_GTPV2C_IE_BEARER_CONTEXT, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_bearer_context_to_modifiy_ie_get, + &modify_bearer_request_p->bearer_context_to_modify); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgParserRun(pMsgParser, + pUlpApi->hMsg, + &offendingIeType, + &offendingIeInstance, + &offendingIeLength); + if (rc != NW_OK) + { + gtp_cause_t cause; + NwGtpv2cUlpApiT ulp_req; + + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause , 0, sizeof(gtp_cause_t)); + + cause.offending_ie_type = offendingIeType; + cause.offending_ie_length = offendingIeLength; + cause.offending_ie_instance = offendingIeInstance; + + switch (rc) + { + case NW_GTPV2C_MANDATORY_IE_MISSING: + S11_DEBUG("Mandatory IE type '%u' of instance '%u' missing!\n", + offendingIeType, offendingIeLength); + cause.cause_value = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + break; + default: + S11_DEBUG("Unknown message parse error!\n"); + cause.cause_value = 0; + break; + } + + /* + * Send Create session response with failure to Gtpv2c Stack Instance + */ + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_CREATE_SESSION_RSP, + 0, + nwGtpv2cMsgGetSeqNumber(pUlpApi->hMsg), + &(ulp_req.hMsg)); + + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + S11_DEBUG("Received NW_GTP_CREATE_SESSION_REQ, Sending NW_GTP_CREATE_SESSION_RSP!\n"); + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + free(message_p); + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return 0; + } + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +int s11_sgw_handle_modify_bearer_response( + NwGtpv2cStackHandleT *stack_p, + SgwModifyBearerResponse *modify_bearer_response_p) +{ + gtp_cause_t cause; + NwRcT rc; + NwGtpv2cUlpApiT ulp_req; + NwGtpv2cTrxnHandleT trxn; + + DevAssert(stack_p != NULL); + DevAssert(modify_bearer_response_p != NULL); + + trxn = (NwGtpv2cTrxnHandleT)modify_bearer_response_p->trxn; + + /* Prepare a modify bearer response to send to MME. + */ + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause , 0, sizeof(gtp_cause_t)); + + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = trxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_MODIFY_BEARER_RSP, + 0, + 0, + &(ulp_req.hMsg)); + DevAssert(NW_OK == rc); + + /* Set the remote TEID */ + rc = nwGtpv2cMsgSetTeid(ulp_req.hMsg, modify_bearer_response_p->teid); + DevAssert(NW_OK == rc); + + cause.cause_value = (uint8_t)modify_bearer_response_p->cause; + + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + return 0; +} diff --git a/openair-cn/S11/s11_sgw_bearer_manager.h b/openair-cn/S11/s11_sgw_bearer_manager.h new file mode 100644 index 0000000000..47bb6d729a --- /dev/null +++ b/openair-cn/S11/s11_sgw_bearer_manager.h @@ -0,0 +1,13 @@ + +#ifndef S11_SGW_BEARER_MANAGER_H_ +#define S11_SGW_BEARER_MANAGER_H_ + +int s11_sgw_handle_modify_bearer_request( + NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi); + +int s11_sgw_handle_modify_bearer_response( + NwGtpv2cStackHandleT *stack_p, + SgwModifyBearerResponse *modify_bearer_response_p); + +#endif /* S11_SGW_BEARER_MANAGER_H_ */ diff --git a/openair-cn/S11/s11_sgw_session_manager.c b/openair-cn/S11/s11_sgw_session_manager.c new file mode 100644 index 0000000000..4368720d54 --- /dev/null +++ b/openair-cn/S11/s11_sgw_session_manager.c @@ -0,0 +1,495 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "assertions.h" +#include "intertask_interface.h" +#include "queue.h" + +#include "NwLog.h" +#include "NwGtpv2c.h" +#include "NwGtpv2cIe.h" +#include "NwGtpv2cMsg.h" +#include "NwGtpv2cMsgParser.h" + +#include "sgw_lite_ie_defs.h" + +#include "s11_common.h" +#include "s11_sgw_session_manager.h" +#include "s11_ie_formatter.h" + +int s11_sgw_handle_create_session_request(NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc = NW_OK; + NwU8T offendingIeType, offendingIeInstance; + NwU16T offendingIeLength; + + SgwCreateSessionRequest *create_session_request_p; + MessageDef *message_p; + + NwGtpv2cMsgParserT *pMsgParser; + + DevAssert(stack_p != NULL); + + message_p = alloc_new_message(TASK_S11, SGW_CREATE_SESSION_REQUEST); + + create_session_request_p = &message_p->msg.sgwCreateSessionRequest; + + /* Create a new message parser */ + rc = nwGtpv2cMsgParserNew(*stack_p, NW_GTP_CREATE_SESSION_REQ, + s11_ie_indication_generic, + NULL, &pMsgParser); + DevAssert(NW_OK == rc); + + /* Imsi IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_IMSI, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_imsi_ie_get, + &create_session_request_p->imsi); + DevAssert(NW_OK == rc); + + /* MSISDN IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_MSISDN, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_msisdn_ie_get, + &create_session_request_p->msisdn); + DevAssert(NW_OK == rc); + + /* MEI IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_MEI, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_mei_ie_get, + &create_session_request_p->mei); + DevAssert(NW_OK == rc); + + /* ULI IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_ULI, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_uli_ie_get, + &create_session_request_p->uli); + DevAssert(NW_OK == rc); + + /* Serving Network IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_SERVING_NETWORK, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_serving_network_ie_get, + &create_session_request_p->serving_network); + DevAssert(NW_OK == rc); + + /* RAT Type IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_RAT_TYPE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_rat_type_ie_get, + &create_session_request_p->rat_type); + DevAssert(NW_OK == rc); + + /* Indication Flags IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_INDICATION, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_indication_flags_ie_get, + &create_session_request_p->indication_flags); + DevAssert(NW_OK == rc); + + /* APN IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_APN, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_apn_ie_get, &create_session_request_p->apn); + DevAssert(NW_OK == rc); + + /* Selection Mode IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_SELECTION_MODE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_ie_indication_generic, NULL); + DevAssert(NW_OK == rc); + + /* PDN Type IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_PDN_TYPE, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_pdn_type_ie_get, &create_session_request_p->pdn_type); + DevAssert(NW_OK == rc); + + /* PAA IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_PAA, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_paa_ie_get, &create_session_request_p->paa); + DevAssert(NW_OK == rc); + + /* Sender FTEID for CP IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_FTEID, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_fteid_ie_get, + &create_session_request_p->sender_fteid_for_cp); + DevAssert(NW_OK == rc); + + /* PGW FTEID for CP IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_FTEID, + NW_GTPV2C_IE_INSTANCE_ONE, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_fteid_ie_get, + &create_session_request_p->pgw_address_for_cp); + DevAssert(NW_OK == rc); + + /* APN Restriction IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_APN_RESTRICTION, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_ie_indication_generic, NULL); + DevAssert(NW_OK == rc); + + /* Bearer Context IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_BEARER_CONTEXT, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_bearer_context_ie_get, + &create_session_request_p->bearer_to_create); + DevAssert(NW_OK == rc); + + /* AMBR IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_AMBR, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_ambr_ie_get, + &create_session_request_p->ambr); + DevAssert(NW_OK == rc); + + /* Recovery IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_RECOVERY, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_MANDATORY, + s11_ie_indication_generic, NULL); + DevAssert(NW_OK == rc); + + create_session_request_p->teid = nwGtpv2cMsgGetTeid(pUlpApi->hMsg); + create_session_request_p->trxn = (void*)pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + create_session_request_p->peer_ip = pUlpApi->apiInfo.initialReqIndInfo.peerIp; + + rc = nwGtpv2cMsgParserRun(pMsgParser, + pUlpApi->hMsg, + &offendingIeType, + &offendingIeInstance, + &offendingIeLength); + if (rc != NW_OK) + { + gtp_cause_t cause; + + NwGtpv2cUlpApiT ulp_req; + + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause , 0, sizeof(gtp_cause_t)); + + cause.offending_ie_type = offendingIeType; + cause.offending_ie_length = offendingIeLength; + cause.offending_ie_instance = offendingIeInstance; + + switch (rc) + { + case NW_GTPV2C_MANDATORY_IE_MISSING: + S11_DEBUG("Mandatory IE type '%u' of instance '%u' missing!\n", + offendingIeType, offendingIeLength); + cause.cause_value = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + break; + default: + S11_DEBUG("Unknown message parse error!\n"); + cause.cause_value = 0; + break; + } + + /* + * Send Create session response with failure to Gtpv2c Stack Instance + */ + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_CREATE_SESSION_RSP, + 0, + nwGtpv2cMsgGetSeqNumber(pUlpApi->hMsg), + &(ulp_req.hMsg)); + + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + S11_DEBUG("Received NW_GTP_CREATE_SESSION_REQ, Sending NW_GTP_CREATE_SESSION_RSP!\n"); + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + free(message_p); + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return 0; + } + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +int s11_sgw_handle_create_session_response( + NwGtpv2cStackHandleT *stack_p, + SgwCreateSessionResponse *create_session_response_p) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulp_req; + NwGtpv2cTrxnHandleT trxn; + + gtp_cause_t cause; + + DevAssert(create_session_response_p != NULL); + DevAssert(stack_p != NULL); + + trxn = (NwGtpv2cTrxnHandleT)create_session_response_p->trxn; + + DevAssert(trxn != 0); + + /* Create a tunnel for the GTPv2-C stack */ + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + + ulp_req.apiType = NW_GTPV2C_ULP_CREATE_LOCAL_TUNNEL; + ulp_req.apiInfo.createLocalTunnelInfo.teidLocal = create_session_response_p->s11_sgw_teid.teid; + ulp_req.apiInfo.createLocalTunnelInfo.peerIp = create_session_response_p->peer_ip; + + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + /* Prepare a create session response to send to MME. + */ + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause , 0, sizeof(gtp_cause_t)); + + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = trxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_CREATE_SESSION_RSP, + 0, + 0, + &(ulp_req.hMsg)); + DevAssert(NW_OK == rc); + + /* Set the remote TEID */ + rc = nwGtpv2cMsgSetTeid(ulp_req.hMsg, create_session_response_p->teid); + DevAssert(NW_OK == rc); + + cause.cause_value = (uint8_t)create_session_response_p->cause; + + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + rc = nwGtpv2cMsgAddIeFteid((ulp_req.hMsg), + NW_GTPV2C_IE_INSTANCE_ZERO, + S1_U_SGW_GTP_U, + create_session_response_p->s11_sgw_teid.teid, + 0xC0A80EA2, + NULL); + + s11_paa_ie_set(&(ulp_req.hMsg), &create_session_response_p->paa); + /* Put 0 for now i.e. no existing context or restriction */ + s11_apn_restriction_ie_set(&(ulp_req.hMsg), 0); + s11_bearer_context_created_ie_set( + &(ulp_req.hMsg), + &create_session_response_p->bearer_context_created); + + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + return 0; +} + +int s11_sgw_handle_delete_session_request(NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi) +{ + NwRcT rc = NW_OK; + NwU8T offendingIeType, offendingIeInstance; + NwU16T offendingIeLength; + + SgwDeleteSessionRequest *delete_session_request_p; + MessageDef *message_p; + + NwGtpv2cMsgParserT *pMsgParser; + + DevAssert(stack_p != NULL); + + message_p = alloc_new_message(TASK_S11, SGW_DELETE_SESSION_REQUEST); + + delete_session_request_p = &message_p->msg.sgwDeleteSessionRequest; + + /* Create a new message parser */ + rc = nwGtpv2cMsgParserNew(*stack_p, NW_GTP_DELETE_SESSION_REQ, + s11_ie_indication_generic, + NULL, &pMsgParser); + DevAssert(NW_OK == rc); + + /* MME FTEID for CP IE */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_FTEID, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_OPTIONAL, + s11_fteid_ie_get, + &delete_session_request_p->sender_fteid_for_cp); + DevAssert(NW_OK == rc); + + /* Linked EPS Bearer Id IE + * This information element shall not be present for TAU/RAU/Handover with + * S-GW relocation procedures. + */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_EBI, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_OPTIONAL, + s11_ebi_ie_get, + &delete_session_request_p->lbi); + DevAssert(NW_OK == rc); + + /* Indication Flags IE + * For a Delete Session Request on S11 interface, + * only the Operation Indication flag might be present. + */ + rc = nwGtpv2cMsgParserAddIe(pMsgParser, NW_GTPV2C_IE_INDICATION, + NW_GTPV2C_IE_INSTANCE_ZERO, + NW_GTPV2C_IE_PRESENCE_CONDITIONAL, + s11_indication_flags_ie_get, + &delete_session_request_p->indication_flags); + DevAssert(NW_OK == rc); + + delete_session_request_p->teid = nwGtpv2cMsgGetTeid(pUlpApi->hMsg); + delete_session_request_p->trxn = (void*)pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + delete_session_request_p->peer_ip = pUlpApi->apiInfo.initialReqIndInfo.peerIp; + + rc = nwGtpv2cMsgParserRun(pMsgParser, + pUlpApi->hMsg, + &offendingIeType, + &offendingIeInstance, + &offendingIeLength); + if (rc != NW_OK) { + NwGtpv2cUlpApiT ulp_req; + gtp_cause_t cause; + + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause , 0, sizeof(gtp_cause_t)); + + cause.offending_ie_type = offendingIeType; + cause.offending_ie_length = offendingIeLength; + cause.offending_ie_instance = offendingIeInstance; + + switch (rc) + { + case NW_GTPV2C_MANDATORY_IE_MISSING: + S11_DEBUG("Mandatory IE type '%u' of instance '%u' missing!\n", + offendingIeType, offendingIeLength); + cause.cause_value = NW_GTPV2C_CAUSE_MANDATORY_IE_MISSING; + break; + default: + S11_DEBUG("Unknown message parse error!\n"); + cause.cause_value = 0; + break; + } + + /* + * Send Create session response with failure to Gtpv2c Stack Instance + */ + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = pUlpApi->apiInfo.initialReqIndInfo.hTrxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_DELETE_SESSION_RSP, + 0, + nwGtpv2cMsgGetSeqNumber(pUlpApi->hMsg), + &(ulp_req.hMsg)); + + /* Adding the cause */ + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + S11_DEBUG("Received NW_GTP_DELETE_SESSION_REQ, Sending NW_GTP_DELETE_SESSION_RSP!\n"); + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + free(message_p); + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return 0; + } + + rc = nwGtpv2cMsgParserDelete(*stack_p, pMsgParser); + DevAssert(NW_OK == rc); + + rc = nwGtpv2cMsgDelete(*stack_p, (pUlpApi->hMsg)); + DevAssert(NW_OK == rc); + + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +int s11_sgw_handle_delete_session_response( + NwGtpv2cStackHandleT *stack_p, + SgwDeleteSessionResponse *delete_session_response_p) +{ + NwRcT rc; + NwGtpv2cUlpApiT ulp_req; + NwGtpv2cTrxnHandleT trxn; + gtp_cause_t cause; + + DevAssert(delete_session_response_p != NULL); + DevAssert(stack_p != NULL); + + trxn = (NwGtpv2cTrxnHandleT)delete_session_response_p->trxn; + + DevAssert(trxn != 0); + + /* Prepare a create session response to send to MME. + */ + memset(&ulp_req, 0, sizeof(NwGtpv2cUlpApiT)); + memset(&cause, 0, sizeof(gtp_cause_t)); + + ulp_req.apiType = NW_GTPV2C_ULP_API_TRIGGERED_RSP; + + ulp_req.apiInfo.triggeredRspInfo.hTrxn = trxn; + + rc = nwGtpv2cMsgNew(*stack_p, + NW_TRUE, + NW_GTP_DELETE_SESSION_RSP, + 0, + 0, + &(ulp_req.hMsg)); + DevAssert(NW_OK == rc); + + /* Set the remote TEID */ + rc = nwGtpv2cMsgSetTeid(ulp_req.hMsg, delete_session_response_p->teid); + DevAssert(NW_OK == rc); + + cause.cause_value = delete_session_response_p->cause; + + s11_cause_ie_set(&(ulp_req.hMsg), &cause); + + rc = nwGtpv2cProcessUlpReq(*stack_p, &ulp_req); + DevAssert(NW_OK == rc); + + return 0; +} diff --git a/openair-cn/S11/s11_sgw_session_manager.h b/openair-cn/S11/s11_sgw_session_manager.h new file mode 100644 index 0000000000..871b42c47e --- /dev/null +++ b/openair-cn/S11/s11_sgw_session_manager.h @@ -0,0 +1,20 @@ +#ifndef S11_SGW_SESSION_MANAGER_H_ +#define S11_SGW_SESSION_MANAGER_H_ + +int s11_sgw_handle_create_session_request( + NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi); + +int s11_sgw_handle_create_session_response( + NwGtpv2cStackHandleT *stack_p, + SgwCreateSessionResponse *create_session_response_p); + +int s11_sgw_handle_delete_session_request( + NwGtpv2cStackHandleT *stack_p, + NwGtpv2cUlpApiT *pUlpApi); + +int s11_sgw_handle_delete_session_response( + NwGtpv2cStackHandleT *stack_p, + SgwDeleteSessionResponse *delete_session_response_p); + +#endif /* S11_SGW_SESSION_MANAGER_H_ */ diff --git a/openair-cn/S1AP/MESSAGES/ASN1/Makefile.am b/openair-cn/S1AP/MESSAGES/ASN1/Makefile.am new file mode 100644 index 0000000000..818775406c --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/Makefile.am @@ -0,0 +1,8 @@ +BUILT_SOURCES=ieregen.stamp + +ieregen.stamp: $(top_srcdir)/S1AP/MESSAGES/ASN1/$(ASN1DIR)/S1AP-PDU-Contents.asn $(top_srcdir)/S1AP/MESSAGES/ASN1/asn1tostruct.py $(top_srcdir)/configure + echo Timestamp > $@ + python $(top_srcdir)/S1AP/MESSAGES/ASN1/asn1tostruct.py -f$(top_srcdir)/S1AP/MESSAGES/ASN1/$(ASN1DIR)/S1AP-PDU-Contents.asn -o$(top_builddir)/S1AP + +clean-local: + rm -f ieregen.stamp \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-CommonDataTypes.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-CommonDataTypes.asn new file mode 100644 index 0000000000..7871eecf97 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-CommonDataTypes.asn @@ -0,0 +1,232 @@ +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** + +S1AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-CommonDataTypes (3) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optional, conditional, mandatory } + +PrivateIE-ID ::= CHOICE { + local INTEGER (0..65535), + global OBJECT IDENTIFIER +} + +ProcedureCode ::= INTEGER { + id-HandoverPreparation(0), + id-HandoverResourceAllocation(1), + id-HandoverNotification(2), + id-PathSwitchRequest(3), + id-HandoverCancel(4), + id-E-RABSetup(5), + id-E-RABModify(6), + id-E-RABRelease(7), + id-E-RABReleaseIndication(8), + id-InitialContextSetup(9), + id-Paging(10), + id-downlinkNASTransport(11), + id-initialUEMessage(12), + id-uplinkNASTransport(13), + id-Reset(14), + id-ErrorIndication(15), + id-NASNonDeliveryIndication(16), + id-S1Setup(17), + id-UEContextReleaseRequest(18), + id-DownlinkS1cdma2000tunneling(19), + id-UplinkS1cdma2000tunneling(20), + id-UEContextModification(21), + id-UECapabilityInfoIndication(22), + id-UEContextRelease(23), + id-eNBStatusTransfer(24), + id-MMEStatusTransfer(25), + id-DeactivateTrace(26), + id-TraceStart(27), + id-TraceFailureIndication(28), + id-ENBConfigurationUpdate(29), + id-MMEConfigurationUpdate(30), + id-LocationReportingControl(31), + id-LocationReportingFailureIndication(32), + id-LocationReport(33), + id-OverloadStart(34), + id-OverloadStop(35), + id-WriteReplaceWarning(36), + id-eNBDirectInformationTransfer(37), + id-MMEDirectInformationTransfer(38), + id-PrivateMessage(39), + id-eNBConfigurationTransfer(40), + id-MMEConfigurationTransfer(41), + id-CellTrafficTrace(42), + id-Kill(43), + id-downlinkUEAssociatedLPPaTransport(44), + id-uplinkUEAssociatedLPPaTransport(45), + id-downlinkNonUEAssociatedLPPaTransport(46), + id-uplinkNonUEAssociatedLPPaTransport(47) +} (0..255) + +ProtocolExtensionID ::= INTEGER (0..65535) + +ProtocolIE-ID ::= INTEGER { + id-MME-UE-S1AP-ID (0), + id-HandoverType (1), + id-Cause (2), + id-SourceID (3), + id-TargetID (4), + id-eNB-UE-S1AP-ID (8), + id-E-RABSubjecttoDataForwardingList (12), + id-E-RABtoReleaseListHOCmd (13), + id-E-RABDataForwardingItem (14), + id-E-RABReleaseItemBearerRelComp (15), + id-E-RABToBeSetupListBearerSUReq (16), + id-E-RABToBeSetupItemBearerSUReq (17), + id-E-RABAdmittedList (18), + id-E-RABFailedToSetupListHOReqAck (19), + id-E-RABAdmittedItem (20), + id-E-RABFailedToSetupItemHOReqAck (21), + id-E-RABToBeSwitchedDLList (22), + id-E-RABToBeSwitchedDLItem (23), + id-E-RABToBeSetupListCtxtSUReq (24), + id-TraceActivation (25), + id-NAS-PDU (26), + id-E-RABToBeSetupItemHOReq (27), + id-E-RABSetupListBearerSURes (28), + id-E-RABFailedToSetupListBearerSURes (29), + id-E-RABToBeModifiedListBearerModReq (30), + id-E-RABModifyListBearerModRes (31), + id-E-RABFailedToModifyList (32), + id-E-RABToBeReleasedList (33), + id-E-RABFailedToReleaseList (34), + id-E-RABItem (35), + id-E-RABToBeModifiedItemBearerModReq (36), + id-E-RABModifyItemBearerModRes (37), + id-E-RABReleaseItem (38), + id-E-RABSetupItemBearerSURes (39), + id-SecurityContext (40), + id-HandoverRestrictionList (41), + id-UEPagingID (43), + id-pagingDRX (44), + id-TAIList (46), + id-TAIItem (47), + id-E-RABFailedToSetupListCtxtSURes (48), + id-E-RABReleaseItemHOCmd (49), + id-E-RABSetupItemCtxtSURes (50), + id-E-RABSetupListCtxtSURes (51), + id-E-RABToBeSetupItemCtxtSUReq (52), + id-E-RABToBeSetupListHOReq (53), + id-GERANtoLTEHOInformationRes (55), + id-UTRANtoLTEHOInformationRes (57), + id-CriticalityDiagnostics (58), + id-Global-ENB-ID (59), + id-eNBname (60), + id-MMEname (61), + id-ServedPLMNs (63), + id-SupportedTAs (64), + id-TimeToWait (65), + id-uEaggregateMaximumBitrate (66), + id-TAI (67), + id-E-RABReleaseListBearerRelComp (69), + id-cdma2000PDU (70), + id-cdma2000RATType (71), + id-cdma2000SectorID (72), + id-SecurityKey (73), + id-UERadioCapability (74), + id-GUMMEI-ID (75), + id-E-RABInformationListItem (78), + id-Direct-Forwarding-Path-Availability (79), + id-UEIdentityIndexValue (80), + id-cdma2000HOStatus (83), + id-cdma2000HORequiredIndication (84), + id-E-UTRAN-Trace-ID (86), + id-RelativeMMECapacity (87), + id-SourceMME-UE-S1AP-ID (88), + id-Bearers-SubjectToStatusTransfer-Item (89), + id-eNB-StatusTransfer-TransparentContainer (90), + id-UE-associatedLogicalS1-ConnectionItem (91), + id-ResetType (92), + id-UE-associatedLogicalS1-ConnectionListResAck (93), + id-E-RABToBeSwitchedULItem (94), + id-E-RABToBeSwitchedULList (95), + id-S-TMSI (96), + id-cdma2000OneXRAND (97), + id-RequestType (98), + id-UE-S1AP-IDs (99), + id-EUTRAN-CGI (100), + id-OverloadResponse (101), + id-cdma2000OneXSRVCCInfo (102), + id-E-RABFailedToBeReleasedList (103), + id-Source-ToTarget-TransparentContainer (104), + id-ServedGUMMEIs (105), + id-SubscriberProfileIDforRFP (106), + id-UESecurityCapabilities (107), + id-CSFallbackIndicator (108), + id-CNDomain (109), + id-E-RABReleasedList (110), + id-MessageIdentifier (111), + id-SerialNumber (112), + id-WarningAreaList (113), + id-RepetitionPeriod (114), + id-NumberofBroadcastRequest (115), + id-WarningType (116), + id-WarningSecurityInfo (117), + id-DataCodingScheme (118), + id-WarningMessageContents (119), + id-BroadcastCompletedAreaList (120), + id-Inter-SystemInformationTransferTypeEDT (121), + id-Inter-SystemInformationTransferTypeMDT (122), + id-Target-ToSource-TransparentContainer (123), + id-SRVCCOperationPossible (124), + id-SRVCCHOIndication (125), + id-NAS-DownlinkCount (126), + id-CSG-Id (127), + id-CSG-IdList (128), + id-SONConfigurationTransferECT (129), + id-SONConfigurationTransferMCT (130), + id-TraceCollectionEntityIPAddress (131), + id-MSClassmark2 (132), + id-MSClassmark3 (133), + id-RRC-Establishment-Cause (134), + id-NASSecurityParametersfromE-UTRAN (135), + id-NASSecurityParameterstoE-UTRAN (136), + id-DefaultPagingDRX (137), + id-Source-ToTarget-TransparentContainer-Secondary (138), + id-Target-ToSource-TransparentContainer-Secondary (139), + id-EUTRANRoundTripDelayEstimationInfo (140), + id-BroadcastCancelledAreaList (141), + id-ConcurrentWarningMessageIndicator (142), + id-Data-Forwarding-Not-Possible (143), + id-ExtendedRepetitionPeriod (144), + id-CellAccessMode (145), + id-CSGMembershipStatus (146), + id-LPPa-PDU (147), + id-Routing-ID (148), + id-Time-Synchronization-Info (149), + id-PS-ServiceNotAvailable (150), + id-PagingPriority (151), + id-x2TNLConfigurationInfo (152), + id-eNBX2ExtendedTransportLayerAddresses (153), + id-GUMMEIList (154), + id-GW-TransportLayerAddress (155), + id-Correlation-ID (156), + id-SourceMME-GUMMEI (157), + id-MME-UE-S1AP-ID-2 (158), + id-RegisteredLAI (159), + id-RelayNode-Indicator (160), + id-TrafficLoadReductionIndication (161), + id-MDTConfiguration (162), + id-MMERelaySupportIndicator (163), + id-GWContextReleaseIndication (164), + id-ManagementBasedMDTAllowed (165), + id-PrivacyIndicator (166) +} (0..65535) + +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessfull-outcome } + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Constants.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Constants.asn new file mode 100644 index 0000000000..5c6ce8cf08 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Constants.asn @@ -0,0 +1,283 @@ +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** + +S1AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Constants (4) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + ProcedureCode, + ProtocolIE-ID + +FROM S1AP-CommonDataTypes; + + +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** + +id-HandoverPreparation ProcedureCode ::= 0 +id-HandoverResourceAllocation ProcedureCode ::= 1 +id-HandoverNotification ProcedureCode ::= 2 +id-PathSwitchRequest ProcedureCode ::= 3 +id-HandoverCancel ProcedureCode ::= 4 +id-E-RABSetup ProcedureCode ::= 5 +id-E-RABModify ProcedureCode ::= 6 +id-E-RABRelease ProcedureCode ::= 7 +id-E-RABReleaseIndication ProcedureCode ::= 8 +id-InitialContextSetup ProcedureCode ::= 9 +id-Paging ProcedureCode ::= 10 +id-downlinkNASTransport ProcedureCode ::= 11 +id-initialUEMessage ProcedureCode ::= 12 +id-uplinkNASTransport ProcedureCode ::= 13 +id-Reset ProcedureCode::= 14 +id-ErrorIndication ProcedureCode ::= 15 +id-NASNonDeliveryIndication ProcedureCode ::= 16 +id-S1Setup ProcedureCode ::= 17 +id-UEContextReleaseRequest ProcedureCode ::= 18 +id-DownlinkS1cdma2000tunneling ProcedureCode ::= 19 +id-UplinkS1cdma2000tunneling ProcedureCode ::= 20 +id-UEContextModification ProcedureCode ::= 21 +id-UECapabilityInfoIndication ProcedureCode ::= 22 +id-UEContextRelease ProcedureCode ::= 23 +id-eNBStatusTransfer ProcedureCode ::= 24 +id-MMEStatusTransfer ProcedureCode ::= 25 +id-DeactivateTrace ProcedureCode ::= 26 +id-TraceStart ProcedureCode ::= 27 +id-TraceFailureIndication ProcedureCode ::= 28 +id-ENBConfigurationUpdate ProcedureCode ::= 29 +id-MMEConfigurationUpdate ProcedureCode ::= 30 +id-LocationReportingControl ProcedureCode ::= 31 +id-LocationReportingFailureIndication ProcedureCode ::= 32 +id-LocationReport ProcedureCode ::= 33 +id-OverloadStart ProcedureCode ::= 34 +id-OverloadStop ProcedureCode ::= 35 +id-WriteReplaceWarning ProcedureCode ::= 36 +id-eNBDirectInformationTransfer ProcedureCode ::= 37 +id-MMEDirectInformationTransfer ProcedureCode ::= 38 +id-PrivateMessage ProcedureCode ::= 39 +id-eNBConfigurationTransfer ProcedureCode ::= 40 +id-MMEConfigurationTransfer ProcedureCode ::= 41 +id-CellTrafficTrace ProcedureCode ::= 42 +id-Kill ProcedureCode ::= 43 +id-downlinkUEAssociatedLPPaTransport ProcedureCode ::= 44 +id-uplinkUEAssociatedLPPaTransport ProcedureCode ::= 45 +id-downlinkNonUEAssociatedLPPaTransport ProcedureCode ::= 46 +id-uplinkNonUEAssociatedLPPaTransport ProcedureCode ::= 47 + +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** + +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** + +maxNrOfCSGs INTEGER ::= 256 +maxNrOfE-RABs INTEGER ::= 256 +maxnoofTAIs INTEGER ::= 256 +maxnoofTACs INTEGER ::= 256 +maxNrOfErrors INTEGER ::= 256 +maxnoofBPLMNs INTEGER ::= 6 +maxnoofPLMNsPerMME INTEGER ::= 32 +maxnoofEPLMNs INTEGER ::= 15 +maxnoofEPLMNsPlusOne INTEGER ::= 16 +maxnoofForbLACs INTEGER ::= 4096 +maxnoofForbTACs INTEGER ::= 4096 +maxNrOfIndividualS1ConnectionsToReset INTEGER ::= 256 +maxnoofCells INTEGER ::= 16 +maxnoofTAIforWarning INTEGER ::= 65535 +maxnoofCellID INTEGER ::= 65535 +maxnoofEmergencyAreaID INTEGER ::= 65535 +maxnoofCellinTAI INTEGER ::= 65535 +maxnoofCellinEAI INTEGER ::= 65535 +maxnoofeNBX2TLAs INTEGER ::= 2 +maxnoofeNBX2ExtTLAs INTEGER ::= 16 +maxnoofeNBX2GTPTLAs INTEGER ::= 16 +maxnoofRATs INTEGER ::= 8 +maxnoofGroupIDs INTEGER ::= 65535 +maxnoofMMECs INTEGER ::= 256 +maxnoofCellIDforMDT INTEGER ::= 32 +maxnoofTAforMDT INTEGER ::= 8 + + +-- ************************************************************** +-- +-- IEs +-- +-- ************************************************************** + +id-MME-UE-S1AP-ID ProtocolIE-ID ::= 0 +id-HandoverType ProtocolIE-ID ::= 1 +id-Cause ProtocolIE-ID ::= 2 +id-SourceID ProtocolIE-ID ::= 3 +id-TargetID ProtocolIE-ID ::= 4 +id-eNB-UE-S1AP-ID ProtocolIE-ID ::= 8 +id-E-RABSubjecttoDataForwardingList ProtocolIE-ID ::= 12 +id-E-RABtoReleaseListHOCmd ProtocolIE-ID ::= 13 +id-E-RABDataForwardingItem ProtocolIE-ID ::= 14 +id-E-RABReleaseItemBearerRelComp ProtocolIE-ID ::= 15 +id-E-RABToBeSetupListBearerSUReq ProtocolIE-ID ::= 16 +id-E-RABToBeSetupItemBearerSUReq ProtocolIE-ID ::= 17 +id-E-RABAdmittedList ProtocolIE-ID ::= 18 +id-E-RABFailedToSetupListHOReqAck ProtocolIE-ID ::= 19 +id-E-RABAdmittedItem ProtocolIE-ID ::= 20 +id-E-RABFailedtoSetupItemHOReqAck ProtocolIE-ID ::= 21 +id-E-RABToBeSwitchedDLList ProtocolIE-ID ::= 22 +id-E-RABToBeSwitchedDLItem ProtocolIE-ID ::= 23 +id-E-RABToBeSetupListCtxtSUReq ProtocolIE-ID ::= 24 +id-TraceActivation ProtocolIE-ID ::= 25 +id-NAS-PDU ProtocolIE-ID ::= 26 +id-E-RABToBeSetupItemHOReq ProtocolIE-ID ::= 27 +id-E-RABSetupListBearerSURes ProtocolIE-ID ::= 28 +id-E-RABFailedToSetupListBearerSURes ProtocolIE-ID ::= 29 +id-E-RABToBeModifiedListBearerModReq ProtocolIE-ID ::= 30 +id-E-RABModifyListBearerModRes ProtocolIE-ID ::= 31 +id-E-RABFailedToModifyList ProtocolIE-ID ::= 32 +id-E-RABToBeReleasedList ProtocolIE-ID ::= 33 +id-E-RABFailedToReleaseList ProtocolIE-ID ::= 34 +id-E-RABItem ProtocolIE-ID ::= 35 +id-E-RABToBeModifiedItemBearerModReq ProtocolIE-ID ::= 36 +id-E-RABModifyItemBearerModRes ProtocolIE-ID ::= 37 +id-E-RABReleaseItem ProtocolIE-ID ::= 38 +id-E-RABSetupItemBearerSURes ProtocolIE-ID ::= 39 +id-SecurityContext ProtocolIE-ID ::= 40 +id-HandoverRestrictionList ProtocolIE-ID ::= 41 +id-UEPagingID ProtocolIE-ID ::= 43 +id-pagingDRX ProtocolIE-ID ::= 44 +id-TAIList ProtocolIE-ID ::= 46 +id-TAIItem ProtocolIE-ID ::= 47 +id-E-RABFailedToSetupListCtxtSURes ProtocolIE-ID ::= 48 +id-E-RABReleaseItemHOCmd ProtocolIE-ID ::= 49 +id-E-RABSetupItemCtxtSURes ProtocolIE-ID ::= 50 +id-E-RABSetupListCtxtSURes ProtocolIE-ID ::= 51 +id-E-RABToBeSetupItemCtxtSUReq ProtocolIE-ID ::= 52 +id-E-RABToBeSetupListHOReq ProtocolIE-ID ::= 53 +id-GERANtoLTEHOInformationRes ProtocolIE-ID ::= 55 +id-UTRANtoLTEHOInformationRes ProtocolIE-ID ::= 57 +id-CriticalityDiagnostics ProtocolIE-ID ::= 58 +id-Global-ENB-ID ProtocolIE-ID ::= 59 +id-eNBname ProtocolIE-ID ::= 60 +id-MMEname ProtocolIE-ID ::= 61 +id-ServedPLMNs ProtocolIE-ID ::= 63 +id-SupportedTAs ProtocolIE-ID ::= 64 +id-TimeToWait ProtocolIE-ID ::= 65 +id-uEaggregateMaximumBitrate ProtocolIE-ID ::= 66 +id-TAI ProtocolIE-ID ::= 67 +id-E-RABReleaseListBearerRelComp ProtocolIE-ID ::= 69 +id-cdma2000PDU ProtocolIE-ID ::= 70 +id-cdma2000RATType ProtocolIE-ID ::= 71 +id-cdma2000SectorID ProtocolIE-ID ::= 72 +id-SecurityKey ProtocolIE-ID ::= 73 +id-UERadioCapability ProtocolIE-ID ::= 74 +id-GUMMEI-ID ProtocolIE-ID ::= 75 +id-E-RABInformationListItem ProtocolIE-ID ::= 78 +id-Direct-Forwarding-Path-Availability ProtocolIE-ID ::= 79 +id-UEIdentityIndexValue ProtocolIE-ID ::= 80 +id-cdma2000HOStatus ProtocolIE-ID ::= 83 +id-cdma2000HORequiredIndication ProtocolIE-ID ::= 84 +id-E-UTRAN-Trace-ID ProtocolIE-ID ::= 86 +id-RelativeMMECapacity ProtocolIE-ID ::= 87 +id-SourceMME-UE-S1AP-ID ProtocolIE-ID ::= 88 +id-Bearers-SubjectToStatusTransfer-Item ProtocolIE-ID ::= 89 +id-eNB-StatusTransfer-TransparentContainer ProtocolIE-ID ::= 90 +id-UE-associatedLogicalS1-ConnectionItem ProtocolIE-ID ::= 91 +id-ResetType ProtocolIE-ID ::= 92 +id-UE-associatedLogicalS1-ConnectionListResAck ProtocolIE-ID ::= 93 +id-E-RABToBeSwitchedULItem ProtocolIE-ID ::= 94 +id-E-RABToBeSwitchedULList ProtocolIE-ID ::= 95 +id-S-TMSI ProtocolIE-ID ::= 96 +id-cdma2000OneXRAND ProtocolIE-ID ::= 97 +id-RequestType ProtocolIE-ID ::= 98 +id-UE-S1AP-IDs ProtocolIE-ID ::= 99 +id-EUTRAN-CGI ProtocolIE-ID ::= 100 +id-OverloadResponse ProtocolIE-ID ::= 101 +id-cdma2000OneXSRVCCInfo ProtocolIE-ID ::= 102 +id-E-RABFailedToBeReleasedList ProtocolIE-ID ::= 103 +id-Source-ToTarget-TransparentContainer ProtocolIE-ID ::= 104 +id-ServedGUMMEIs ProtocolIE-ID ::= 105 +id-SubscriberProfileIDforRFP ProtocolIE-ID ::= 106 +id-UESecurityCapabilities ProtocolIE-ID ::= 107 +id-CSFallbackIndicator ProtocolIE-ID ::= 108 +id-CNDomain ProtocolIE-ID ::= 109 +id-E-RABReleasedList ProtocolIE-ID ::= 110 +id-MessageIdentifier ProtocolIE-ID ::= 111 +id-SerialNumber ProtocolIE-ID ::= 112 +id-WarningAreaList ProtocolIE-ID ::= 113 +id-RepetitionPeriod ProtocolIE-ID ::= 114 +id-NumberofBroadcastRequest ProtocolIE-ID ::= 115 +id-WarningType ProtocolIE-ID ::= 116 +id-WarningSecurityInfo ProtocolIE-ID ::= 117 +id-DataCodingScheme ProtocolIE-ID ::= 118 +id-WarningMessageContents ProtocolIE-ID ::= 119 +id-BroadcastCompletedAreaList ProtocolIE-ID ::= 120 +id-Inter-SystemInformationTransferTypeEDT ProtocolIE-ID ::= 121 +id-Inter-SystemInformationTransferTypeMDT ProtocolIE-ID ::= 122 +id-Target-ToSource-TransparentContainer ProtocolIE-ID ::= 123 +id-SRVCCOperationPossible ProtocolIE-ID ::= 124 +id-SRVCCHOIndication ProtocolIE-ID ::= 125 +id-NAS-DownlinkCount ProtocolIE-ID ::= 126 +id-CSG-Id ProtocolIE-ID ::= 127 +id-CSG-IdList ProtocolIE-ID ::= 128 +id-SONConfigurationTransferECT ProtocolIE-ID ::= 129 +id-SONConfigurationTransferMCT ProtocolIE-ID ::= 130 +id-TraceCollectionEntityIPAddress ProtocolIE-ID ::= 131 +id-MSClassmark2 ProtocolIE-ID ::= 132 +id-MSClassmark3 ProtocolIE-ID ::= 133 +id-RRC-Establishment-Cause ProtocolIE-ID ::= 134 +id-NASSecurityParametersfromE-UTRAN ProtocolIE-ID ::= 135 +id-NASSecurityParameterstoE-UTRAN ProtocolIE-ID ::= 136 +id-DefaultPagingDRX ProtocolIE-ID ::= 137 +id-Source-ToTarget-TransparentContainer-Secondary ProtocolIE-ID ::= 138 +id-Target-ToSource-TransparentContainer-Secondary ProtocolIE-ID ::= 139 +id-EUTRANRoundTripDelayEstimationInfo ProtocolIE-ID ::= 140 +id-BroadcastCancelledAreaList ProtocolIE-ID ::= 141 +id-ConcurrentWarningMessageIndicator ProtocolIE-ID ::= 142 +id-Data-Forwarding-Not-Possible ProtocolIE-ID ::= 143 +id-ExtendedRepetitionPeriod ProtocolIE-ID ::= 144 +id-CellAccessMode ProtocolIE-ID ::= 145 +id-CSGMembershipStatus ProtocolIE-ID ::= 146 +id-LPPa-PDU ProtocolIE-ID ::= 147 +id-Routing-ID ProtocolIE-ID ::= 148 +id-Time-Synchronization-Info ProtocolIE-ID ::= 149 +id-PS-ServiceNotAvailable ProtocolIE-ID ::= 150 +id-PagingPriority ProtocolIE-ID ::= 151 +id-x2TNLConfigurationInfo ProtocolIE-ID ::= 152 +id-eNBX2ExtendedTransportLayerAddresses ProtocolIE-ID ::= 153 +id-GUMMEIList ProtocolIE-ID ::= 154 +id-GW-TransportLayerAddress ProtocolIE-ID ::= 155 +id-Correlation-ID ProtocolIE-ID ::= 156 +id-SourceMME-GUMMEI ProtocolIE-ID ::= 157 +id-MME-UE-S1AP-ID-2 ProtocolIE-ID ::= 158 +id-RegisteredLAI ProtocolIE-ID ::= 159 +id-RelayNode-Indicator ProtocolIE-ID ::= 160 +id-TrafficLoadReductionIndication ProtocolIE-ID ::= 161 +id-MDTConfiguration ProtocolIE-ID ::= 162 +id-MMERelaySupportIndicator ProtocolIE-ID ::= 163 +id-GWContextReleaseIndication ProtocolIE-ID ::= 164 +id-ManagementBasedMDTAllowed ProtocolIE-ID ::= 165 +id-PrivacyIndicator ProtocolIE-ID ::= 166 + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Containers.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Containers.asn new file mode 100644 index 0000000000..58490bd75a --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-Containers.asn @@ -0,0 +1,197 @@ +-- ************************************************************** +-- +-- Container definitions +-- +-- ************************************************************** + +S1AP-Containers { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Containers (5) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + Presence, + PrivateIE-ID, + ProtocolExtensionID, + ProtocolIE-ID +FROM S1AP-CommonDataTypes + + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs +FROM S1AP-Constants; + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +S1AP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +S1AP-PROTOCOL-IES-PAIR ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &firstCriticality Criticality, + &FirstValue, + &secondCriticality Criticality, + &SecondValue, + &presence Presence +} +WITH SYNTAX { + ID &id + FIRST CRITICALITY &firstCriticality + FIRST TYPE &FirstValue + SECOND CRITICALITY &secondCriticality + SECOND TYPE &SecondValue + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol Extensions +-- +-- ************************************************************** + +S1AP-PROTOCOL-EXTENSION ::= CLASS { + &id ProtocolExtensionID UNIQUE, + &criticality Criticality, + &Extension, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + EXTENSION &Extension + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Private IEs +-- +-- ************************************************************** + +S1AP-PRIVATE-IES ::= CLASS { + &id PrivateIE-ID, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Container for Protocol IEs +-- +-- ************************************************************** + +ProtocolIE-Container {S1AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-SingleContainer {S1AP-PROTOCOL-IES : IEsSetParam} ::= + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-Field {S1AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-IES.&id ({IEsSetParam}), + criticality S1AP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}), + value S1AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Protocol IE Pairs +-- +-- ************************************************************** + +ProtocolIE-ContainerPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-FieldPair {{IEsSetParam}} + +ProtocolIE-FieldPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-IES-PAIR.&id ({IEsSetParam}), + firstCriticality S1AP-PROTOCOL-IES-PAIR.&firstCriticality ({IEsSetParam}{@id}), + firstValue S1AP-PROTOCOL-IES-PAIR.&FirstValue ({IEsSetParam}{@id}), + secondCriticality S1AP-PROTOCOL-IES-PAIR.&secondCriticality ({IEsSetParam}{@id}), + secondValue S1AP-PROTOCOL-IES-PAIR.&SecondValue ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container Lists for Protocol IE Containers +-- +-- ************************************************************** + +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-SingleContainer {{IEsSetParam}} + +ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-ContainerPair {{IEsSetParam}} + +-- ************************************************************** +-- +-- Container for Protocol Extensions +-- +-- ************************************************************** + +ProtocolExtensionContainer {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= + SEQUENCE (SIZE (1..maxProtocolExtensions)) OF + ProtocolExtensionField {{ExtensionSetParam}} + +ProtocolExtensionField {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}), + criticality S1AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}), + extensionValue S1AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Private IEs +-- +-- ************************************************************** + +PrivateIE-Container {S1AP-PRIVATE-IES : IEsSetParam } ::= + SEQUENCE (SIZE (1.. maxPrivateIEs)) OF + PrivateIE-Field {{IEsSetParam}} + +PrivateIE-Field {S1AP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE { + id S1AP-PRIVATE-IES.&id ({IEsSetParam}), + criticality S1AP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}), + value S1AP-PRIVATE-IES.&Value ({IEsSetParam}{@id}) +} + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-IEs.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-IEs.asn new file mode 100644 index 0000000000..9a7db5f592 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-IEs.asn @@ -0,0 +1,1444 @@ +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** + +S1AP-IEs { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-IEs (2) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + id-E-RABInformationListItem, + id-E-RABItem, + id-Bearers-SubjectToStatusTransfer-Item, + id-Time-Synchronization-Info, + id-x2TNLConfigurationInfo, + id-eNBX2ExtendedTransportLayerAddresses, + id-MDTConfiguration, + maxNrOfCSGs, + maxNrOfE-RABs, + maxNrOfErrors, + maxnoofBPLMNs, + maxnoofPLMNsPerMME, + maxnoofTACs, + maxnoofEPLMNs, + maxnoofEPLMNsPlusOne, + maxnoofForbLACs, + maxnoofForbTACs, + maxnoofCells, + maxnoofCellID, + maxnoofEmergencyAreaID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + maxnoofeNBX2TLAs, + maxnoofeNBX2ExtTLAs, + maxnoofeNBX2GTPTLAs, + maxnoofRATs, + maxnoofGroupIDs, + maxnoofMMECs, + maxnoofTAforMDT, + maxnoofCellIDforMDT, + maxProtocolExtensions, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofTAIs + +FROM S1AP-Constants + + IE +FROM S1AP-PDU + + Criticality, + ProcedureCode, + ProtocolIE-ID, + TriggeringMessage +FROM S1AP-CommonDataTypes; + +IE-Extensions ::= SEQUENCE (SIZE (1..maxProtocolExtensions)) OF IE + +-- A + +AreaScopeOfMDT ::= CHOICE { + cellBased CellBasedMDT, + tABased TABasedMDT, + pLMNWide NULL, + ... +} + +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, + -- iE-Extensions ProtocolExtensionContainer { {AllocationAndRetentionPriority-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- B + +-- Bearers-SubjectToStatusTransferList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { Bearers-SubjectToStatusTransfer-ItemIEs } } +Bearers-SubjectToStatusTransfer-List ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +Bearers-SubjectToStatusTransfer-Item ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + uL-COUNTvalue COUNTvalue, + dL-COUNTvalue COUNTvalue, + receiveStatusofULPDCPSDUs ReceiveStatusofULPDCPSDUs OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {Bearers-SubjectToStatusTransfer-ItemExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +BitRate ::= INTEGER (0..10000000000) + +BPLMNs ::= SEQUENCE (SIZE(1.. maxnoofBPLMNs)) OF PLMNidentity + +BroadcastCancelledAreaList ::= CHOICE { + cellID-Cancelled CellID-Cancelled, + tAI-Cancelled TAI-Cancelled, + emergencyAreaID-Cancelled EmergencyAreaID-Cancelled, + ... +} + +BroadcastCompletedAreaList ::= CHOICE { + cellID-Broadcast CellID-Broadcast, + tAI-Broadcast TAI-Broadcast, + emergencyAreaID-Broadcast EmergencyAreaID-Broadcast, + ... +} + + +-- C + +CancelledCellinEAI ::= SEQUENCE (SIZE(1..maxnoofCellinEAI)) OF CancelledCellinEAI-Item + +CancelledCellinEAI-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + -- iE-Extensions ProtocolExtensionContainer { {CancelledCellinEAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CancelledCellinTAI ::= SEQUENCE (SIZE(1..maxnoofCellinTAI)) OF CancelledCellinTAI-Item + +CancelledCellinTAI-Item ::= SEQUENCE{ + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + -- iE-Extensions ProtocolExtensionContainer { {CancelledCellinTAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nas CauseNas, + protocol CauseProtocol, + misc CauseMisc, + ... +} + +CauseMisc ::= ENUMERATED { + control-processing-overload, + not-enough-user-plane-processing-resources, + hardware-failure, + om-intervention, + unspecified, + unknown-PLMN, + ... +} + +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} + +CauseRadioNetwork ::= ENUMERATED { + unspecified, + tx2relocoverall-expiry, + successful-handover, + release-due-to-eutran-generated-reason, + handover-cancelled, + partial-handover, + ho-failure-in-target-EPC-eNB-or-target-system, + ho-target-not-allowed, + tS1relocoverall-expiry, + tS1relocprep-expiry, + cell-not-available, + unknown-targetID, + no-radio-resources-available-in-target-cell, + unknown-mme-ue-s1ap-id, + unknown-enb-ue-s1ap-id, + unknown-pair-ue-s1ap-id, + handover-desirable-for-radio-reason, + time-critical-handover, + resource-optimisation-handover, + reduce-load-in-serving-cell, + user-inactivity, + radio-connection-with-ue-lost, + load-balancing-tau-required, + cs-fallback-triggered, + ue-not-available-for-ps-service, + radio-resources-not-available, + failure-in-radio-interface-procedure, + invalid-qos-combination, + interrat-redirection, + interaction-with-other-procedure, + unknown-E-RAB-ID, + multiple-E-RAB-ID-instances, + encryption-and-or-integrity-protection-algorithms-not-supported, + s1-intra-system-handover-triggered, + s1-inter-system-handover-triggered, + x2-handover-triggered, + ..., + redirection-towards-1xRTT, + not-supported-QCI-value, + invalid-CSG-Id + +} + +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} + +CauseNas ::= ENUMERATED { + normal-release, + authentication-failure, + detach, + unspecified, + ..., + csg-subscription-expiry +} + +CellAccessMode ::= ENUMERATED { + hybrid, + ... +} + +CellIdentity ::= BIT STRING (SIZE (28)) + +CellID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF CellID-Broadcast-Item + +CellID-Broadcast-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + -- iE-Extensions ProtocolExtensionContainer { {CellID-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CellID-Cancelled::= SEQUENCE (SIZE(1..maxnoofCellID)) OF CellID-Cancelled-Item + +CellID-Cancelled-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + -- iE-Extensions ProtocolExtensionContainer { {CellID-Cancelled-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CellBasedMDT::= SEQUENCE { + cellIdListforMDT CellIdListforMDT, + -- iE-Extensions ProtocolExtensionContainer { {CellBasedMDT-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CellIdListforMDT ::= SEQUENCE (SIZE(1..maxnoofCellIDforMDT)) OF EUTRAN-CGI + +Cdma2000PDU ::= OCTET STRING + +Cdma2000RATType ::= ENUMERATED { + hRPD, + onexRTT, + ... +} + +Cdma2000SectorID ::= OCTET STRING + +Cdma2000HOStatus ::= ENUMERATED { + hOSuccess, + hOFailure, + ... +} + +Cdma2000HORequiredIndication ::= ENUMERATED { + true, + ... +} + +Cdma2000OneXSRVCCInfo ::= SEQUENCE { + cdma2000OneXMEID Cdma2000OneXMEID, + cdma2000OneXMSI Cdma2000OneXMSI, + cdma2000OneXPilot Cdma2000OneXPilot, + -- iE-Extensions ProtocolExtensionContainer { {Cdma2000OneXSRVCCInfo-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Cdma2000OneXMEID ::= OCTET STRING + +Cdma2000OneXMSI ::= OCTET STRING + +Cdma2000OneXPilot ::= OCTET STRING + +Cdma2000OneXRAND ::= OCTET STRING + + +Cell-Size ::= ENUMERATED {verysmall, small, medium, large, ...} + +CellType ::= SEQUENCE { + cell-Size Cell-Size, + -- iE-Extensions ProtocolExtensionContainer { { CellType-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, + cI CI, + rAC RAC OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {CGI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... + } + +CI ::= OCTET STRING (SIZE (2)) + +CNDomain ::= ENUMERATED { + ps, + cs +} + +ConcurrentWarningMessageIndicator ::= ENUMERATED { + true +} + +Correlation-ID ::= OCTET STRING (SIZE (4)) + +CSFallbackIndicator ::= ENUMERATED { + cs-fallback-required, + ..., + cs-fallback-high-priority +} + +CSG-Id ::= BIT STRING (SIZE (27)) + + +CSG-IdList ::= SEQUENCE (SIZE (1..maxNrOfCSGs)) OF CSG-IdList-Item + +CSG-IdList-Item ::= SEQUENCE { + cSG-Id CSG-Id, + -- iE-Extensions ProtocolExtensionContainer { {CSG-IdList-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CSGMembershipStatus ::= ENUMERATED { + member, + not-member +} + + +COUNTvalue ::= SEQUENCE { + pDCP-SN PDCP-SN, + hFN HFN, + -- iE-Extensions ProtocolExtensionContainer { {COUNTvalue-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer {{CriticalityDiagnostics-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxNrOfErrors)) OF CriticalityDiagnostics-IE-Item + +CriticalityDiagnostics-IE-Item ::= SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, + -- iE-Extensions ProtocolExtensionContainer {{CriticalityDiagnostics-IE-Item-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- D + +DataCodingScheme ::= BIT STRING (SIZE (8)) + +DL-Forwarding ::= ENUMERATED { + dL-Forwarding-proposed, + ... +} + +Direct-Forwarding-Path-Availability ::= ENUMERATED { + directPathAvailable, + ... +} + +Data-Forwarding-Not-Possible ::= ENUMERATED { + data-Forwarding-not-Possible, + ... +} + +-- E + +ECGIList ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF EUTRAN-CGI + +EmergencyAreaIDList ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID + +EmergencyAreaID ::= OCTET STRING (SIZE (3)) + +EmergencyAreaID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID-Broadcast-Item + +EmergencyAreaID-Broadcast-Item ::= SEQUENCE { + emergencyAreaID EmergencyAreaID, + completedCellinEAI CompletedCellinEAI, + -- iE-Extensions ProtocolExtensionContainer { {EmergencyAreaID-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EmergencyAreaID-Cancelled ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID-Cancelled-Item + +EmergencyAreaID-Cancelled-Item ::= SEQUENCE { + emergencyAreaID EmergencyAreaID, + cancelledCellinEAI CancelledCellinEAI, + -- iE-Extensions ProtocolExtensionContainer { {EmergencyAreaID-Cancelled-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CompletedCellinEAI ::= SEQUENCE (SIZE(1..maxnoofCellinEAI)) OF CompletedCellinEAI-Item + +CompletedCellinEAI-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + -- iE-Extensions ProtocolExtensionContainer { {CompletedCellinEAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-ID ::= CHOICE { + macroENB-ID BIT STRING (SIZE(20)), + homeENB-ID BIT STRING (SIZE(28)), + ... +} + +GERAN-Cell-ID ::= SEQUENCE { + lAI LAI, + rAC RAC, + cI CI, + -- iE-Extensions ProtocolExtensionContainer { { GERAN-Cell-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Global-ENB-ID ::= SEQUENCE { + pLMNidentity PLMNidentity, + eNB-ID ENB-ID, + -- iE-Extensions ProtocolExtensionContainer { {GlobalENB-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +GUMMEIList::= SEQUENCE (SIZE (1.. maxnoofMMECs)) OF GUMMEI + +ENB-StatusTransfer-TransparentContainer ::= SEQUENCE { + bearers-SubjectToStatusTransferList Bearers-SubjectToStatusTransfer-List, + -- iE-Extensions ProtocolExtensionContainer { {ENB-StatusTransfer-TransparentContainer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-UE-S1AP-ID ::= INTEGER (0..16777215) + +ENBname ::= PrintableString (SIZE (1..150,...)) + +ENBX2TLAs ::= SEQUENCE (SIZE(1.. maxnoofeNBX2TLAs)) OF TransportLayerAddress + +EncryptionAlgorithms ::= BIT STRING (SIZE (16,...)) + +EPLMNs ::= SEQUENCE (SIZE(1..maxnoofEPLMNs)) OF PLMNidentity +EventType ::= ENUMERATED { + direct, + change-of-serve-cell, + stop-change-of-serve-cell, + ... +} + +E-RAB-ID ::= INTEGER (0..15, ...) + +E-RABDataForwardingItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { { E-RABDataForwardingItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemHOReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + e-RABlevelQosParameters E-RABLevelQoSParameters, + -- iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemHOReq-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABAdmittedItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {E-RABAdmittedItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedDLItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + -- iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedDLItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedULItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + -- iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedULItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemBearerSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU, + -- iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemBearerSUReqExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupItemBearerSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + -- iE-Extensions ProtocolExtensionContainer { {E-RABSetupItemBearerSUResExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeModifiedItemBearerModReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABLevelQoSParameters E-RABLevelQoSParameters, + nAS-PDU NAS-PDU, + -- iE-Extensions ProtocolExtensionContainer { {E-RABToBeModifyItemBearerModReqExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABReleaseItemBearerRelComp ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + -- iE-Extensions ProtocolExtensionContainer { {E-RABReleaseItemBearerRelCompExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemCtxtSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupItemCtxtSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF IE +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABDataForwardingList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABFailedToSetupListHOReqAck ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABAdmittedList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABToBeSwitchedDLList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABToBeSwitchedULList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE +E-RABToBeSetupListHOReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +TAIList::= SEQUENCE (SIZE(1.. maxnoofTAIs)) OF IE +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE + +E-RABModifyItemBearerModRes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + -- iE-Extensions ProtocolExtensionContainer { {E-RABModifyItemBearerModResExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + -- iE-Extensions ProtocolExtensionContainer { { E-RABFailedToSetupItemHOReqAckExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABInformationListItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-Forwarding DL-Forwarding OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {E-RABInformationListItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABItemIEs} } +E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + -- iE-Extensions ProtocolExtensionContainer { {E-RABItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABLevelQoSParameters ::= SEQUENCE { + qCI QCI, + allocationRetentionPriority AllocationAndRetentionPriority, + gbrQosInformation GBR-QosInformation OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {E-RABQoSParameters-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EUTRAN-CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + cell-ID CellIdentity, + -- iE-Extensions ProtocolExtensionContainer { {EUTRAN-CGI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EUTRANRoundTripDelayEstimationInfo ::= INTEGER (0..2047) + +ExtendedRNC-ID ::= INTEGER (4096..65535) + +ExtendedRepetitionPeriod ::= INTEGER (4096..131071) + +-- F + +ForbiddenInterRATs ::= ENUMERATED { + all, + geran, + utran, + cdma2000, + ..., + geranandutran, + cdma2000andutran + +} + +ForbiddenTAs ::= SEQUENCE (SIZE(1.. maxnoofEPLMNsPlusOne)) OF ForbiddenTAs-Item + +ForbiddenTAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenTACs ForbiddenTACs, + -- iE-Extensions ProtocolExtensionContainer { {ForbiddenTAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ForbiddenTACs ::= SEQUENCE (SIZE(1..maxnoofForbTACs)) OF TAC + +ForbiddenLAs ::= SEQUENCE (SIZE(1..maxnoofEPLMNsPlusOne)) OF ForbiddenLAs-Item + +ForbiddenLAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenLACs ForbiddenLACs, + -- iE-Extensions ProtocolExtensionContainer { {ForbiddenLAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ForbiddenLACs ::= SEQUENCE (SIZE(1..maxnoofForbLACs)) OF LAC + +-- G + +GBR-QosInformation ::= SEQUENCE { + e-RAB-MaximumBitrateDL BitRate, + e-RAB-MaximumBitrateUL BitRate, + e-RAB-GuaranteedBitrateDL BitRate, + e-RAB-GuaranteedBitrateUL BitRate, + -- iE-Extensions ProtocolExtensionContainer { { GBR-QosInformation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +GTP-TEID ::= OCTET STRING (SIZE (4)) + +GUMMEI ::= SEQUENCE { + pLMN-Identity PLMNidentity, + mME-Group-ID MME-Group-ID, + mME-Code MME-Code, + -- iE-Extensions ProtocolExtensionContainer { {GUMMEI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +GWContextReleaseIndication ::= ENUMERATED { + true, + ... +} + +-- H + +HandoverRestrictionList ::= SEQUENCE { + servingPLMN PLMNidentity, + equivalentPLMNs EPLMNs OPTIONAL, + forbiddenTAs ForbiddenTAs OPTIONAL, + forbiddenLAs ForbiddenLAs OPTIONAL, + forbiddenInterRATs ForbiddenInterRATs OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {HandoverRestrictionList-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +HandoverType ::= ENUMERATED { + intralte, + ltetoutran, + ltetogeran, + utrantolte, + gerantolte, + ... +} + +HFN ::= INTEGER (0..1048575) + +-- I + +ImmediateMDT ::= SEQUENCE { + measurementsToActivate MeasurementsToActivate, + reportingTriggerMDT ReportingTriggerMDT, + thresholdeventA2 ThresholdEventA2 OPTIONAL, +-- Included in case of event-triggered reporting for measurement M1 + periodicReportingMDT PeriodicReportingMDT OPTIONAL, +-- Included in case of periodic reporting + -- iE-Extensions ProtocolExtensionContainer { { ImmediateMDT-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +IMSI ::= OCTET STRING (SIZE (3..8)) + +IntegrityProtectionAlgorithms ::= BIT STRING (SIZE (16,...)) + +InterfacesToTrace ::= BIT STRING (SIZE (8)) + +Inter-SystemInformationTransferType ::= CHOICE { + rIMTransfer RIMTransfer, + ... +} + +-- J +-- K +-- L + + +LAC ::= OCTET STRING (SIZE (2)) + +LAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, + -- iE-Extensions ProtocolExtensionContainer { {LAI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +LastVisitedCell-Item ::= CHOICE { + e-UTRAN-Cell LastVisitedEUTRANCellInformation, + uTRAN-Cell LastVisitedUTRANCellInformation, + gERAN-Cell LastVisitedGERANCellInformation, + ... +} +LastVisitedEUTRANCellInformation ::= SEQUENCE { + global-Cell-ID EUTRAN-CGI, + cellType CellType, + time-UE-StayedInCell Time-UE-StayedInCell, + -- iE-Extensions ProtocolExtensionContainer { { LastVisitedEUTRANCellInformation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +LastVisitedUTRANCellInformation ::= OCTET STRING + +LastVisitedGERANCellInformation ::= CHOICE { + undefined NULL, + ... +} + +L3-Information ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + +LPPa-PDU ::= OCTET STRING + +LoggedMDT ::= SEQUENCE { + loggingInterval LoggingInterval, + loggingDuration LoggingDuration, + -- iE-Extensions ProtocolExtensionContainer { {LoggedMDT-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +LoggingInterval ::= ENUMERATED {ms128, ms256, ms512, ms1024, ms2048, ms3072, ms4096, ms6144} + +LoggingDuration ::= ENUMERATED {m10, m20, m40, m60, m90, m120} + +-- M + +MDT-Activation ::= ENUMERATED { + immediate-MDT-only, + immediate-MDT-and-Trace, + logged-MDT-only, + ... +} + +MDT-Configuration ::= SEQUENCE { + mdt-Activation MDT-Activation, + areaScopeOfMDT AreaScopeOfMDT, + mDTMode MDTMode, + -- iE-Extensions ProtocolExtensionContainer { { MDT-Configuration-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ManagementBasedMDTAllowed ::= ENUMERATED {allowed, ...} + +PrivacyIndicator ::= ENUMERATED { + immediate-MDT, + logged-MDT, + ... +} + +MDTMode ::= CHOICE { + immediateMDT ImmediateMDT, + loggedMDT LoggedMDT, + ... +} + +MeasurementsToActivate ::= BIT STRING (SIZE (8)) + +MeasurementThresholdA2 ::= CHOICE { + threshold-RSRP Threshold-RSRP, + threshold-RSRQ Threshold-RSRQ, + ... +} + +MessageIdentifier ::= BIT STRING (SIZE (16)) + +MMEname ::= PrintableString (SIZE (1..150,...)) + +MMERelaySupportIndicator ::= ENUMERATED {true, ...} + +MME-Group-ID ::= OCTET STRING (SIZE (2)) + +MME-Code ::= OCTET STRING (SIZE (1)) + +MME-UE-S1AP-ID ::= INTEGER (0..4294967295) +M-TMSI ::= OCTET STRING (SIZE (4)) + +MSClassmark2 ::= OCTET STRING +MSClassmark3 ::= OCTET STRING + +-- N + +NAS-PDU ::= OCTET STRING + +NASSecurityParametersfromE-UTRAN ::= OCTET STRING + +NASSecurityParameterstoE-UTRAN ::= OCTET STRING + +NumberofBroadcastRequest ::= INTEGER (0..65535) + +NumberOfBroadcasts ::= INTEGER (0..65535) + +-- O +OldBSS-ToNewBSS-Information ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + +OverloadAction ::= ENUMERATED { + reject-non-emergency-mo-dt, + reject-rrc-cr-signalling, + permit-emergency-sessions-and-mobile-terminated-services-only, + ..., + permit-high-priority-sessions-and-mobile-terminated-services-only, + reject-delay-tolerant-access +} + +OverloadResponse ::= CHOICE { + overloadAction OverloadAction, + ... +} + + +-- P + +PagingDRX ::= ENUMERATED { + v32, + v64, + v128, + v256, + ... + } + +PagingPriority ::= ENUMERATED { + priolevel1, + priolevel2, + priolevel3, + priolevel4, + priolevel5, + priolevel6, + priolevel7, + priolevel8, + ... +} + +PDCP-SN ::= INTEGER (0..4095) + +PeriodicReportingMDT ::= SEQUENCE { + reportInterval ReportIntervalMDT, + reportAmount ReportAmountMDT, + -- iE-Extensions ProtocolExtensionContainer { { PeriodicReportingMDT-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +PLMNidentity ::= TBCD-STRING + +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} + +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} + +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) + +PS-ServiceNotAvailable ::= ENUMERATED { + ps-service-not-available, + ... +} + +-- Q + +QCI ::= INTEGER (0..255) + +-- R + +ResetType ::= CHOICE { + s1-Interface ResetAll, + partOfS1-Interface UE-associatedLogicalS1-ConnectionListRes, + ... +} + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +ReceiveStatusofULPDCPSDUs ::= BIT STRING (SIZE(4096)) + +RelativeMMECapacity ::= INTEGER (0..255) + +RelayNode-Indicator ::= ENUMERATED { + true, + ... +} + +RAC ::= OCTET STRING (SIZE (1)) + +ReportAmountMDT ::= ENUMERATED{r1, r2, r4, r8, r16, r32, r64, rinfinity} + +ReportIntervalMDT ::= ENUMERATED {ms120, ms240, ms480, ms640, ms1024, ms2048, ms5120, ms10240, min1, min6, min12, min30, min60} + +ReportingTriggerMDT ::= ENUMERATED{ + periodic, + a2eventtriggered, + ... +} + +RequestType ::= SEQUENCE { + eventType EventType, + reportArea ReportArea, + -- iE-Extensions ProtocolExtensionContainer { { RequestType-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +RIMTransfer ::= SEQUENCE { + rIMInformation RIMInformation, + rIMRoutingAddress RIMRoutingAddress OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { { RIMTransfer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +RIMInformation ::= OCTET STRING + +RIMRoutingAddress ::= CHOICE { + gERAN-Cell-ID GERAN-Cell-ID, + ..., + targetRNC-ID TargetRNC-ID +} + +ReportArea ::= ENUMERATED { + ecgi, + ... +} + +RepetitionPeriod ::= INTEGER (0..4095) + + +RNC-ID ::= INTEGER (0..4095) + +RRC-Container ::= OCTET STRING + +RRC-Establishment-Cause ::= ENUMERATED { + emergency, + highPriorityAccess, + mt-Access, + mo-Signalling, + mo-Data, + ..., + delay-TolerantAccess +} + +Routing-ID ::= INTEGER (0..255) + +-- S + + +SecurityKey ::= BIT STRING (SIZE(256)) + + + +SecurityContext ::= SEQUENCE { + nextHopChainingCount INTEGER (0..7), + nextHopParameter SecurityKey, + -- iE-Extensions ProtocolExtensionContainer { { SecurityContext-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +SerialNumber ::= BIT STRING (SIZE (16)) + +SONInformation ::= CHOICE{ + sONInformationRequest SONInformationRequest, + sONInformationReply SONInformationReply, + ... +} + +SONInformationRequest ::= ENUMERATED { + x2TNL-Configuration-Info, + ..., + time-Synchronization-Info} + +SONInformationReply ::= SEQUENCE { + x2TNLConfigurationInfo X2TNLConfigurationInfo OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer {{SONInformationReply-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +SONConfigurationTransfer ::= SEQUENCE { + targeteNB-ID TargeteNB-ID, + sourceeNB-ID SourceeNB-ID, + sONInformation SONInformation, + -- iE-Extensions ProtocolExtensionContainer { { SONConfigurationTransfer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, +... +} + +Source-ToTarget-TransparentContainer ::= OCTET STRING +-- This IE includes a transparent container from the source RAN node to the target RAN node. +-- The octets of the OCTET STRING are encoded according to the specifications of the target system. + +SourceBSS-ToTargetBSS-TransparentContainer ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + +SourceeNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, + -- iE-Extensions ProtocolExtensionContainer { {SourceeNB-ID-ExtIEs} } OPTIONAL + iE-Extensions IE-Extensions OPTIONAL +} + +SRVCCOperationPossible ::= ENUMERATED { + possible, + ... +} + +SRVCCHOIndication ::= ENUMERATED { + pSandCS, + cSonly, + ... +} + +SourceeNB-ToTargeteNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, + e-RABInformationList E-RABInformationList OPTIONAL, + targetCell-ID EUTRAN-CGI, + subscriberProfileIDforRFP SubscriberProfileIDforRFP OPTIONAL, + uE-HistoryInformation UE-HistoryInformation, + -- iE-Extensions ProtocolExtensionContainer { {SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +SourceRNC-ToTargetRNC-TransparentContainer ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + + +ServedGUMMEIs ::= SEQUENCE (SIZE (1.. maxnoofRATs)) OF ServedGUMMEIsItem + +ServedGUMMEIsItem ::= SEQUENCE { + servedPLMNs ServedPLMNs, + servedGroupIDs ServedGroupIDs, + servedMMECs ServedMMECs, + -- iE-Extensions ProtocolExtensionContainer { {ServedGUMMEIsItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ServedGroupIDs ::= SEQUENCE (SIZE(1.. maxnoofGroupIDs)) OF MME-Group-ID +ServedMMECs ::= SEQUENCE (SIZE(1.. maxnoofMMECs)) OF MME-Code + +ServedPLMNs ::= SEQUENCE (SIZE(1.. maxnoofPLMNsPerMME)) OF PLMNidentity + +SubscriberProfileIDforRFP ::= INTEGER (1..256) + +SupportedTAs ::= SEQUENCE (SIZE(1.. maxnoofTACs)) OF SupportedTAs-Item + +SupportedTAs-Item ::= SEQUENCE { + tAC TAC, + broadcastPLMNs BPLMNs, + -- iE-Extensions ProtocolExtensionContainer { {SupportedTAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +StratumLevel ::= INTEGER (0..3, ...) + +SynchronizationStatus ::= ENUMERATED { synchronous, asynchronous, ... } + +TimeSynchronizationInfo ::= SEQUENCE { + stratumLevel StratumLevel, + synchronizationStatus SynchronizationStatus, + -- iE-Extensions ProtocolExtensionContainer { { TimeSynchronizationInfo-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +S-TMSI ::= SEQUENCE { + mMEC MME-Code, + m-TMSI M-TMSI, + -- iE-Extensions ProtocolExtensionContainer { {S-TMSI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- T + +TAC ::= OCTET STRING (SIZE (2)) + +TAIListforWarning ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI + +TAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + tAC TAC, + -- iE-Extensions ProtocolExtensionContainer { {TAI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAIItem ::= SEQUENCE { + tAI TAI, + -- iE-Extensions ProtocolExtensionContainer { {TAIItemExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAI-Broadcast ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI-Broadcast-Item + +TAI-Broadcast-Item ::= SEQUENCE { + tAI TAI, + completedCellinTAI CompletedCellinTAI, + -- iE-Extensions ProtocolExtensionContainer { {TAI-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAI-Cancelled ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI-Cancelled-Item + +TAI-Cancelled-Item ::= SEQUENCE { + tAI TAI, + cancelledCellinTAI CancelledCellinTAI, + -- iE-Extensions ProtocolExtensionContainer { {TAI-Cancelled-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TABasedMDT ::= SEQUENCE { + tAListforMDT TAListforMDT, + -- iE-Extensions ProtocolExtensionContainer { {TABasedMDT-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAListforMDT ::= SEQUENCE (SIZE(1..maxnoofTAforMDT)) OF TAC + +CompletedCellinTAI ::= SEQUENCE (SIZE(1..maxnoofCellinTAI)) OF CompletedCellinTAI-Item + +CompletedCellinTAI-Item ::= SEQUENCE{ + eCGI EUTRAN-CGI, + -- iE-Extensions ProtocolExtensionContainer { {CompletedCellinTAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TBCD-STRING ::= OCTET STRING (SIZE (3)) + +TargetID ::= CHOICE { + targeteNB-ID TargeteNB-ID, + targetRNC-ID TargetRNC-ID, + cGI CGI, + ... +} + +TargeteNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, + -- iE-Extensions ProtocolExtensionContainer { {TargeteNB-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TargetRNC-ID ::= SEQUENCE { + lAI LAI, + rAC RAC OPTIONAL, + rNC-ID RNC-ID, + extendedRNC-ID ExtendedRNC-ID OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { {TargetRNC-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... + } + +TargeteNB-ToSourceeNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, + -- iE-Extensions ProtocolExtensionContainer { {TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Target-ToSource-TransparentContainer ::= OCTET STRING +-- This IE includes a transparent container from the target RAN node to the source RAN node. +-- The octets of the OCTET STRING are coded according to the specifications of the target system. + +TargetRNC-ToSourceRNC-TransparentContainer ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + +TargetBSS-ToSourceBSS-TransparentContainer ::= OCTET STRING +-- This is a dummy IE used only as a reference to the actual definition in relevant specification. + +ThresholdEventA2 ::= SEQUENCE { + measurementThreshold MeasurementThresholdA2, + -- iE-Extensions ProtocolExtensionContainer { { ThresholdEventA2-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Threshold-RSRP ::= INTEGER(0..97) + +Threshold-RSRQ ::= INTEGER(0..34) + +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} + +Time-UE-StayedInCell ::= INTEGER (0..4095) + +TransportLayerAddress ::= BIT STRING (SIZE(1..160, ...)) + +TraceActivation ::= SEQUENCE { + e-UTRAN-Trace-ID E-UTRAN-Trace-ID, + interfacesToTrace InterfacesToTrace, +traceDepth TraceDepth, +traceCollectionEntityIPAddress TransportLayerAddress, + -- iE-Extensions ProtocolExtensionContainer { { TraceActivation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TraceDepth ::= ENUMERATED { + minimum, + medium, + maximum, + minimumWithoutVendorSpecificExtension, + mediumWithoutVendorSpecificExtension, + maximumWithoutVendorSpecificExtension, + ... +} + +E-UTRAN-Trace-ID ::= OCTET STRING (SIZE (8)) + +TrafficLoadReductionIndication ::= INTEGER (1..99) + +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} + +-- U + +UEAggregateMaximumBitrate ::= SEQUENCE { + uEaggregateMaximumBitRateDL BitRate, + uEaggregateMaximumBitRateUL BitRate, + -- iE-Extensions ProtocolExtensionContainer { {UEAggregate-MaximumBitrates-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UE-S1AP-IDs ::= CHOICE{ + uE-S1AP-ID-pair UE-S1AP-ID-pair, + mME-UE-S1AP-ID MME-UE-S1AP-ID, + ... +} + +UE-S1AP-ID-pair ::= SEQUENCE{ + mME-UE-S1AP-ID MME-UE-S1AP-ID, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID, + -- iE-Extensions ProtocolExtensionContainer { {UE-S1AP-ID-pair-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UE-associatedLogicalS1-ConnectionItem ::= SEQUENCE { + mME-UE-S1AP-ID MME-UE-S1AP-ID OPTIONAL, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { { UE-associatedLogicalS1-ConnectionItemExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UEIdentityIndexValue ::= BIT STRING (SIZE (10)) + +UE-HistoryInformation ::= SEQUENCE (SIZE(1..maxnoofCells)) OF LastVisitedCell-Item + +UEPagingID ::= CHOICE { + s-TMSI S-TMSI, + iMSI IMSI, + ... + } + +UERadioCapability ::= OCTET STRING + +UESecurityCapabilities ::= SEQUENCE { + encryptionAlgorithms EncryptionAlgorithms, + integrityProtectionAlgorithms IntegrityProtectionAlgorithms, + -- iE-Extensions ProtocolExtensionContainer { { UESecurityCapabilities-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, +... +} + +-- V +-- W + +WarningAreaList ::= CHOICE { + cellIDList ECGIList, + trackingAreaListforWarning TAIListforWarning, + emergencyAreaIDList EmergencyAreaIDList, + ... +} + + +WarningType ::= OCTET STRING (SIZE (2)) + +WarningSecurityInfo ::= OCTET STRING (SIZE (50)) + + +WarningMessageContents ::= OCTET STRING (SIZE(1..9600)) + + +-- X + + +X2TNLConfigurationInfo ::= SEQUENCE { + eNBX2TransportLayerAddresses ENBX2TLAs, + -- iE-Extensions ProtocolExtensionContainer { { X2TNLConfigurationInfo-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENBX2ExtTLAs ::= SEQUENCE (SIZE(1.. maxnoofeNBX2ExtTLAs)) OF ENBX2ExtTLA + +ENBX2ExtTLA ::= SEQUENCE { + iPsecTLA TransportLayerAddress OPTIONAL, + gTPTLAa ENBX2GTPTLAs OPTIONAL, + -- iE-Extensions ProtocolExtensionContainer { { ENBX2ExtTLA-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENBX2GTPTLAs ::= SEQUENCE (SIZE(1.. maxnoofeNBX2GTPTLAs)) OF TransportLayerAddress + +-- Y +-- Z + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Contents.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Contents.asn new file mode 100644 index 0000000000..a0e57fe850 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Contents.asn @@ -0,0 +1,2413 @@ + + +-- ************************************************************** +-- +-- PDU definitions for S1AP. +-- +-- ************************************************************** + +S1AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-PDU-Contents (1) } + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + + UEAggregateMaximumBitrate, + Cause, + CellAccessMode, + Cdma2000HORequiredIndication, + Cdma2000HOStatus, + Cdma2000OneXSRVCCInfo, + Cdma2000OneXRAND, + Cdma2000PDU, + Cdma2000RATType, + Cdma2000SectorID, + EUTRANRoundTripDelayEstimationInfo, + CNDomain, + ConcurrentWarningMessageIndicator, + CriticalityDiagnostics, + CSFallbackIndicator, + CSG-Id, + CSG-IdList, + CSGMembershipStatus, + Data-Forwarding-Not-Possible, + Direct-Forwarding-Path-Availability, + Global-ENB-ID, + EUTRAN-CGI, + ENBname, + ENB-StatusTransfer-TransparentContainer, + ENB-UE-S1AP-ID, + ExtendedRepetitionPeriod, + GTP-TEID, + GUMMEI, + HandoverRestrictionList, + HandoverType, + LAI, + LPPa-PDU, + ManagementBasedMDTAllowed, + MMEname, + MMERelaySupportIndicator, + MME-UE-S1AP-ID, + MSClassmark2, + MSClassmark3, + NAS-PDU, + NASSecurityParametersfromE-UTRAN, + NASSecurityParameterstoE-UTRAN, + OverloadResponse, + PagingDRX, + PagingPriority, + PLMNidentity, + RIMTransfer, + RelativeMMECapacity, + RequestType, + E-RAB-ID, + E-RABLevelQoSParameters, + E-RABList, + RelayNode-Indicator, + Routing-ID, + SecurityKey, + SecurityContext, + ServedGUMMEIs, + SONConfigurationTransfer, + Source-ToTarget-TransparentContainer, + SourceBSS-ToTargetBSS-TransparentContainer, + SourceeNB-ToTargeteNB-TransparentContainer, + SourceRNC-ToTargetRNC-TransparentContainer, + SubscriberProfileIDforRFP, + SRVCCOperationPossible, + SRVCCHOIndication, + SupportedTAs, + TAI, + Target-ToSource-TransparentContainer, + TargetBSS-ToSourceBSS-TransparentContainer, + TargeteNB-ToSourceeNB-TransparentContainer, + TargetID, + TargetRNC-ToSourceRNC-TransparentContainer, + TimeToWait, + TraceActivation, + TrafficLoadReductionIndication, + E-UTRAN-Trace-ID, + TransportLayerAddress, + UEIdentityIndexValue, + UEPagingID, + UERadioCapability, + UE-S1AP-IDs, + UE-associatedLogicalS1-ConnectionItem, + UESecurityCapabilities, + S-TMSI, + MessageIdentifier, + SerialNumber, + WarningAreaList, + RepetitionPeriod, + NumberofBroadcastRequest, + WarningType, + WarningSecurityInfo, + DataCodingScheme, + WarningMessageContents, + BroadcastCompletedAreaList, + RRC-Establishment-Cause, + BroadcastCancelledAreaList, + PS-ServiceNotAvailable, + GUMMEIList, + Correlation-ID, + GWContextReleaseIndication, + PrivacyIndicator + + + +FROM S1AP-IEs + + PrivateIE-Container{}, + ProtocolExtensionContainer{}, + ProtocolIE-Container{}, + ProtocolIE-ContainerList{}, + ProtocolIE-ContainerPair{}, + ProtocolIE-ContainerPairList{}, + ProtocolIE-SingleContainer{}, + S1AP-PRIVATE-IES, + S1AP-PROTOCOL-EXTENSION, + S1AP-PROTOCOL-IES, + S1AP-PROTOCOL-IES-PAIR +FROM S1AP-Containers + + + id-uEaggregateMaximumBitrate, + id-Cause, + id-CellAccessMode, + id-cdma2000HORequiredIndication, + id-cdma2000HOStatus, + id-cdma2000OneXSRVCCInfo, + id-cdma2000OneXRAND, + id-cdma2000PDU, + id-cdma2000RATType, + id-cdma2000SectorID, + id-EUTRANRoundTripDelayEstimationInfo, + id-CNDomain, + id-ConcurrentWarningMessageIndicator, + id-CriticalityDiagnostics, + id-CSFallbackIndicator, + id-CSG-Id, + id-CSG-IdList, + id-CSGMembershipStatus, + id-Data-Forwarding-Not-Possible, + id-DefaultPagingDRX, + id-Direct-Forwarding-Path-Availability, + id-Global-ENB-ID, + id-EUTRAN-CGI, + id-eNBname, + id-eNB-StatusTransfer-TransparentContainer, + id-eNB-UE-S1AP-ID, + id-GERANtoLTEHOInformationRes, + id-GUMMEI-ID, + id-HandoverRestrictionList, + id-HandoverType, + id-InitialContextSetup, + id-Inter-SystemInformationTransferTypeEDT, + id-Inter-SystemInformationTransferTypeMDT, + id-LPPa-PDU, + id-NAS-DownlinkCount, + id-ManagementBasedMDTAllowed, + id-MMEname, + id-MME-UE-S1AP-ID, + id-MSClassmark2, + id-MSClassmark3, + id-NAS-PDU, + id-NASSecurityParametersfromE-UTRAN, + id-NASSecurityParameterstoE-UTRAN, + id-OverloadResponse, + id-pagingDRX, + id-PagingPriority, + id-RelativeMMECapacity, + id-RequestType, + id-Routing-ID, + id-E-RABAdmittedItem, + id-E-RABAdmittedList, + id-E-RABDataForwardingItem, + id-E-RABFailedToModifyList, + id-E-RABFailedToReleaseList, + id-E-RABFailedToSetupItemHOReqAck, + id-E-RABFailedToSetupListBearerSURes, + id-E-RABFailedToSetupListCtxtSURes, + id-E-RABFailedToSetupListHOReqAck, + id-E-RABFailedToBeReleasedList, + id-E-RABModify, + id-E-RABModifyItemBearerModRes, + id-E-RABModifyListBearerModRes, + id-E-RABRelease, + id-E-RABReleaseItemBearerRelComp, + id-E-RABReleaseItemHOCmd, + id-E-RABReleaseListBearerRelComp, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-E-RABSetupItemBearerSURes, + id-E-RABSetupItemCtxtSURes, + id-E-RABSetupListBearerSURes, + id-E-RABSetupListCtxtSURes, + id-E-RABSubjecttoDataForwardingList, + id-E-RABToBeModifiedItemBearerModReq, + id-E-RABToBeModifiedListBearerModReq, + id-E-RABToBeReleasedList, + id-E-RABReleasedList, + id-E-RABToBeSetupItemBearerSUReq, + id-E-RABToBeSetupItemCtxtSUReq, + id-E-RABToBeSetupItemHOReq, + id-E-RABToBeSetupListBearerSUReq, + id-E-RABToBeSetupListCtxtSUReq, + id-E-RABToBeSetupListHOReq, + id-E-RABToBeSwitchedDLItem, + id-E-RABToBeSwitchedDLList, + id-E-RABToBeSwitchedULList, + id-E-RABToBeSwitchedULItem, + id-E-RABtoReleaseListHOCmd, + id-SecurityKey, + id-SecurityContext, + id-ServedGUMMEIs, + id-SONConfigurationTransferECT, + id-SONConfigurationTransferMCT, + id-Source-ToTarget-TransparentContainer, + id-Source-ToTarget-TransparentContainer-Secondary, + id-SourceMME-UE-S1AP-ID, + id-SRVCCOperationPossible, + id-SRVCCHOIndication, + id-SubscriberProfileIDforRFP, + id-SupportedTAs, + id-S-TMSI, + id-TAI, + id-TAIItem, + id-TAIList, + id-Target-ToSource-TransparentContainer, + id-Target-ToSource-TransparentContainer-Secondary, + id-TargetID, + id-TimeToWait, + id-TraceActivation, + id-TrafficLoadReductionIndication, + id-E-UTRAN-Trace-ID, + id-UEIdentityIndexValue, + id-UEPagingID, + id-UERadioCapability, + id-UTRANtoLTEHOInformationRes, + id-UE-associatedLogicalS1-ConnectionListResAck, + id-UE-associatedLogicalS1-ConnectionItem, + id-UESecurityCapabilities, + id-UE-S1AP-IDs, + id-ResetType, + id-MessageIdentifier, + id-SerialNumber, + id-WarningAreaList, + id-RepetitionPeriod, + id-NumberofBroadcastRequest, + id-WarningType, + id-WarningSecurityInfo, + id-DataCodingScheme, + id-WarningMessageContents, + id-BroadcastCompletedAreaList, + id-BroadcastCancelledAreaList, + id-RRC-Establishment-Cause, + id-TraceCollectionEntityIPAddress, + maxnoofTAIs, + maxNrOfErrors, + maxNrOfE-RABs, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofEmergencyAreaID, + maxnoofCellID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + id-ExtendedRepetitionPeriod, + id-PS-ServiceNotAvailable, + id-RegisteredLAI, + id-GUMMEIList, + id-SourceMME-GUMMEI, + id-MME-UE-S1AP-ID-2, + id-GW-TransportLayerAddress, + id-RelayNode-Indicator, + id-Correlation-ID, + id-MMERelaySupportIndicator, + id-GWContextReleaseIndication, + id-PrivacyIndicator + + +FROM S1AP-Constants; + +-- ************************************************************** +-- +-- Common Container Lists +-- +-- ************************************************************** + +E-RAB-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } +E-RAB-IE-ContainerPairList { S1AP-PROTOCOL-IES-PAIR : IEsSetParam } ::= ProtocolIE-ContainerPairList { 1, maxNrOfE-RABs, {IEsSetParam} } +ProtocolError-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } + +-- ************************************************************** +-- +-- HANDOVER PREPARATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +Bearers-SubjectToStatusTransfer-ItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-Bearers-SubjectToStatusTransfer-Item CRITICALITY ignore TYPE Bearers-SubjectToStatusTransfer-Item PRESENCE mandatory }, + ... +} + +E-RABInformationItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABInformationListItem CRITICALITY ignore TYPE E-RABInformationListItem PRESENCE mandatory }, + ... +} + +E-RABItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABItem CRITICALITY ignore TYPE E-RABItem PRESENCE mandatory }, + ... +} + +SONInformationReply-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + -- Extension for Release 9 to transfer Time synchronization information -- + {ID id-Time-Synchronization-Info CRITICALITY ignore EXTENSION TimeSynchronizationInfo PRESENCE optional}, + ... +} + +SONConfigurationTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + -- Extension for Release 10 to transfer the IP addresses of the eNB initiating the ANR action -- + {ID id-x2TNLConfigurationInfo CRITICALITY ignore EXTENSION X2TNLConfigurationInfo PRESENCE conditional + -- This IE shall be present if the SON Information IE contains the SON Information Request IE and the SON Information Request IE is set to “X2TNL Configuration Info†-- }, + ... +} + +SourceeNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ServedGUMMEIsItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SupportedTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +S-TMSI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TimeSynchronizationInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TABasedMDT-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CompletedCellinTAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargeteNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargetRNC-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ThresholdEventA2-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TraceActivation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + -- Extension for Rel-10 to support MDT -- + { ID id-MDTConfiguration CRITICALITY ignore EXTENSION MDT-Configuration PRESENCE optional }, + ... +} + +UEAggregate-MaximumBitrates-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UE-S1AP-ID-pair-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UE-associatedLogicalS1-ConnectionItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UESecurityCapabilities-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +X2TNLConfigurationInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + -- Extension for Release 10 to transfer the IPsec and U-plane addresses during ANR action -- + {ID id-eNBX2ExtendedTransportLayerAddresses CRITICALITY ignore EXTENSION ENBX2ExtTLAs PRESENCE optional}, + ... +} + +ENBX2ExtTLA-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +AllocationAndRetentionPriority-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +Bearers-SubjectToStatusTransfer-ItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CancelledCellinEAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CancelledCellinTAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellID-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellBasedMDT-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +Cdma2000OneXSRVCCInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CSG-IdList-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +COUNTvalue-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CompletedCellinEAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-IE-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EmergencyAreaID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EmergencyAreaID-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ENB-StatusTransfer-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABInformationListItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABQoSParameters-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EUTRAN-CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ForbiddenTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ForbiddenLAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GBR-QosInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GERAN-Cell-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GlobalENB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GUMMEI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +HandoverRestrictionList-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ImmediateMDT-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +LAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +LastVisitedEUTRANCellInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +LoggedMDT-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +MDT-Configuration-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +PeriodicReportingMDT-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +RequestType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +RIMTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SecurityContext-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +Bearers-SubjectToStatusTransfer-List ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { Bearers-SubjectToStatusTransfer-ItemIEs } } + +E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { E-RABInformationItemIEs } } + +-- ************************************************************** +-- +-- Handover Required +-- +-- ************************************************************** + +HandoverRequired ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverRequiredIEs} }, + ... +} + +HandoverRequiredIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TargetID CRITICALITY reject TYPE TargetID PRESENCE mandatory }| + { ID id-Direct-Forwarding-Path-Availability CRITICALITY ignore TYPE Direct-Forwarding-Path-Availability PRESENCE optional }| + { ID id-SRVCCHOIndication CRITICALITY reject TYPE SRVCCHOIndication PRESENCE optional }| + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory }| + { ID id-Source-ToTarget-TransparentContainer-Secondary CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE optional }| + { ID id-MSClassmark2 CRITICALITY reject TYPE MSClassmark2 PRESENCE conditional }| + { ID id-MSClassmark3 CRITICALITY ignore TYPE MSClassmark3 PRESENCE conditional }| + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional }| + { ID id-CellAccessMode CRITICALITY reject TYPE CellAccessMode PRESENCE optional }| + { ID id-PS-ServiceNotAvailable CRITICALITY ignore TYPE PS-ServiceNotAvailable PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- Handover Command +-- +-- ************************************************************** + +HandoverCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCommandIEs} }, + ... +} + +HandoverCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-NASSecurityParametersfromE-UTRAN CRITICALITY reject TYPE NASSecurityParametersfromE-UTRAN PRESENCE conditional + -- This IE shall be present if HandoverType IE is set to value "LTEtoUTRAN" or "LTEtoGERAN" -- }| + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-E-RABtoReleaseListHOCmd CRITICALITY ignore TYPE E-RABList PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-Target-ToSource-TransparentContainer-Secondary CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABDataForwardingList ::= E-RAB-IE-ContainerList { {E-RABDataForwardingItemIEs} } + +E-RABDataForwardingItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABDataForwardingItem CRITICALITY ignore TYPE E-RABDataForwardingItem PRESENCE mandatory }, + ... +} + +E-RABDataForwardingItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABItemIEs} } + +-- ************************************************************** +-- +-- Handover Preparation Failure +-- +-- ************************************************************** + +HandoverPreparationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverPreparationFailureIEs} }, + ... +} + +HandoverPreparationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER RESOURCE ALLOCATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Request +-- +-- ************************************************************** + +HandoverRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestIEs} }, + ... +} + +HandoverRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory}| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory}| + { ID id-E-RABToBeSetupListHOReq CRITICALITY reject TYPE E-RABToBeSetupListHOReq PRESENCE mandatory}| + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory}| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional}| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional}| + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE optional}| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional}| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-NASSecurityParameterstoE-UTRAN CRITICALITY reject TYPE NASSecurityParameterstoE-UTRAN PRESENCE conditional + -- This IE shall be present if the Handover Type IE is set to the value "UTRANtoLTE" or "GERANtoLTE" --}| + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional}| + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional}| + { ID id-GUMMEI-ID CRITICALITY ignore TYPE GUMMEI PRESENCE optional}| + { ID id-MME-UE-S1AP-ID-2 CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional}| + { ID id-ManagementBasedMDTAllowed CRITICALITY ignore TYPE ManagementBasedMDTAllowed PRESENCE optional}, + ... +} + +E-RABToBeSetupListHOReq ::= E-RAB-IE-ContainerList { {E-RABToBeSetupItemHOReqIEs} } + +E-RABToBeSetupItemHOReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemHOReq CRITICALITY reject TYPE E-RABToBeSetupItemHOReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemHOReq-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + {ID id-Data-Forwarding-Not-Possible CRITICALITY ignore EXTENSION Data-Forwarding-Not-Possible PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- Handover Request Acknowledge +-- +-- ************************************************************** + +HandoverRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestAcknowledgeIEs} }, + ... +} + +HandoverRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABAdmittedList CRITICALITY ignore TYPE E-RABAdmittedList PRESENCE mandatory } | + { ID id-E-RABFailedToSetupListHOReqAck CRITICALITY ignore TYPE E-RABFailedToSetupListHOReqAck PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-CSG-Id CRITICALITY ignore TYPE CSG-Id PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABAdmittedList ::= E-RAB-IE-ContainerList { {E-RABAdmittedItemIEs} } + +E-RABAdmittedItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABAdmittedItem CRITICALITY ignore TYPE E-RABAdmittedItem PRESENCE mandatory }, + ... +} + +E-RABAdmittedItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABFailedToSetupListHOReqAck ::= E-RAB-IE-ContainerList { {E-RABFailedToSetupItemHOReqAckIEs} } + +E-RABFailedToSetupItemHOReqAckIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABFailedToSetupItemHOReqAck CRITICALITY ignore TYPE E-RABFailedToSetupItemHOReqAck PRESENCE mandatory }, + ... +} + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + iE-Extensions ProtocolExtensionContainer { { E-RABFailedToSetupItemHOReqAckExtIEs} } OPTIONAL, + ... +} + +E-RABFailedToSetupItemHOReqAckExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Handover Failure +-- +-- ************************************************************** + +HandoverFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverFailureIEs} }, + ... +} + +HandoverFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER NOTIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Notify +-- +-- ************************************************************** + +HandoverNotify ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverNotifyIEs} }, + ... +} + +HandoverNotifyIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- PATH SWITCH REQUEST ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Path Switch Request +-- +-- ************************************************************** + +PathSwitchRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestIEs} }, + ... +} + +PathSwitchRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-E-RABToBeSwitchedDLList CRITICALITY reject TYPE E-RABToBeSwitchedDLList PRESENCE mandatory}| + { ID id-SourceMME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY ignore TYPE UESecurityCapabilities PRESENCE mandatory}| + { ID id-CSG-Id CRITICALITY ignore TYPE CSG-Id PRESENCE optional}| + { ID id-CellAccessMode CRITICALITY ignore TYPE CellAccessMode PRESENCE optional}| + { ID id-SourceMME-GUMMEI CRITICALITY ignore TYPE GUMMEI PRESENCE optional}, + ... +} + +E-RABToBeSwitchedDLList ::= E-RAB-IE-ContainerList { {E-RABToBeSwitchedDLItemIEs} } + +E-RABToBeSwitchedDLItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedDLItem CRITICALITY reject TYPE E-RABToBeSwitchedDLItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedDLItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- Path Switch Request Acknowledge +-- +-- ************************************************************** + +PathSwitchRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestAcknowledgeIEs} }, + ... +} + +PathSwitchRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional}| + { ID id-E-RABToBeSwitchedULList CRITICALITY ignore TYPE E-RABToBeSwitchedULList PRESENCE optional}| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE optional}| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}| + { ID id-MME-UE-S1AP-ID-2 CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional}, + ... +} + +E-RABToBeSwitchedULList ::= E-RAB-IE-ContainerList { {E-RABToBeSwitchedULItemIEs} } + +E-RABToBeSwitchedULItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedULItem CRITICALITY ignore TYPE E-RABToBeSwitchedULItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedULItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Path Switch Request Failure +-- +-- ************************************************************** + +PathSwitchRequestFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestFailureIEs} }, + ... +} + +PathSwitchRequestFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER CANCEL ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Cancel +-- +-- ************************************************************** + +HandoverCancel ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelIEs} }, + ... +} + +HandoverCancelIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Handover Cancel Request Acknowledge +-- +-- ************************************************************** + +HandoverCancelAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelAcknowledgeIEs} }, + ... +} + +HandoverCancelAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- E-RAB SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Setup Request +-- +-- ************************************************************** + +E-RABSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupRequestIEs} }, + ... +} + +E-RABSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeSetupListBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupListBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemBearerSUReqIEs} } + +E-RABToBeSetupItemBearerSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupItemBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemBearerSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + { ID id-Correlation-ID CRITICALITY ignore EXTENSION Correlation-ID PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- E-RAB Setup Response +-- +-- ************************************************************** + +E-RABSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupResponseIEs} }, + ... +} + +E-RABSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListBearerSURes CRITICALITY ignore TYPE E-RABSetupListBearerSURes PRESENCE optional }| + { ID id-E-RABFailedToSetupListBearerSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemBearerSUResIEs} } + +E-RABSetupItemBearerSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemBearerSURes CRITICALITY ignore TYPE E-RABSetupItemBearerSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemBearerSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB MODIFY ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Modify Request +-- +-- ************************************************************** + +E-RABModifyRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyRequestIEs} }, + ... +} + +E-RABModifyRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeModifiedListBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedListBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeModifiedItemBearerModReqIEs} } + +E-RABToBeModifiedItemBearerModReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeModifiedItemBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedItemBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifyItemBearerModReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB Modify Response +-- +-- ************************************************************** + +E-RABModifyResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyResponseIEs} }, + ... +} + +E-RABModifyResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABModifyListBearerModRes CRITICALITY ignore TYPE E-RABModifyListBearerModRes PRESENCE optional }| + { ID id-E-RABFailedToModifyList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABModifyItemBearerModResIEs} } + +E-RABModifyItemBearerModResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABModifyItemBearerModRes CRITICALITY ignore TYPE E-RABModifyItemBearerModRes PRESENCE mandatory }, + ... +} + +E-RABModifyItemBearerModResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- E-RAB RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Command +-- +-- ************************************************************** + +E-RABReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseCommandIEs} }, + ... +} + +E-RABReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }| + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- E-RAB Release Response +-- +-- ************************************************************** + +E-RABReleaseResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { E-RABReleaseResponseIEs } }, + ... +} + +E-RABReleaseResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleaseListBearerRelComp CRITICALITY ignore TYPE E-RABReleaseListBearerRelComp PRESENCE optional }| + { ID id-E-RABFailedToReleaseList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABReleaseItemBearerRelCompIEs} } + +E-RABReleaseItemBearerRelCompIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABReleaseItemBearerRelComp CRITICALITY ignore TYPE E-RABReleaseItemBearerRelComp PRESENCE mandatory }, + ... +} + +E-RABReleaseItemBearerRelCompExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- E-RAB RELEASE INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Indication +-- +-- ************************************************************** + +E-RABReleaseIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseIndicationIEs} }, + ... +} + +E-RABReleaseIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }, + ... +} +-- ************************************************************** +-- +-- INITIAL CONTEXT SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Initial Context Setup Request +-- +-- ************************************************************** + +InitialContextSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupRequestIEs} }, + ... +} + +InitialContextSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory}| + { ID id-E-RABToBeSetupListCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupListCtxtSUReq PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory}| + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE mandatory}| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional}| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional}| + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE optional}| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional}| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional}| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional}| + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional}| + { ID id-RegisteredLAI CRITICALITY ignore TYPE LAI PRESENCE optional}| + { ID id-GUMMEI-ID CRITICALITY ignore TYPE GUMMEI PRESENCE optional}| + { ID id-MME-UE-S1AP-ID-2 CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional}| + { ID id-ManagementBasedMDTAllowed CRITICALITY ignore TYPE ManagementBasedMDTAllowed PRESENCE optional}, + ... +} + +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemCtxtSUReqIEs} } + +E-RABToBeSetupItemCtxtSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupItemCtxtSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemCtxtSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + { ID id-Correlation-ID CRITICALITY ignore EXTENSION Correlation-ID PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- Initial Context Setup Response +-- +-- ************************************************************** + +InitialContextSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupResponseIEs} }, + ... +} + +InitialContextSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListCtxtSURes CRITICALITY ignore TYPE E-RABSetupListCtxtSURes PRESENCE mandatory }| + { ID id-E-RABFailedToSetupListCtxtSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemCtxtSUResIEs} } + +E-RABSetupItemCtxtSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemCtxtSURes CRITICALITY ignore TYPE E-RABSetupItemCtxtSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemCtxtSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- Initial Context Setup Failure +-- +-- ************************************************************** + +InitialContextSetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupFailureIEs} }, + ... +} + +InitialContextSetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- PAGING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + + +-- ************************************************************** +-- +-- Paging +-- +-- ************************************************************** + +Paging ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{PagingIEs}}, + ... +} + +PagingIEs S1AP-PROTOCOL-IES ::= { + { ID id-UEIdentityIndexValue CRITICALITY ignore TYPE UEIdentityIndexValue PRESENCE mandatory}| + { ID id-UEPagingID CRITICALITY ignore TYPE UEPagingID PRESENCE mandatory}| + { ID id-pagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional}| + { ID id-CNDomain CRITICALITY ignore TYPE CNDomain PRESENCE mandatory}| + { ID id-TAIList CRITICALITY ignore TYPE TAIList PRESENCE mandatory}| + { ID id-CSG-IdList CRITICALITY ignore TYPE CSG-IdList PRESENCE optional}| + { ID id-PagingPriority CRITICALITY ignore TYPE PagingPriority PRESENCE optional}, + ... +} + +TAIList::= SEQUENCE (SIZE(1.. maxnoofTAIs)) OF ProtocolIE-SingleContainer {{TAIItemIEs}} + +TAIItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-TAIItem CRITICALITY ignore TYPE TAIItem PRESENCE mandatory }, + ... +} + +TAIItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE REQUEST +-- +-- ************************************************************** + +UEContextReleaseRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseRequest-IEs}}, + ... +} + +UEContextReleaseRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}| + { ID id-GWContextReleaseIndication CRITICALITY reject TYPE GWContextReleaseIndication PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- UE Context Release Command +-- +-- ************************************************************** + +UEContextReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseCommand-IEs}}, + ... +} + +UEContextReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-S1AP-IDs CRITICALITY reject TYPE UE-S1AP-IDs PRESENCE mandatory} | + + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UE Context Release Complete +-- +-- ************************************************************** + +UEContextReleaseComplete ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseComplete-IEs}}, + ... +} + +UEContextReleaseCompleteIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- UE CONTEXT MODIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Context Modification Request +-- +-- ************************************************************** + +UEContextModificationRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationRequestIEs} }, + ... +} + +UEContextModificationRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE optional}| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional}| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional}| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional}| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE optional}| + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional}| + { ID id-RegisteredLAI CRITICALITY ignore TYPE LAI PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- UE Context Modification Response +-- +-- ************************************************************** + +UEContextModificationResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationResponseIEs} }, + ... +} + +UEContextModificationResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +}-- ************************************************************** +-- +-- UE Context Modification Failure +-- +-- ************************************************************** + +UEContextModificationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationFailureIEs} }, + ... +} + +UEContextModificationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- NAS TRANSPORT ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DOWNLINK NAS TRANSPORT +-- +-- ************************************************************** + +DownlinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkNASTransport-IEs}}, + ... +} + +DownlinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional} | + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- INITIAL UE MESSAGE +-- +-- ************************************************************** + +InitialUEMessage ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{InitialUEMessage-IEs}}, + ... +} + +InitialUEMessageIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-TAI CRITICALITY reject TYPE TAI PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-RRC-Establishment-Cause CRITICALITY ignore TYPE RRC-Establishment-Cause PRESENCE mandatory} | + { ID id-S-TMSI CRITICALITY reject TYPE S-TMSI PRESENCE optional} | + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional} | + { ID id-GUMMEI-ID CRITICALITY reject TYPE GUMMEI PRESENCE optional} | + { ID id-CellAccessMode CRITICALITY reject TYPE CellAccessMode PRESENCE optional} | + { ID id-GW-TransportLayerAddress CRITICALITY ignore TYPE TransportLayerAddress PRESENCE optional} | + { ID id-RelayNode-Indicator CRITICALITY reject TYPE RelayNode-Indicator PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- UPLINK NAS TRANSPORT +-- +-- ************************************************************** + +UplinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkNASTransport-IEs}}, + ... +} + +UplinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory} | + { ID id-GW-TransportLayerAddress CRITICALITY ignore TYPE TransportLayerAddress PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- NAS NON DELIVERY INDICATION +-- +-- ************************************************************** + +NASNonDeliveryIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{NASNonDeliveryIndication-IEs}}, + ... +} + +NASNonDeliveryIndication-IEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- RESET ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Reset +-- +-- ************************************************************** + +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetIEs} }, + ... +} + +ResetIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory }, + ... +} + +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemRes } } + +UE-associatedLogicalS1-ConnectionItemRes S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY reject TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- Reset Acknowledge +-- +-- ************************************************************** + +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetAcknowledgeIEs} }, + ... +} + +ResetAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionListResAck CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionListResAck PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemResAck } } + +UE-associatedLogicalS1-ConnectionItemResAck S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- ERROR INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Error Indication +-- +-- ************************************************************** + +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndicationIEs}}, + ... +} + +ErrorIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE optional } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + +-- ************************************************************** +-- +-- S1 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- S1 Setup Request +-- +-- ************************************************************** + +S1SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupRequestIEs} }, + ... +} + +S1SetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-Global-ENB-ID CRITICALITY reject TYPE Global-ENB-ID PRESENCE mandatory}| + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional}| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE mandatory}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE mandatory}| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Response +-- +-- ************************************************************** + +S1SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupResponseIEs} }, + ... +} + + +S1SetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional}| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE mandatory}| + { ID id-RelativeMMECapacity CRITICALITY ignore TYPE RelativeMMECapacity PRESENCE mandatory}| + { ID id-MMERelaySupportIndicator CRITICALITY ignore TYPE MMERelaySupportIndicator PRESENCE optional}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Failure +-- +-- ************************************************************** + +S1SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupFailureIEs} }, + ... +} + +S1SetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Update +-- +-- ************************************************************** + +ENBConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateIEs} }, + ... +} + +ENBConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional }| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE optional }| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Acknowledge +-- +-- ************************************************************** + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +ENBConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Failure +-- +-- ************************************************************** + +ENBConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateFailureIEs} }, + ... +} + +ENBConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, +... +} + + +-- ************************************************************** +-- +-- MME Configuration UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Update +-- +-- ************************************************************** + +MMEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateIEs} }, + ... +} + +MMEConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional }| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE optional }| + { ID id-RelativeMMECapacity CRITICALITY reject TYPE RelativeMMECapacity PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Acknowledge +-- +-- ************************************************************** + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +MMEConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Failure +-- +-- ************************************************************** + +MMEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateFailureIEs} }, + ... +} + +MMEConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- DOWNLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Downlink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {DownlinkS1cdma2000tunnelingIEs} }, + ... +} + +DownlinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-cdma2000HOStatus CRITICALITY ignore TYPE Cdma2000HOStatus PRESENCE optional } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- UPLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Uplink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +UplinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {UplinkS1cdma2000tunnelingIEs} }, + ... +} + +UplinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000SectorID CRITICALITY reject TYPE Cdma2000SectorID PRESENCE mandatory } | + { ID id-cdma2000HORequiredIndication CRITICALITY ignore TYPE Cdma2000HORequiredIndication PRESENCE optional } | + { ID id-cdma2000OneXSRVCCInfo CRITICALITY reject TYPE Cdma2000OneXSRVCCInfo PRESENCE optional } | + { ID id-cdma2000OneXRAND CRITICALITY reject TYPE Cdma2000OneXRAND PRESENCE optional } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }| + { ID id-EUTRANRoundTripDelayEstimationInfo CRITICALITY ignore TYPE EUTRANRoundTripDelayEstimationInfo PRESENCE optional}, + -- Extension for Release 9 to assist target HRPD access with the acquisition of the UE -- + ... +} + + +-- ************************************************************** +-- +-- UE CAPABILITY INFO INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Capability Info Indication +-- +-- ************************************************************** + +UECapabilityInfoIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UECapabilityInfoIndicationIEs} }, + ... +} + +UECapabilityInfoIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- eNB STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Status Transfer +-- +-- ************************************************************** + +ENBStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBStatusTransferIEs} }, + ... +} + +ENBStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- MME STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Status Transfer +-- +-- ************************************************************** + +MMEStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEStatusTransferIEs} }, + ... +} + +MMEStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- TRACE ELEMENTARY PROCEDURES +-- +-- ************************************************************** +-- ************************************************************** +-- +-- Trace Start +-- +-- ************************************************************** + +TraceStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceStartIEs} }, + ... +} + +TraceStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Trace Failure Indication +-- +-- ************************************************************** + +TraceFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceFailureIndicationIEs} }, + ... +} + +TraceFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- DEACTIVATE TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DEACTIVATE TRACE +-- +-- ************************************************************** + +DeactivateTrace ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { DeactivateTraceIEs} }, + ... +} + +DeactivateTraceIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE +-- +-- ************************************************************** + +CellTrafficTrace ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { CellTrafficTraceIEs } }, + ... +} + +CellTrafficTraceIEs S1AP-PROTOCOL-IES ::= { + {ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + {ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + {ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory}| + {ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + {ID id-TraceCollectionEntityIPAddress CRITICALITY ignore TYPE TransportLayerAddress PRESENCE mandatory}| + {ID id-PrivacyIndicator CRITICALITY ignore TYPE PrivacyIndicator PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- LOCATION ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Location Reporting Control +-- +-- ************************************************************** + +LocationReportingControl ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingControlIEs} }, + ... +} + +LocationReportingControlIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- Location Report Failure Indication +-- +-- ************************************************************** + +LocationReportingFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingFailureIndicationIEs} }, + ... +} + +LocationReportingFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- Location Report +-- +-- ************************************************************** + +LocationReport ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportIEs} }, + ... +} + +LocationReportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- OVERLOAD ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Overload Start +-- +-- ************************************************************** + +OverloadStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStartIEs} }, + ... +} + +OverloadStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-OverloadResponse CRITICALITY reject TYPE OverloadResponse PRESENCE mandatory}| + { ID id-GUMMEIList CRITICALITY ignore TYPE GUMMEIList PRESENCE optional}| + { ID id-TrafficLoadReductionIndication CRITICALITY ignore TYPE TrafficLoadReductionIndication PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- Overload Stop +-- +-- ************************************************************** + +OverloadStop ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStopIEs} }, + ... +} + +OverloadStopIEs S1AP-PROTOCOL-IES ::= { +{ ID id-GUMMEIList CRITICALITY ignore TYPE GUMMEIList PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- WRITE-REPLACE WARNING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Write-Replace Warning Request +-- +-- ************************************************************** + + +WriteReplaceWarningRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningRequestIEs} }, + ... +} + +WriteReplaceWarningRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-WarningAreaList CRITICALITY ignore TYPE WarningAreaList PRESENCE optional }| + { ID id-RepetitionPeriod CRITICALITY reject TYPE RepetitionPeriod PRESENCE mandatory }| + { ID id-ExtendedRepetitionPeriod CRITICALITY reject TYPE ExtendedRepetitionPeriod PRESENCE optional }| + { ID id-NumberofBroadcastRequest CRITICALITY reject TYPE NumberofBroadcastRequest PRESENCE mandatory }| + { ID id-WarningType CRITICALITY ignore TYPE WarningType PRESENCE optional }| + { ID id-WarningSecurityInfo CRITICALITY ignore TYPE WarningSecurityInfo PRESENCE optional }| + { ID id-DataCodingScheme CRITICALITY ignore TYPE DataCodingScheme PRESENCE optional }| + { ID id-WarningMessageContents CRITICALITY ignore TYPE WarningMessageContents PRESENCE optional }| + { ID id-ConcurrentWarningMessageIndicator CRITICALITY reject TYPE ConcurrentWarningMessageIndicator PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- Write-Replace Warning Response +-- +-- ************************************************************** + +WriteReplaceWarningResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningResponseIEs} }, + ... +} + +WriteReplaceWarningResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-BroadcastCompletedAreaList CRITICALITY ignore TYPE BroadcastCompletedAreaList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Direct Information Transfer +-- +-- ************************************************************** + +ENBDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBDirectInformationTransferIEs}}, + ... +} + +ENBDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeEDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- MME DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Direct Information Transfer +-- +-- ************************************************************** + +MMEDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEDirectInformationTransferIEs}}, + ... +} + +MMEDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeMDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} +-- ************************************************************** +-- +-- eNB CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Transfer +-- +-- ************************************************************** + +ENBConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBConfigurationTransferIEs}}, + ... +} + +ENBConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferECT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- MME CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Transfer +-- +-- ************************************************************** + +MMEConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEConfigurationTransferIEs}}, + ... +} + +MMEConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferMCT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- PRIVATE MESSAGE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Private Message +-- +-- ************************************************************** + +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessageIEs}}, + ... +} + +PrivateMessageIEs S1AP-PRIVATE-IES ::= { + ... +} + +-- ************************************************************** +-- +-- Kill Request +-- +-- ************************************************************** + + +KillRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {KillRequestIEs} }, + ... +} + +KillRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-WarningAreaList CRITICALITY ignore TYPE WarningAreaList PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- Kill Response +-- +-- ************************************************************** + +KillResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {KillResponseIEs} }, + ... +} + +KillResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-BroadcastCancelledAreaList CRITICALITY ignore TYPE BroadcastCancelledAreaList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- LPPA TRANSPORT ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DOWNLINK UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +DownlinkUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkUEAssociatedLPPaTransport-IEs}}, + ... +} + +DownlinkUEAssociatedLPPaTransport-IEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory } | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- UPLINK UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +UplinkUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkUEAssociatedLPPaTransport-IEs}}, + ... +} + +UplinkUEAssociatedLPPaTransport-IEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- DOWNLINK NON UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +DownlinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkNonUEAssociatedLPPaTransport-IEs}}, + ... +} + +DownlinkNonUEAssociatedLPPaTransport-IEs S1AP-PROTOCOL-IES ::= { + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UPLINK NON UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +UplinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkNonUEAssociatedLPPaTransport-IEs}}, + ... +} + +UplinkNonUEAssociatedLPPaTransport-IEs S1AP-PROTOCOL-IES ::= { + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Descriptions.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Descriptions.asn new file mode 100644 index 0000000000..983a1950c1 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU-Descriptions.asn @@ -0,0 +1,591 @@ +-- ************************************************************** +-- +-- Elementary Procedure definitions +-- +-- ************************************************************** + +S1AP-PDU-Descriptions { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-PDU-Descriptions (0)} + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + ProcedureCode +FROM S1AP-CommonDataTypes + + CellTrafficTrace, + DeactivateTrace, + DownlinkUEAssociatedLPPaTransport, + DownlinkNASTransport, + DownlinkNonUEAssociatedLPPaTransport, + DownlinkS1cdma2000tunneling, + ENBDirectInformationTransfer, + ENBStatusTransfer, + ENBConfigurationUpdate, + ENBConfigurationUpdateAcknowledge, + ENBConfigurationUpdateFailure, + ErrorIndication, + HandoverCancel, + HandoverCancelAcknowledge, + HandoverCommand, + HandoverFailure, + HandoverNotify, + HandoverPreparationFailure, + HandoverRequest, + HandoverRequestAcknowledge, + HandoverRequired, + InitialContextSetupFailure, + InitialContextSetupRequest, + InitialContextSetupResponse, + InitialUEMessage, + KillRequest, + KillResponse, + LocationReportingControl, + LocationReportingFailureIndication, + LocationReport, + MMEConfigurationUpdate, + MMEConfigurationUpdateAcknowledge, + MMEConfigurationUpdateFailure, + MMEDirectInformationTransfer, + MMEStatusTransfer, + NASNonDeliveryIndication, + OverloadStart, + OverloadStop, + Paging, + PathSwitchRequest, + PathSwitchRequestAcknowledge, + PathSwitchRequestFailure, + PrivateMessage, + Reset, + ResetAcknowledge, + S1SetupFailure, + S1SetupRequest, + S1SetupResponse, + E-RABModifyRequest, + E-RABModifyResponse, + E-RABReleaseCommand, + E-RABReleaseResponse, + E-RABReleaseIndication, + E-RABSetupRequest, + E-RABSetupResponse, + TraceFailureIndication, + TraceStart, + UECapabilityInfoIndication, + UEContextModificationFailure, + UEContextModificationRequest, + UEContextModificationResponse, + UEContextReleaseCommand, + UEContextReleaseComplete, + UEContextReleaseRequest, + UplinkUEAssociatedLPPaTransport, + UplinkNASTransport, + UplinkNonUEAssociatedLPPaTransport, + UplinkS1cdma2000tunneling, + WriteReplaceWarningRequest, + WriteReplaceWarningResponse, + ENBConfigurationTransfer, + MMEConfigurationTransfer + + +FROM S1AP-PDU-Contents + + id-CellTrafficTrace, + id-DeactivateTrace, + id-downlinkUEAssociatedLPPaTransport, + id-downlinkNASTransport, + id-downlinkNonUEAssociatedLPPaTransport, + id-DownlinkS1cdma2000tunneling, + id-eNBStatusTransfer, + id-ErrorIndication, + id-HandoverCancel, + id-HandoverNotification, + id-HandoverPreparation, + id-HandoverResourceAllocation, + id-InitialContextSetup, + id-initialUEMessage, + id-ENBConfigurationUpdate, + id-Kill, + id-LocationReportingControl, + id-LocationReportingFailureIndication, + id-LocationReport, + id-eNBDirectInformationTransfer, + id-MMEConfigurationUpdate, + id-MMEDirectInformationTransfer, + id-MMEStatusTransfer, + id-NASNonDeliveryIndication, + id-OverloadStart, + id-OverloadStop, + id-Paging, + id-PathSwitchRequest, + id-PrivateMessage, + id-Reset, + id-S1Setup, + id-E-RABModify, + id-E-RABRelease, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-TraceFailureIndication, + id-TraceStart, + id-UECapabilityInfoIndication, + id-UEContextModification, + id-UEContextRelease, + id-UEContextReleaseRequest, + id-uplinkUEAssociatedLPPaTransport, + id-uplinkNASTransport, + id-uplinkNonUEAssociatedLPPaTransport, + id-UplinkS1cdma2000tunneling, + id-WriteReplaceWarning, + id-eNBConfigurationTransfer, + id-MMEConfigurationTransfer +FROM S1AP-Constants; + + +-- ************************************************************** +-- +-- Interface Elementary Procedure Class +-- +-- ************************************************************** + +S1AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} + +-- ************************************************************** +-- +-- Interface PDU Definition +-- +-- ************************************************************** + +S1AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +-- ************************************************************** +-- +-- Interface Elementary Procedure List +-- +-- ************************************************************** + +S1AP-ELEMENTARY-PROCEDURES S1AP-ELEMENTARY-PROCEDURE ::= { + S1AP-ELEMENTARY-PROCEDURES-CLASS-1 | + S1AP-ELEMENTARY-PROCEDURES-CLASS-2, + ... +} + + +S1AP-ELEMENTARY-PROCEDURES-CLASS-1 S1AP-ELEMENTARY-PROCEDURE ::= { + handoverPreparation | + handoverResourceAllocation | + pathSwitchRequest | + e-RABSetup | + e-RABModify | + e-RABRelease | + initialContextSetup | + handoverCancel | + kill | + reset | + s1Setup | + uEContextModification | + uEContextRelease | + eNBConfigurationUpdate | + mMEConfigurationUpdate | + writeReplaceWarning , + ... +} + +S1AP-ELEMENTARY-PROCEDURES-CLASS-2 S1AP-ELEMENTARY-PROCEDURE ::= { + handoverNotification | + e-RABReleaseIndication | + paging | + downlinkNASTransport | + initialUEMessage | + uplinkNASTransport | + errorIndication | + nASNonDeliveryIndication | + uEContextReleaseRequest | + downlinkS1cdma2000tunneling | + uplinkS1cdma2000tunneling | + uECapabilityInfoIndication | + eNBStatusTransfer | + mMEStatusTransfer | + deactivateTrace | + traceStart | + traceFailureIndication | + cellTrafficTrace | + locationReportingControl | + locationReportingFailureIndication | + locationReport | + overloadStart | + overloadStop | + eNBDirectInformationTransfer | + mMEDirectInformationTransfer | + eNBConfigurationTransfer | + mMEConfigurationTransfer | + privateMessage , + ..., + downlinkUEAssociatedLPPaTransport | + uplinkUEAssociatedLPPaTransport | + downlinkNonUEAssociatedLPPaTransport | + uplinkNonUEAssociatedLPPaTransport +} + +-- ************************************************************** +-- +-- Interface Elementary Procedures +-- +-- ************************************************************** + +handoverPreparation S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverRequired + SUCCESSFUL OUTCOME HandoverCommand + UNSUCCESSFUL OUTCOME HandoverPreparationFailure + PROCEDURE CODE id-HandoverPreparation + CRITICALITY reject +} + +handoverResourceAllocation S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverRequest + SUCCESSFUL OUTCOME HandoverRequestAcknowledge + UNSUCCESSFUL OUTCOME HandoverFailure + PROCEDURE CODE id-HandoverResourceAllocation + CRITICALITY reject +} + +handoverNotification S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverNotify + PROCEDURE CODE id-HandoverNotification + CRITICALITY ignore +} + +pathSwitchRequest S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PathSwitchRequest + SUCCESSFUL OUTCOME PathSwitchRequestAcknowledge + UNSUCCESSFUL OUTCOME PathSwitchRequestFailure + PROCEDURE CODE id-PathSwitchRequest + CRITICALITY reject +} + +e-RABSetup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABSetupRequest + SUCCESSFUL OUTCOME E-RABSetupResponse + PROCEDURE CODE id-E-RABSetup + CRITICALITY reject +} + +e-RABModify S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABModifyRequest + SUCCESSFUL OUTCOME E-RABModifyResponse + PROCEDURE CODE id-E-RABModify + CRITICALITY reject +} + +e-RABRelease S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABReleaseCommand + SUCCESSFUL OUTCOME E-RABReleaseResponse + PROCEDURE CODE id-E-RABRelease + CRITICALITY reject +} + +e-RABReleaseIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABReleaseIndication + PROCEDURE CODE id-E-RABReleaseIndication + CRITICALITY ignore +} + +initialContextSetup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE InitialContextSetupRequest + SUCCESSFUL OUTCOME InitialContextSetupResponse + UNSUCCESSFUL OUTCOME InitialContextSetupFailure + PROCEDURE CODE id-InitialContextSetup + CRITICALITY reject +} + +uEContextReleaseRequest S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextReleaseRequest + PROCEDURE CODE id-UEContextReleaseRequest + CRITICALITY ignore +} + +paging S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Paging + PROCEDURE CODE id-Paging + CRITICALITY ignore +} + +downlinkNASTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkNASTransport + PROCEDURE CODE id-downlinkNASTransport + CRITICALITY ignore +} + +initialUEMessage S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE InitialUEMessage + PROCEDURE CODE id-initialUEMessage + CRITICALITY ignore +} + +uplinkNASTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkNASTransport + PROCEDURE CODE id-uplinkNASTransport + CRITICALITY ignore +} +nASNonDeliveryIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE NASNonDeliveryIndication + PROCEDURE CODE id-NASNonDeliveryIndication + CRITICALITY ignore +} + +handoverCancel S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverCancel + SUCCESSFUL OUTCOME HandoverCancelAcknowledge + PROCEDURE CODE id-HandoverCancel + CRITICALITY reject +} + +reset S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Reset + SUCCESSFUL OUTCOME ResetAcknowledge + PROCEDURE CODE id-Reset + CRITICALITY reject +} + +errorIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ErrorIndication + PROCEDURE CODE id-ErrorIndication + CRITICALITY ignore +} + +s1Setup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE S1SetupRequest + SUCCESSFUL OUTCOME S1SetupResponse + UNSUCCESSFUL OUTCOME S1SetupFailure + PROCEDURE CODE id-S1Setup + CRITICALITY reject +} + +eNBConfigurationUpdate S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBConfigurationUpdate + SUCCESSFUL OUTCOME ENBConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME ENBConfigurationUpdateFailure + PROCEDURE CODE id-ENBConfigurationUpdate + CRITICALITY reject +} + +mMEConfigurationUpdate S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEConfigurationUpdate + SUCCESSFUL OUTCOME MMEConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME MMEConfigurationUpdateFailure + PROCEDURE CODE id-MMEConfigurationUpdate + CRITICALITY reject +} + +downlinkS1cdma2000tunneling S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkS1cdma2000tunneling + PROCEDURE CODE id-DownlinkS1cdma2000tunneling + CRITICALITY ignore +} + +uplinkS1cdma2000tunneling S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkS1cdma2000tunneling + PROCEDURE CODE id-UplinkS1cdma2000tunneling + CRITICALITY ignore +} + +uEContextModification S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextModificationRequest + SUCCESSFUL OUTCOME UEContextModificationResponse + UNSUCCESSFUL OUTCOME UEContextModificationFailure + + PROCEDURE CODE id-UEContextModification + CRITICALITY reject +} + +uECapabilityInfoIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UECapabilityInfoIndication + PROCEDURE CODE id-UECapabilityInfoIndication + CRITICALITY ignore +} + +uEContextRelease S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextReleaseCommand + SUCCESSFUL OUTCOME UEContextReleaseComplete + PROCEDURE CODE id-UEContextRelease + CRITICALITY reject +} + +eNBStatusTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBStatusTransfer + PROCEDURE CODE id-eNBStatusTransfer + CRITICALITY ignore +} + +mMEStatusTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEStatusTransfer + PROCEDURE CODE id-MMEStatusTransfer + CRITICALITY ignore +} + +deactivateTrace S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DeactivateTrace + PROCEDURE CODE id-DeactivateTrace + CRITICALITY ignore +} + +traceStart S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE TraceStart + PROCEDURE CODE id-TraceStart + CRITICALITY ignore +} + +traceFailureIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE TraceFailureIndication + PROCEDURE CODE id-TraceFailureIndication + CRITICALITY ignore +} +cellTrafficTrace S1AP-ELEMENTARY-PROCEDURE ::={ +INITIATING MESSAGE CellTrafficTrace +PROCEDURE CODE id-CellTrafficTrace +CRITICALITY ignore +} + +locationReportingControl S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReportingControl + PROCEDURE CODE id-LocationReportingControl + CRITICALITY ignore +} + +locationReportingFailureIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReportingFailureIndication + PROCEDURE CODE id-LocationReportingFailureIndication + CRITICALITY ignore +} + +locationReport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReport + PROCEDURE CODE id-LocationReport + CRITICALITY ignore +} + +overloadStart S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE OverloadStart + PROCEDURE CODE id-OverloadStart + CRITICALITY ignore +} + +overloadStop S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE OverloadStop + PROCEDURE CODE id-OverloadStop + CRITICALITY reject +} + +writeReplaceWarning S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE WriteReplaceWarningRequest + SUCCESSFUL OUTCOME WriteReplaceWarningResponse + PROCEDURE CODE id-WriteReplaceWarning + CRITICALITY reject +} + +eNBDirectInformationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBDirectInformationTransfer + PROCEDURE CODE id-eNBDirectInformationTransfer + CRITICALITY ignore +} + +mMEDirectInformationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEDirectInformationTransfer + PROCEDURE CODE id-MMEDirectInformationTransfer + CRITICALITY ignore +} + +eNBConfigurationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBConfigurationTransfer + PROCEDURE CODE id-eNBConfigurationTransfer + CRITICALITY ignore +} + +mMEConfigurationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEConfigurationTransfer + PROCEDURE CODE id-MMEConfigurationTransfer + CRITICALITY ignore +} + + +privateMessage S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PrivateMessage + PROCEDURE CODE id-PrivateMessage + CRITICALITY ignore +} + +kill S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE KillRequest + SUCCESSFUL OUTCOME KillResponse + PROCEDURE CODE id-Kill + CRITICALITY reject +} + +downlinkUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkUEAssociatedLPPaTransport + PROCEDURE CODE id-downlinkUEAssociatedLPPaTransport + CRITICALITY ignore +} + +uplinkUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkUEAssociatedLPPaTransport + PROCEDURE CODE id-uplinkUEAssociatedLPPaTransport + CRITICALITY ignore +} +downlinkNonUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkNonUEAssociatedLPPaTransport + PROCEDURE CODE id-downlinkNonUEAssociatedLPPaTransport + CRITICALITY ignore +} + +uplinkNonUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkNonUEAssociatedLPPaTransport + PROCEDURE CODE id-uplinkNonUEAssociatedLPPaTransport + CRITICALITY ignore +} + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU.asn b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU.asn new file mode 100644 index 0000000000..1b20645bf6 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R10.5/S1AP-PDU.asn @@ -0,0 +1,413 @@ +S1AP-PDU { + itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) + eps-Access (21) modules (3) s1ap (1) version1 (1) +} + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS +Criticality, +ProcedureCode, +ProtocolIE-ID + +FROM S1AP-CommonDataTypes + +maxProtocolIEs + +FROM S1AP-Constants; + +S1AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +HandoverRequired ::= SEQUENCE { + handoverRequired-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCommand ::= SEQUENCE { + handoverCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverPreparationFailure ::= SEQUENCE { + handoverPreparationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequest ::= SEQUENCE { + handoverRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequestAcknowledge ::= SEQUENCE { + handoverRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverFailure ::= SEQUENCE { + handoverFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverNotify ::= SEQUENCE { + handoverNotify-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequest ::= SEQUENCE { + pathSwitchRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestAcknowledge ::= SEQUENCE { + pathSwitchRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestFailure ::= SEQUENCE { + pathSwitchRequestFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupRequest ::= SEQUENCE { + e-RABSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupResponse ::= SEQUENCE { + e-RABSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyRequest ::= SEQUENCE { + e-RABModifyRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyResponse ::= SEQUENCE { + e-RABModifyResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseIndication ::= SEQUENCE { + e-RABReleaseIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseCommand ::= SEQUENCE { + e-RABReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseResponse ::= SEQUENCE { + e-RABReleaseResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupRequest ::= SEQUENCE { + initialContextSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupResponse ::= SEQUENCE { + initialContextSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupFailure ::= SEQUENCE { + initialContextSetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseRequest ::= SEQUENCE { + ueContextReleaseRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Paging ::= SEQUENCE { + paging-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkNASTransport ::= SEQUENCE { + downlinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialUEMessage ::= SEQUENCE { + initialUEMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkNASTransport ::= SEQUENCE { + uplinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +NASNonDeliveryIndication ::= SEQUENCE { + nasNonDeliveryIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancel ::= SEQUENCE { + handoverCancel-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancelAcknowledge ::= SEQUENCE { + handoverCancelAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Reset ::= SEQUENCE { + reset-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ResetAcknowledge ::= SEQUENCE { + resetAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupResponse ::= SEQUENCE { + s1SetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupRequest ::= SEQUENCE { + s1SetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupFailure ::= SEQUENCE +{ + s1SetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ErrorIndication ::= SEQUENCE { + errorIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdate ::= SEQUENCE { + eNBConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + eNBConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateFailure ::= SEQUENCE { + eNBConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdate ::= SEQUENCE { + mmeConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + mmeConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateFailure ::= SEQUENCE { + mmeConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + downlinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkS1cdma2000tunneling ::= SEQUENCE { + uplinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationRequest ::= SEQUENCE { + ueContextModificationRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationResponse ::= SEQUENCE { + ueContextModificationResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationFailure ::= SEQUENCE { + ueContextModificationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UECapabilityInfoIndication ::= SEQUENCE { + ueCapabilityInfoIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseCommand ::= SEQUENCE { + ueContextReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseComplete ::= SEQUENCE { + ueContextReleaseComplete-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBStatusTransfer ::= SEQUENCE { + eNBStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEStatusTransfer ::= SEQUENCE { + mmeStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DeactivateTrace ::= SEQUENCE { + deactivateTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceStart ::= SEQUENCE { + traceStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceFailureIndication ::= SEQUENCE { + traceFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +CellTrafficTrace ::= SEQUENCE { + cellTrafficTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingControl ::= SEQUENCE { + locationReportingControl-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingFailureIndication ::= SEQUENCE { + locationReportingFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReport ::= SEQUENCE { + locationReport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStart ::= SEQUENCE { + overloadStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStop ::= SEQUENCE { + overloadStop-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningRequest ::= SEQUENCE { + writeReplaceWarningRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningResponse ::= SEQUENCE { + writeReplaceWarningResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBDirectInformationTransfer ::= SEQUENCE { + eNBDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEDirectInformationTransfer ::= SEQUENCE { + mmeDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationTransfer ::= SEQUENCE { + eNBConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationTransfer ::= SEQUENCE { + mmeConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PrivateMessage ::= SEQUENCE { + privateMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +KillRequest ::= SEQUENCE { + killRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +KillResponse ::= SEQUENCE { + killResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkUEAssociatedLPPaTransport ::= SEQUENCE { + downlinkUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkUEAssociatedLPPaTransport ::= SEQUENCE { + uplinkUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + downlinkNonUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + uplinkNonUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +IE ::= SEQUENCE { + id ProtocolIE-ID, + criticality Criticality, + value ANY +} + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-CommonDataTypes.asn b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-CommonDataTypes.asn new file mode 100644 index 0000000000..3b86547186 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-CommonDataTypes.asn @@ -0,0 +1,201 @@ +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** + +S1AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-CommonDataTypes (3) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optional, conditional, mandatory } + +PrivateIE-ID ::= CHOICE { + local INTEGER (0..65535), + global OBJECT IDENTIFIER +} + +--ProcedureCode ::= INTEGER (0..255) +ProcedureCode ::= INTEGER { +id-HandoverPreparation(0), +id-HandoverResourceAllocation(1), +id-HandoverNotification(2), +id-PathSwitchRequest(3), +id-HandoverCancel(4), +id-E-RABSetup(5), +id-E-RABModify(6), +id-E-RABRelease(7), +id-E-RABReleaseIndication(8), +id-InitialContextSetup(9), +id-Paging(10), +id-downlinkNASTransport(11), +id-initialUEMessage(12), +id-uplinkNASTransport(13), +id-Reset(14), +id-ErrorIndication(15), +id-NASNonDeliveryIndication(16), +id-S1Setup(17), +id-UEContextReleaseRequest(18), +id-DownlinkS1cdma2000tunneling(19), +id-UplinkS1cdma2000tunneling(20), +id-UEContextModification(21), +id-UECapabilityInfoIndication(22), +id-UEContextRelease(23), +id-eNBStatusTransfer(24), +id-MMEStatusTransfer(25), +id-DeactivateTrace(26), +id-TraceStart(27), +id-TraceFailureIndication(28), +id-ENBConfigurationUpdate(29), +id-MMEConfigurationUpdate(30), +id-LocationReportingControl(31), +id-LocationReportingFailureIndication(32), +id-LocationReport(33), +id-OverloadStart(34), +id-OverloadStop(35), +id-WriteReplaceWarning(36), +id-eNBDirectInformationTransfer(37), +id-MMEDirectInformationTransfer(38), +id-PrivateMessage(39), +id-eNBConfigurationTransfer(40), +id-MMEConfigurationTransfer(41), +id-CellTrafficTrace(42) +} (0..255) + +ProtocolExtensionID ::= INTEGER (0..65535) + +ProtocolIE-ID ::= INTEGER { +id-MME-UE-S1AP-ID(0), +id-HandoverType(1), +id-Cause(2), +id-SourceID(3), +id-TargetID (4), +id-eNB-UE-S1AP-ID(8), +id-E-RABSubjecttoDataForwardingList(12), +id-E-RABtoReleaseListHOCmd(13), +id-E-RABDataForwardingItem(14), +id-E-RABReleaseItemBearerRelComp(15), +id-E-RABToBeSetupListBearerSUReq(16), +id-E-RABToBeSetupItemBearerSUReq(17), +id-E-RABAdmittedList(18), +id-E-RABFailedToSetupListHOReqAck(19), +id-E-RABAdmittedItem(20), +id-E-RABFailedtoSetupItemHOReqAck(21), +id-E-RABToBeSwitchedDLList(22), +id-E-RABToBeSwitchedDLItem(23), +id-E-RABToBeSetupListCtxtSUReq(24), +id-TraceActivation(25), +id-NAS-PDU(26), +id-E-RABToBeSetupItemHOReq(27), +id-E-RABSetupListBearerSURes(28), +id-E-RABFailedToSetupListBearerSURes(29), +id-E-RABToBeModifiedListBearerModReq(30), +id-E-RABModifyListBearerModRes(31), +id-E-RABFailedToModifyList(32), +id-E-RABToBeReleasedList(33), +id-E-RABFailedToReleaseList(34), +id-E-RABItem(35), +id-E-RABToBeModifiedItemBearerModReq(36), +id-E-RABModifyItemBearerModRes(37), +id-E-RABReleaseItem(38), +id-E-RABSetupItemBearerSURes(39), +id-SecurityContext(40), +id-HandoverRestrictionList(41), +id-UEPagingID(43), +id-pagingDRX(44), +id-TAIList(46), +id-TAIItem(47), +id-E-RABFailedToSetupListCtxtSURes(48), +id-E-RABReleaseItemHOCmd(49), +id-E-RABSetupItemCtxtSURes(50), +id-E-RABSetupListCtxtSURes(51), +id-E-RABToBeSetupItemCtxtSUReq(52), +id-E-RABToBeSetupListHOReq(53), +id-GERANtoLTEHOInformationRes(55), +id-UTRANtoLTEHOInformationRes(57), +id-CriticalityDiagnostics(58), +id-Global-ENB-ID(59), +id-eNBname(60), +id-MMEname(61), +id-ServedPLMNs(63), +id-SupportedTAs(64), +id-TimeToWait(65), +id-uEaggregateMaximumBitrate(66), +id-TAI(67), +id-E-RABReleaseListBearerRelComp(69), +id-cdma2000PDU(70), +id-cdma2000RATType(71), +id-cdma2000SectorID(72), +id-SecurityKey(73), +id-UERadioCapability(74), +id-GUMMEI-ID(75), +id-E-RABInformationListItem(78), +id-Direct-Forwarding-Path-Availability(79), +id-UEIdentityIndexValue(80), +id-cdma2000HOStatus(83), +id-cdma2000HORequiredIndication(84), +id-E-UTRAN-Trace-ID(86), +id-RelativeMMECapacity(87), +id-SourceMME-UE-S1AP-ID(88), +id-Bearers-SubjectToStatusTransfer-Item(89), +id-eNB-StatusTransfer-TransparentContainer(90), +id-UE-associatedLogicalS1-ConnectionItem(91), +id-ResetType(92), +id-UE-associatedLogicalS1-ConnectionListResAck(93), +id-E-RABToBeSwitchedULItem(94), +id-E-RABToBeSwitchedULList(95), +id-S-TMSI(96), +id-cdma2000OneXRAND(97), +id-RequestType(98), +id-UE-S1AP-IDs(99), +id-EUTRAN-CGI(100), +id-OverloadResponse(101), +id-cdma2000OneXSRVCCInfo(102), +id-E-RABFailedToBeReleasedList(103), +id-Source-ToTarget-TransparentContainer(104), +id-ServedGUMMEIs(105), +id-SubscriberProfileIDforRFP(106), +id-UESecurityCapabilities(107), +id-CSFallbackIndicator(108), +id-CNDomain(109), +id-E-RABReleasedList(110), +id-MessageIdentifier(111), +id-SerialNumber(112), +id-WarningAreaList(113), +id-RepetitionPeriod(114), +id-NumberofBroadcastRequest(115), +id-WarningType(116), +id-WarningSecurityInfo(117), +id-DataCodingScheme(118), +id-WarningMessageContents(119), +id-BroadcastCompletedAreaList(120), +id-Inter-SystemInformationTransferTypeEDT(121), +id-Inter-SystemInformationTransferTypeMDT(122), +id-Target-ToSource-TransparentContainer(123), +id-SRVCCOperationPossible(124), +id-SRVCCHOIndication(125), +id-NAS-DownlinkCount(126), +id-CSG-Id(127), +id-CSG-IdList(128), +id-SONConfigurationTransferECT(129), +id-SONConfigurationTransferMCT(130), +id-TraceCollectionEntityIPAddress(131), +id-MSClassmark2(132), +id-MSClassmark3(133), +id-RRC-Establishment-Cause(134), +id-NASSecurityParametersfromE-UTRAN(135), +id-NASSecurityParameterstoE-UTRAN(136), +id-DefaultPagingDRX(137), +id-Source-ToTarget-TransparentContainer-Secondary(138), +id-Target-ToSource-TransparentContainer-Secondary(139) +} (0..65535) + +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessfull-outcome } + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-Constants.asn b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-Constants.asn new file mode 100644 index 0000000000..debbafd79d --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-Constants.asn @@ -0,0 +1,249 @@ +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** + +S1AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Constants (4) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + + +IMPORTS + ProcedureCode, + ProtocolIE-ID + +FROM S1AP-CommonDataTypes; + + +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** + +id-HandoverPreparation ProcedureCode ::= 0 +id-HandoverResourceAllocation ProcedureCode ::= 1 +id-HandoverNotification ProcedureCode ::= 2 +id-PathSwitchRequest ProcedureCode ::= 3 +id-HandoverCancel ProcedureCode ::= 4 +id-E-RABSetup ProcedureCode ::= 5 +id-E-RABModify ProcedureCode ::= 6 +id-E-RABRelease ProcedureCode ::= 7 +id-E-RABReleaseIndication ProcedureCode ::= 8 +id-InitialContextSetup ProcedureCode ::= 9 +id-Paging ProcedureCode ::= 10 +id-downlinkNASTransport ProcedureCode ::= 11 +id-initialUEMessage ProcedureCode ::= 12 +id-uplinkNASTransport ProcedureCode ::= 13 +id-Reset ProcedureCode ::= 14 +id-ErrorIndication ProcedureCode ::= 15 +id-NASNonDeliveryIndication ProcedureCode ::= 16 +id-S1Setup ProcedureCode ::= 17 +id-UEContextReleaseRequest ProcedureCode ::= 18 +id-DownlinkS1cdma2000tunneling ProcedureCode ::= 19 +id-UplinkS1cdma2000tunneling ProcedureCode ::= 20 +id-UEContextModification ProcedureCode ::= 21 +id-UECapabilityInfoIndication ProcedureCode ::= 22 +id-UEContextRelease ProcedureCode ::= 23 +id-eNBStatusTransfer ProcedureCode ::= 24 +id-MMEStatusTransfer ProcedureCode ::= 25 +id-DeactivateTrace ProcedureCode ::= 26 +id-TraceStart ProcedureCode ::= 27 +id-TraceFailureIndication ProcedureCode ::= 28 +id-ENBConfigurationUpdate ProcedureCode ::= 29 +id-MMEConfigurationUpdate ProcedureCode ::= 30 +id-LocationReportingControl ProcedureCode ::= 31 +id-LocationReportingFailureIndication ProcedureCode ::= 32 +id-LocationReport ProcedureCode ::= 33 +id-OverloadStart ProcedureCode ::= 34 +id-OverloadStop ProcedureCode ::= 35 +id-WriteReplaceWarning ProcedureCode ::= 36 +id-eNBDirectInformationTransfer ProcedureCode ::= 37 +id-MMEDirectInformationTransfer ProcedureCode ::= 38 +id-PrivateMessage ProcedureCode ::= 39 +id-eNBConfigurationTransfer ProcedureCode ::= 40 +id-MMEConfigurationTransfer ProcedureCode ::= 41 +id-CellTrafficTrace ProcedureCode ::= 42 + +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** + +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** + +maxNrOfCSGs INTEGER ::= 256 +maxNrOfE-RABs INTEGER ::= 256 +maxnoofTAIs INTEGER ::= 256 +maxnoofTACs INTEGER ::= 256 +maxNrOfErrors INTEGER ::= 256 +maxnoofBPLMNs INTEGER ::= 6 +maxnoofPLMNsPerMME INTEGER ::= 32 +maxnoofEPLMNs INTEGER ::= 15 +maxnoofEPLMNsPlusOne INTEGER ::= 16 +maxnoofForbLACs INTEGER ::= 4096 +maxnoofForbTACs INTEGER ::= 4096 +maxNrOfIndividualS1ConnectionsToReset INTEGER ::= 256 +maxnoofCells INTEGER ::= 16 +maxnoofTAIforWarning INTEGER ::= 65535 +maxnoofCellID INTEGER ::= 65535 +maxnoofEmergencyAreaID INTEGER ::= 65535 +maxnoofCellinTAI INTEGER ::= 65535 +maxnoofCellinEAI INTEGER ::= 65535 +maxnoofeNBX2TLAs INTEGER ::= 2 +maxnoofRATs INTEGER ::= 8 +maxnoofGroupIDs INTEGER ::= 65535 +maxnoofMMECs INTEGER ::= 256 + + + + +-- ************************************************************** +-- +-- IEs +-- +-- ************************************************************** + +id-MME-UE-S1AP-ID ProtocolIE-ID ::= 0 +id-HandoverType ProtocolIE-ID ::= 1 +id-Cause ProtocolIE-ID ::= 2 +id-SourceID ProtocolIE-ID ::= 3 +id-TargetID ProtocolIE-ID ::= 4 +id-eNB-UE-S1AP-ID ProtocolIE-ID ::= 8 +id-E-RABSubjecttoDataForwardingList ProtocolIE-ID ::= 12 +id-E-RABtoReleaseListHOCmd ProtocolIE-ID ::= 13 +id-E-RABDataForwardingItem ProtocolIE-ID ::= 14 +id-E-RABReleaseItemBearerRelComp ProtocolIE-ID ::= 15 +id-E-RABToBeSetupListBearerSUReq ProtocolIE-ID ::= 16 +id-E-RABToBeSetupItemBearerSUReq ProtocolIE-ID ::= 17 +id-E-RABAdmittedList ProtocolIE-ID ::= 18 +id-E-RABFailedToSetupListHOReqAck ProtocolIE-ID ::= 19 +id-E-RABAdmittedItem ProtocolIE-ID ::= 20 +id-E-RABFailedtoSetupItemHOReqAck ProtocolIE-ID ::= 21 +id-E-RABToBeSwitchedDLList ProtocolIE-ID ::= 22 +id-E-RABToBeSwitchedDLItem ProtocolIE-ID ::= 23 +id-E-RABToBeSetupListCtxtSUReq ProtocolIE-ID ::= 24 +id-TraceActivation ProtocolIE-ID ::= 25 +id-NAS-PDU ProtocolIE-ID ::= 26 +id-E-RABToBeSetupItemHOReq ProtocolIE-ID ::= 27 +id-E-RABSetupListBearerSURes ProtocolIE-ID ::= 28 +id-E-RABFailedToSetupListBearerSURes ProtocolIE-ID ::= 29 +id-E-RABToBeModifiedListBearerModReq ProtocolIE-ID ::= 30 +id-E-RABModifyListBearerModRes ProtocolIE-ID ::= 31 +id-E-RABFailedToModifyList ProtocolIE-ID ::= 32 +id-E-RABToBeReleasedList ProtocolIE-ID ::= 33 +id-E-RABFailedToReleaseList ProtocolIE-ID ::= 34 +id-E-RABItem ProtocolIE-ID ::= 35 +id-E-RABToBeModifiedItemBearerModReq ProtocolIE-ID ::= 36 +id-E-RABModifyItemBearerModRes ProtocolIE-ID ::= 37 +id-E-RABReleaseItem ProtocolIE-ID ::= 38 +id-E-RABSetupItemBearerSURes ProtocolIE-ID ::= 39 +id-SecurityContext ProtocolIE-ID ::= 40 +id-HandoverRestrictionList ProtocolIE-ID ::= 41 +id-UEPagingID ProtocolIE-ID ::= 43 +id-pagingDRX ProtocolIE-ID ::= 44 +id-TAIList ProtocolIE-ID ::= 46 +id-TAIItem ProtocolIE-ID ::= 47 +id-E-RABFailedToSetupListCtxtSURes ProtocolIE-ID ::= 48 +id-E-RABReleaseItemHOCmd ProtocolIE-ID ::= 49 +id-E-RABSetupItemCtxtSURes ProtocolIE-ID ::= 50 +id-E-RABSetupListCtxtSURes ProtocolIE-ID ::= 51 +id-E-RABToBeSetupItemCtxtSUReq ProtocolIE-ID ::= 52 +id-E-RABToBeSetupListHOReq ProtocolIE-ID ::= 53 +id-GERANtoLTEHOInformationRes ProtocolIE-ID ::= 55 +id-UTRANtoLTEHOInformationRes ProtocolIE-ID ::= 57 +id-CriticalityDiagnostics ProtocolIE-ID ::= 58 +id-Global-ENB-ID ProtocolIE-ID ::= 59 +id-eNBname ProtocolIE-ID ::= 60 +id-MMEname ProtocolIE-ID ::= 61 +id-ServedPLMNs ProtocolIE-ID ::= 63 +id-SupportedTAs ProtocolIE-ID ::= 64 +id-TimeToWait ProtocolIE-ID ::= 65 +id-uEaggregateMaximumBitrate ProtocolIE-ID ::= 66 +id-TAI ProtocolIE-ID ::= 67 +id-E-RABReleaseListBearerRelComp ProtocolIE-ID ::= 69 +id-cdma2000PDU ProtocolIE-ID ::= 70 +id-cdma2000RATType ProtocolIE-ID ::= 71 +id-cdma2000SectorID ProtocolIE-ID ::= 72 +id-SecurityKey ProtocolIE-ID ::= 73 +id-UERadioCapability ProtocolIE-ID ::= 74 +id-GUMMEI-ID ProtocolIE-ID ::= 75 +id-E-RABInformationListItem ProtocolIE-ID ::= 78 +id-Direct-Forwarding-Path-Availability ProtocolIE-ID ::= 79 +id-UEIdentityIndexValue ProtocolIE-ID ::= 80 +id-cdma2000HOStatus ProtocolIE-ID ::= 83 +id-cdma2000HORequiredIndication ProtocolIE-ID ::= 84 +id-E-UTRAN-Trace-ID ProtocolIE-ID ::= 86 +id-RelativeMMECapacity ProtocolIE-ID ::= 87 +id-SourceMME-UE-S1AP-ID ProtocolIE-ID ::= 88 +id-Bearers-SubjectToStatusTransfer-Item ProtocolIE-ID ::= 89 +id-eNB-StatusTransfer-TransparentContainer ProtocolIE-ID ::= 90 +id-UE-associatedLogicalS1-ConnectionItem ProtocolIE-ID ::= 91 +id-ResetType ProtocolIE-ID ::= 92 +id-UE-associatedLogicalS1-ConnectionListResAck ProtocolIE-ID ::= 93 +id-E-RABToBeSwitchedULItem ProtocolIE-ID ::= 94 +id-E-RABToBeSwitchedULList ProtocolIE-ID ::= 95 +id-S-TMSI ProtocolIE-ID ::= 96 +id-cdma2000OneXRAND ProtocolIE-ID ::= 97 +id-RequestType ProtocolIE-ID ::= 98 +id-UE-S1AP-IDs ProtocolIE-ID ::= 99 +id-EUTRAN-CGI ProtocolIE-ID ::= 100 +id-OverloadResponse ProtocolIE-ID ::= 101 +id-cdma2000OneXSRVCCInfo ProtocolIE-ID ::= 102 +id-E-RABFailedToBeReleasedList ProtocolIE-ID ::= 103 +id-Source-ToTarget-TransparentContainer ProtocolIE-ID ::= 104 +id-ServedGUMMEIs ProtocolIE-ID ::= 105 +id-SubscriberProfileIDforRFP ProtocolIE-ID ::= 106 +id-UESecurityCapabilities ProtocolIE-ID ::= 107 +id-CSFallbackIndicator ProtocolIE-ID ::= 108 +id-CNDomain ProtocolIE-ID ::= 109 +id-E-RABReleasedList ProtocolIE-ID ::= 110 +id-MessageIdentifier ProtocolIE-ID ::= 111 +id-SerialNumber ProtocolIE-ID ::= 112 +id-WarningAreaList ProtocolIE-ID ::= 113 +id-RepetitionPeriod ProtocolIE-ID ::= 114 +id-NumberofBroadcastRequest ProtocolIE-ID ::= 115 +id-WarningType ProtocolIE-ID ::= 116 +id-WarningSecurityInfo ProtocolIE-ID ::= 117 +id-DataCodingScheme ProtocolIE-ID ::= 118 +id-WarningMessageContents ProtocolIE-ID ::= 119 +id-BroadcastCompletedAreaList ProtocolIE-ID ::= 120 +id-Inter-SystemInformationTransferTypeEDT ProtocolIE-ID ::= 121 +id-Inter-SystemInformationTransferTypeMDT ProtocolIE-ID ::= 122 +id-Target-ToSource-TransparentContainer ProtocolIE-ID ::= 123 +id-SRVCCOperationPossible ProtocolIE-ID ::= 124 +id-SRVCCHOIndication ProtocolIE-ID ::= 125 +id-NAS-DownlinkCount ProtocolIE-ID ::= 126 +id-CSG-Id ProtocolIE-ID ::= 127 +id-CSG-IdList ProtocolIE-ID ::= 128 +id-SONConfigurationTransferECT ProtocolIE-ID ::= 129 +id-SONConfigurationTransferMCT ProtocolIE-ID ::= 130 +id-TraceCollectionEntityIPAddress ProtocolIE-ID ::= 131 +id-MSClassmark2 ProtocolIE-ID ::= 132 +id-MSClassmark3 ProtocolIE-ID ::= 133 +id-RRC-Establishment-Cause ProtocolIE-ID ::= 134 +id-NASSecurityParametersfromE-UTRAN ProtocolIE-ID ::= 135 +id-NASSecurityParameterstoE-UTRAN ProtocolIE-ID ::= 136 +id-DefaultPagingDRX ProtocolIE-ID ::= 137 +id-Source-ToTarget-TransparentContainer-Secondary ProtocolIE-ID ::= 138 +id-Target-ToSource-TransparentContainer-Secondary ProtocolIE-ID ::= 139 +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-IEs.asn b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-IEs.asn new file mode 100644 index 0000000000..6f76164b08 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-IEs.asn @@ -0,0 +1,1401 @@ +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** + +S1AP-IEs { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-IEs (2) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + id-E-RABInformationListItem, + id-E-RABItem, + id-Bearers-SubjectToStatusTransfer-Item, + maxNrOfCSGs, + maxNrOfE-RABs, + maxNrOfErrors, + maxnoofBPLMNs, + maxnoofPLMNsPerMME, + maxnoofTACs, + maxnoofEPLMNs, + maxnoofEPLMNsPlusOne, + maxnoofForbLACs, + maxnoofForbTACs, + maxnoofCells, + maxnoofCellID, + maxnoofEmergencyAreaID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + maxnoofeNBX2TLAs, + maxnoofRATs, + maxnoofGroupIDs, + maxnoofMMECs, + maxProtocolExtensions, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofTAIs, + maxProtocolIEs +FROM S1AP-Constants + + IE +FROM S1AP-PDU + + Criticality, + ProcedureCode, + ProtocolIE-ID, + ProtocolExtensionID, + TriggeringMessage +FROM S1AP-CommonDataTypes; + +IE-Extensions ::= SEQUENCE (SIZE (1..maxProtocolExtensions)) OF IE +-- A + + +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, +-- iE-Extensions ProtocolExtensionContainer { {AllocationAndRetentionPriority-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +AllocationAndRetentionPriority-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +-- B + +Bearers-SubjectToStatusTransfer-List ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +Bearers-SubjectToStatusTransfer-Item ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + uL-COUNTvalue COUNTvalue, + dL-COUNTvalue COUNTvalue, + receiveStatusofULPDCPSDUs ReceiveStatusofULPDCPSDUs OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +Bearers-SubjectToStatusTransfer-ItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +BitRate ::= INTEGER (0..10000000000) + +BPLMNs ::= SEQUENCE (SIZE(1.. maxnoofBPLMNs)) OF PLMNidentity + +BroadcastCompletedAreaList ::= CHOICE { + cellID-Broadcast CellID-Broadcast, + tAI-Broadcast TAI-Broadcast, + emergencyAreaID-Broadcast EmergencyAreaID-Broadcast, + ... +} + + +-- C + +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nas CauseNas, + protocol CauseProtocol, + misc CauseMisc, + ... +} + +CauseMisc ::= ENUMERATED { + control-processing-overload, + not-enough-user-plane-processing-resources, + hardware-failure, + om-intervention, + unspecified, + unknown-PLMN, +... +} + +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} + +CauseRadioNetwork ::= ENUMERATED { + unspecified, + tx2relocoverall-expiry, + successful-handover, + release-due-to-eutran-generated-reason, + handover-cancelled, + partial-handover, + ho-failure-in-target-EPC-eNB-or-target-system, + ho-target-not-allowed, + tS1relocoverall-expiry, + tS1relocprep-expiry, + cell-not-available, + unknown-targetID, + no-radio-resources-available-in-target-cell, + unknown-mme-ue-s1ap-id, + unknown-enb-ue-s1ap-id, + unknown-pair-ue-s1ap-id, + handover-desirable-for-radio-reason, + time-critical-handover, + resource-optimisation-handover, + reduce-load-in-serving-cell, + user-inactivity, + radio-connection-with-ue-lost, + load-balancing-tau-required, + cs-fallback-triggered, + ue-not-available-for-ps-service, + radio-resources-not-available, + failure-in-radio-interface-procedure, + invalid-qos-combination, + interrat-redirection, + interaction-with-other-procedure, + unknown-E-RAB-ID, + multiple-E-RAB-ID-instances, + encryption-and-or-integrity-protection-algorithms-not-supported, + s1-intra-system-handover-triggered, + s1-inter-system-handover-triggered, + x2-handover-triggered, + ..., + redirection-towards-1xRTT, + not-supported-QCI-value + +} + +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} + +CauseNas ::= ENUMERATED { + normal-release, + authentication-failure, + detach, + unspecified, + ... +} + +CellIdentity ::= BIT STRING (SIZE (28)) + +CellID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF CellID-Broadcast-Item + +CellID-Broadcast-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, +-- iE-Extensions ProtocolExtensionContainer { {CellID-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +CellID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +Cdma2000PDU ::= OCTET STRING + +Cdma2000RATType ::= ENUMERATED { + hRPD, + onexRTT, + ... +} + +Cdma2000SectorID ::= OCTET STRING + +Cdma2000HOStatus ::= ENUMERATED { + hOSuccess, + hOFailure, + ... +} + +Cdma2000HORequiredIndication ::= ENUMERATED { + true, + ... +} + +Cdma2000OneXSRVCCInfo ::= SEQUENCE { + cdma2000OneXMEID Cdma2000OneXMEID, + cdma2000OneXMSI Cdma2000OneXMSI, + cdma2000OneXPilot Cdma2000OneXPilot, +-- iE-Extensions ProtocolExtensionContainer { {Cdma2000OneXSRVCCInfo-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +Cdma2000OneXSRVCCInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +Cdma2000OneXMEID ::= OCTET STRING + +Cdma2000OneXMSI ::= OCTET STRING + +Cdma2000OneXPilot ::= OCTET STRING + +Cdma2000OneXRAND ::= OCTET STRING + + +Cell-Size ::= ENUMERATED {verysmall, small, medium, large, ...} + +CellType ::= SEQUENCE { + cell-Size Cell-Size, +-- iE-Extensions ProtocolExtensionContainer { { CellType-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +CellType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, + cI CI, + rAC RAC OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {CGI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +CI ::= OCTET STRING (SIZE (2)) + +CNDomain ::= ENUMERATED { + ps, + cs +} + +CSFallbackIndicator ::= ENUMERATED { + cs-fallback-required, + ..., + cs-fallback-high-priority +} + +CSG-Id ::= BIT STRING (SIZE (27)) + + +CSG-IdList ::= SEQUENCE (SIZE (1..maxNrOfCSGs)) OF CSG-IdList-Item + +CSG-IdList-Item ::= SEQUENCE { + cSG-Id CSG-Id, +-- iE-Extensions ProtocolExtensionContainer { {CSG-IdList-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +CSG-IdList-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +COUNTvalue ::= SEQUENCE { + pDCP-SN PDCP-SN, + hFN HFN, +-- iE-Extensions ProtocolExtensionContainer { {COUNTvalue-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +COUNTvalue-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer {{CriticalityDiagnostics-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +--CriticalityDiagnostics-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { +-- ... +--} + +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxNrOfErrors)) OF CriticalityDiagnostics-IE-Item + +CriticalityDiagnostics-IE-Item ::= SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, +-- iE-Extensions ProtocolExtensionContainer {{CriticalityDiagnostics-IE-Item-ExtIEs}} OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +--CriticalityDiagnostics-IE-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { +-- ... +--} + + +-- D + +DataCodingScheme ::= BIT STRING (SIZE (8)) + +DL-Forwarding ::= ENUMERATED { + dL-Forwarding-proposed, + ... +} + +Direct-Forwarding-Path-Availability ::= ENUMERATED { + directPathAvailable, + ... +} + +-- E + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeModifiedItemBearerModReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABLevelQoSParameters E-RABLevelQoSParameters, + nAS-PDU NAS-PDU, +-- iE-Extensions ProtocolExtensionContainer { {E-RABToBeModifyItemBearerModReqExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABReleaseItemBearerRelComp ::= SEQUENCE { + e-RAB-ID E-RAB-ID, +-- iE-Extensions ProtocolExtensionContainer { {E-RABReleaseItemBearerRelCompExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABDataForwardingList ::= SEQUENCE (SIZE (0..maxNrOfE-RABs)) OF IE + +E-RABDataForwardingItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { { E-RABDataForwardingItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1..maxNrOfE-RABs)) OF IE + +E-RABToBeSetupItemCtxtSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemCtxtSUReqExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABSetupItemBearerSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, +-- iE-Extensions ProtocolExtensionContainer { {E-RABSetupItemBearerSUResExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABFailedtoSetupListHOReqAck ::= SEQUENCE (SIZE (0..maxNrOfE-RABs)) OF IE + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, +-- iE-Extensions ProtocolExtensionContainer { { E-RABFailedToSetupItemHOReqAckExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSetupItemBearerSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU, +-- iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemBearerSUReqExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABAdmittedList ::= SEQUENCE (SIZE (0..maxNrOfE-RABs)) OF IE + +E-RABAdmittedItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {E-RABAdmittedItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedDLList ::= SEQUENCE (SIZE (0..maxNrOfE-RABs)) OF IE + +E-RABToBeSwitchedDLItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, +-- iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedDLItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedULList ::= SEQUENCE (SIZE (0..maxNrOfE-RABs)) OF IE + +E-RABToBeSwitchedULItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, +-- iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedULItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABModifyItemBearerModRes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABSetupItemCtxtSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, +-- iE-Extensions ProtocolExtensionContainer { {E-RABSetupItemCtxtSUResExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupListHOReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSetupItemHOReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + e-RABlevelQosParameters E-RABLevelQoSParameters, +-- iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemHOReq-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ECGIList ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF EUTRAN-CGI + +EmergencyAreaIDList ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID + +EmergencyAreaID ::= OCTET STRING (SIZE (3)) + +EmergencyAreaID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID-Broadcast-Item + +EmergencyAreaID-Broadcast-Item ::= SEQUENCE { + emergencyAreaID EmergencyAreaID, + completedCellinEAI CompletedCellinEAI, +-- iE-Extensions ProtocolExtensionContainer { {EmergencyAreaID-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +--EmergencyAreaID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { +-- ... +--} + + +CompletedCellinEAI ::= SEQUENCE (SIZE(1..maxnoofCellinEAI)) OF CompletedCellinEAI-Item + +CompletedCellinEAI-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, +-- iE-Extensions ProtocolExtensionContainer { {CompletedCellinEAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +/* +CompletedCellinEAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ENB-ID ::= CHOICE { + macroENB-ID BIT STRING (SIZE(20)), + homeENB-ID BIT STRING (SIZE(28)), + ... +} + +GERAN-Cell-ID ::= SEQUENCE { + lAI LAI, + rAC RAC, + cI CI, +-- iE-Extensions ProtocolExtensionContainer { { GERAN-Cell-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +--GERAN-Cell-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { +-- ... +--} + +Global-ENB-ID ::= SEQUENCE { + pLMNidentity PLMNidentity, + eNB-ID ENB-ID, + --iE-Extensions ProtocolExtensionContainer { {GlobalENB-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +--GlobalENB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { +-- ... +--} + + +ENB-StatusTransfer-TransparentContainer ::= SEQUENCE { + bearers-SubjectToStatusTransfer-List Bearers-SubjectToStatusTransfer-List, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-UE-S1AP-ID ::= INTEGER (0..16777215) + +ENBname ::= PrintableString (SIZE (1..150,...)) + +ENBX2TLAs ::= SEQUENCE (SIZE(1.. maxnoofeNBX2TLAs)) OF TransportLayerAddress + +EncryptionAlgorithms ::= BIT STRING (SIZE (16,...)) + +EPLMNs ::= SEQUENCE (SIZE(1..maxnoofEPLMNs)) OF PLMNidentity +EventType ::= ENUMERATED { + direct, + change-of-serve-cell, + stop-change-of-serve-cell, + ... +} + +E-RAB-ID ::= INTEGER (0..15, ...) + +--E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { E-RABInformationListIEs } } +E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF IE + +--E-RABInformationListIEs S1AP-PROTOCOL-IES ::= { +-- { ID id-E-RABInformationListItem CRITICALITY ignore TYPE E-RABInformationListItem PRESENCE mandatory }, +-- ... +--} + +E-RABInformationListItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-Forwarding DL-Forwarding OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {E-RABInformationListItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +E-RABInformationListItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +--E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABItemIEs} } +E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ANY + +--E-RABItemIEs S1AP-PROTOCOL-IES ::= { +-- { ID id-E-RABItem CRITICALITY ignore TYPE E-RABItem PRESENCE mandatory }, +-- ... +--} + +E-RABItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, +-- iE-Extensions ProtocolExtensionContainer { {E-RABItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +E-RABItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + + + +E-RABLevelQoSParameters ::= SEQUENCE { + qCI QCI, + allocationRetentionPriority AllocationAndRetentionPriority, + gbrQosInformation GBR-QosInformation OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {E-RABQoSParameters-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +E-RABQoSParameters-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +EUTRAN-CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + cell-ID CellIdentity, +-- iE-Extensions ProtocolExtensionContainer { {EUTRAN-CGI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +EUTRAN-CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ExtendedRNC-ID ::= INTEGER (4096..65535) + +-- F + +ForbiddenInterRATs ::= ENUMERATED { + all, + geran, + utran, + cdma2000, + ... +} + +ForbiddenTAs ::= SEQUENCE (SIZE(1.. maxnoofEPLMNsPlusOne)) OF ForbiddenTAs-Item + +ForbiddenTAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenTACs ForbiddenTACs, +-- iE-Extensions ProtocolExtensionContainer { {ForbiddenTAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +ForbiddenTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ForbiddenTACs ::= SEQUENCE (SIZE(1..maxnoofForbTACs)) OF TAC + +ForbiddenLAs ::= SEQUENCE (SIZE(1..maxnoofEPLMNsPlusOne)) OF ForbiddenLAs-Item + +ForbiddenLAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenLACs ForbiddenLACs, +-- iE-Extensions ProtocolExtensionContainer { {ForbiddenLAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +ForbiddenLAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ForbiddenLACs ::= SEQUENCE (SIZE(1..maxnoofForbLACs)) OF LAC + +-- G + +GBR-QosInformation ::= SEQUENCE { + e-RAB-MaximumBitrateDL BitRate, + e-RAB-MaximumBitrateUL BitRate, + e-RAB-GuaranteedBitrateDL BitRate, + e-RAB-GuaranteedBitrateUL BitRate, +-- iE-Extensions ProtocolExtensionContainer { { GBR-QosInformation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +GBR-QosInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +GTP-TEID ::= OCTET STRING (SIZE (4)) + +GUMMEI ::= SEQUENCE { + pLMN-Identity PLMNidentity, + mME-Group-ID MME-Group-ID, + mME-Code MME-Code, +-- iE-Extensions ProtocolExtensionContainer { {GUMMEI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +GUMMEI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +-- H + +HandoverRestrictionList ::= SEQUENCE { + servingPLMN PLMNidentity, + equivalentPLMNs EPLMNs OPTIONAL, + forbiddenTAs ForbiddenTAs OPTIONAL, + forbiddenLAs ForbiddenLAs OPTIONAL, + forbiddenInterRATs ForbiddenInterRATs OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {HandoverRestrictionList-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +HandoverRestrictionList-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +HandoverType ::= ENUMERATED { + intralte, + ltetoutran, + ltetogeran, + utrantolte, + gerantolte, + ... +} + +HFN ::= INTEGER (0..1048575) + +-- I + +Inter-SystemInformationTransferType ::= CHOICE { + rIMTransfer RIMTransfer, + ... +} + +IMSI ::= OCTET STRING (SIZE (3..8)) + +IntegrityProtectionAlgorithms ::= BIT STRING (SIZE (16,...)) + +InterfacesToTrace ::= BIT STRING (SIZE (8)) + + + +-- J +-- K +-- L + + +LAC ::= OCTET STRING (SIZE (2)) + +LAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, +-- iE-Extensions ProtocolExtensionContainer { {LAI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +LAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +LastVisitedCell-Item ::= CHOICE { + e-UTRAN-Cell LastVisitedEUTRANCellInformation, + uTRAN-Cell LastVisitedUTRANCellInformation, + gERAN-Cell LastVisitedGERANCellInformation, + ... +} +LastVisitedEUTRANCellInformation ::= SEQUENCE { + global-Cell-ID EUTRAN-CGI, + cellType CellType, + time-UE-StayedInCell Time-UE-StayedInCell, +-- iE-Extensions ProtocolExtensionContainer { { LastVisitedEUTRANCellInformation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +LastVisitedEUTRANCellInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ +LastVisitedUTRANCellInformation ::= OCTET STRING + +LastVisitedGERANCellInformation ::= CHOICE { + undefined NULL, + ... +} + +L3-Information ::= OCTET STRING + + +-- M + +MessageIdentifier ::= BIT STRING (SIZE (16)) + +MMEname ::= PrintableString (SIZE (1..150,...)) + +MME-Group-ID ::= OCTET STRING (SIZE (2)) + +MME-Code ::= OCTET STRING (SIZE (1)) + +MME-UE-S1AP-ID ::= INTEGER (0..4294967295) +M-TMSI ::= OCTET STRING (SIZE (4)) + +MSClassmark2 ::= OCTET STRING +MSClassmark3 ::= OCTET STRING + +-- N + +NAS-PDU ::= OCTET STRING + +NASSecurityParametersfromE-UTRAN ::= OCTET STRING + +NASSecurityParameterstoE-UTRAN ::= OCTET STRING + +NumberofBroadcastRequest ::= INTEGER (0..65535) + +NumberOfBroadcasts ::= INTEGER (0..65535) + +-- O +OldBSS-ToNewBSS-Information ::= OCTET STRING + +OverloadAction ::= ENUMERATED { + reject-non-emergency-mo-dt, + reject-all-rrc-cr-signalling, + permit-emergency-sessions-only, + ... +} + +OverloadResponse ::= CHOICE { + overloadAction OverloadAction, + ... +} + + +-- P + +PagingDRX ::= ENUMERATED { + v32, + v64, + v128, + v256, + ... + } + +PDCP-SN ::= INTEGER (0..4095) + +PLMNidentity ::= TBCD-STRING +--PLMNidentity ::= OCTET STRING (SIZE (3)) + +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} + +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} + +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) + + +-- Q + +QCI ::= INTEGER (0..255) + +-- R + +ReceiveStatusofULPDCPSDUs ::= BIT STRING (SIZE(4096)) + +RelativeMMECapacity ::= INTEGER (0..255) + +RAC ::= OCTET STRING (SIZE (1)) + + +RequestType ::= SEQUENCE { + eventType EventType, + reportArea ReportArea, +-- iE-Extensions ProtocolExtensionContainer { { RequestType-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +/* +RequestType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ResetType ::= CHOICE { + s1-Interface ResetAll, + partOfS1-Interface UE-associatedLogicalS1-ConnectionListRes, + ... +} + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +RIMTransfer ::= SEQUENCE { + rIMInformation RIMInformation, + rIMRoutingAddress RIMRoutingAddress OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { { RIMTransfer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, +... +} +/* +RIMTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +RIMInformation ::= OCTET STRING + +RIMRoutingAddress ::= CHOICE { + gERAN-Cell-ID GERAN-Cell-ID, + ... +} + +ReportArea ::= ENUMERATED { + ecgi, + ... +} + +RepetitionPeriod ::= INTEGER (0..4095) + + +RNC-ID ::= INTEGER (0..4095) + +RRC-Container ::= OCTET STRING + +RRC-Establishment-Cause ::= ENUMERATED { + emergency, + highPriorityAccess, + mt-Access, + mo-Signalling, + mo-Data, + ... +} + +-- S + + +SecurityKey ::= BIT STRING (SIZE(256)) + + + +SecurityContext ::= SEQUENCE { + nextHopChainingCount INTEGER (0..7), + nextHopParameter SecurityKey, +-- iE-Extensions ProtocolExtensionContainer { { SecurityContext-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +/* +SecurityContext-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +SerialNumber ::= BIT STRING (SIZE (16)) + +SONInformation ::= CHOICE{ + sONInformationRequest SONInformationRequest, + sONInformationReply SONInformationReply, + ... +} + +SONInformationRequest ::= ENUMERATED { + x2TNL-Configuration-Info, + ... +} + +SONInformationReply ::= SEQUENCE { + x2TNLConfigurationInfo X2TNLConfigurationInfo OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer {{SONInformationReply-ExtIEs}} OPTIONAL, + iE-Extensions-Container IE-Extensions OPTIONAL, + ... +} +/* +SONInformationReply-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +SONConfigurationTransfer ::= SEQUENCE { + targeteNB-ID TargeteNB-ID, + sourceeNB-ID SourceeNB-ID, + sONInformation SONInformation, +-- iE-Extensions ProtocolExtensionContainer { { SONConfigurationTransfer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, +... +} +/* +SONConfigurationTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + + +Source-ToTarget-TransparentContainer ::= OCTET STRING + +SourceBSS-ToTargetBSS-TransparentContainer ::= OCTET STRING +SourceeNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, +-- iE-Extensions ProtocolExtensionContainer { {SourceeNB-ID-ExtIEs} } OPTIONAL + iE-Extensions IE-Extensions OPTIONAL +} +/* +SourceeNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +SRVCCOperationPossible ::= ENUMERATED { + possible, + ... +} + +SRVCCHOIndication ::= ENUMERATED { + pSandCS, + cSonly, + ... +} + +SourceeNB-ToTargeteNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, + e-RABInformationList E-RABInformationList OPTIONAL, + targetCell-ID EUTRAN-CGI, + subscriberProfileIDforRFP SubscriberProfileIDforRFP OPTIONAL, + uE-HistoryInformation UE-HistoryInformation, +-- iE-Extensions ProtocolExtensionContainer { {SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +SourceRNC-ToTargetRNC-TransparentContainer ::= OCTET STRING + + +ServedGUMMEIs ::= SEQUENCE (SIZE (1.. maxnoofRATs)) OF ServedGUMMEIsItem + +ServedGUMMEIsItem ::= SEQUENCE { + servedPLMNs ServedPLMNs, + servedGroupIDs ServedGroupIDs, + servedMMECs ServedMMECs, +-- iE-Extensions ProtocolExtensionContainer { {ServedGUMMEIsItem-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +ServedGUMMEIsItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +ServedGroupIDs ::= SEQUENCE (SIZE(1.. maxnoofGroupIDs)) OF MME-Group-ID +ServedMMECs ::= SEQUENCE (SIZE(1.. maxnoofMMECs)) OF MME-Code + +ServedPLMNs ::= SEQUENCE (SIZE(1.. maxnoofPLMNsPerMME)) OF PLMNidentity + +SubscriberProfileIDforRFP ::= INTEGER (1..256) + +SupportedTAs ::= SEQUENCE (SIZE(1.. maxnoofTACs)) OF SupportedTAs-Item + +SupportedTAs-Item ::= SEQUENCE { + tAC TAC, + broadcastPLMNs BPLMNs, +-- iE-Extensions ProtocolExtensionContainer { {SupportedTAs-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +SupportedTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +S-TMSI ::= SEQUENCE { + mMEC MME-Code, + m-TMSI M-TMSI, +-- iE-Extensions ProtocolExtensionContainer { {S-TMSI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +S-TMSI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +-- T + +TAC ::= OCTET STRING (SIZE (2)) + +TAIListforWarning ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI + +TAIList ::= SEQUENCE (SIZE(1..maxnoofTAIs)) OF IE + +TAIItem ::= SEQUENCE { + tAI TAI, +-- iE-Extensions ProtocolExtensionContainer { {TAIItemExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + tAC TAC, +-- iE-Extensions ProtocolExtensionContainer { {TAI-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +TAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +TAI-Broadcast ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI-Broadcast-Item + +TAI-Broadcast-Item ::= SEQUENCE { + tAI TAI, + completedCellinTAI CompletedCellinTAI, +-- iE-Extensions ProtocolExtensionContainer { {TAI-Broadcast-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +TAI-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +CompletedCellinTAI ::= SEQUENCE (SIZE(1..maxnoofCellinTAI)) OF CompletedCellinTAI-Item + +CompletedCellinTAI-Item ::= SEQUENCE{ + eCGI EUTRAN-CGI, +-- iE-Extensions ProtocolExtensionContainer { {CompletedCellinTAI-Item-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +CompletedCellinTAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +TBCD-STRING ::= OCTET STRING (SIZE (3)) + +TargetID ::= CHOICE { + targeteNB-ID TargeteNB-ID, + targetRNC-ID TargetRNC-ID, + cGI CGI, + ... +} + +TargeteNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, +-- iE-Extensions ProtocolExtensionContainer { {TargeteNB-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +TargeteNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +TargetRNC-ID ::= SEQUENCE { + lAI LAI, + rAC RAC OPTIONAL, + rNC-ID RNC-ID, + extendedRNC-ID ExtendedRNC-ID OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { {TargetRNC-ID-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +/* +TargetRNC-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +TargeteNB-ToSourceeNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, +-- iE-Extensions ProtocolExtensionContainer { {TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +Target-ToSource-TransparentContainer ::= OCTET STRING +TargetRNC-ToSourceRNC-TransparentContainer ::= OCTET STRING +TargetBSS-ToSourceBSS-TransparentContainer ::= OCTET STRING + +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} + +Time-UE-StayedInCell ::= INTEGER (0..4095) + +TransportLayerAddress ::= BIT STRING (SIZE(1..160, ...)) + +TraceActivation ::= SEQUENCE { + e-UTRAN-Trace-ID E-UTRAN-Trace-ID, + interfacesToTrace InterfacesToTrace, +traceDepth TraceDepth, +traceCollectionEntityIPAddress TransportLayerAddress, +-- iE-Extensions ProtocolExtensionContainer { { TraceActivation-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +TraceActivation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +TraceDepth ::= ENUMERATED { + minimum, + medium, + maximum, + minimumWithoutVendorSpecificExtension, + mediumWithoutVendorSpecificExtension, + maximumWithoutVendorSpecificExtension, + ... +} + +E-UTRAN-Trace-ID ::= OCTET STRING (SIZE (8)) + +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} + +-- U + +UEAggregateMaximumBitrate ::= SEQUENCE { + uEaggregateMaximumBitRateDL BitRate, + uEaggregateMaximumBitRateUL BitRate, +-- iE-Extensions ProtocolExtensionContainer { {UEAggregate-MaximumBitrates-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +UEAggregate-MaximumBitrates-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + + +UE-S1AP-IDs ::= CHOICE{ + uE-S1AP-ID-pair UE-S1AP-ID-pair, + mME-UE-S1AP-ID MME-UE-S1AP-ID, + ... +} + +UE-S1AP-ID-pair ::= SEQUENCE{ + mME-UE-S1AP-ID MME-UE-S1AP-ID, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID, +-- iE-Extensions ProtocolExtensionContainer { {UE-S1AP-ID-pair-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +UE-S1AP-ID-pair-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + + +--WARNING: not the right IE definition... +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE + +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE + +UE-associatedLogicalS1-ConnectionItemRes ::= SET { + ue-associatedLogicalS1-ConnectionItemRes-ies UE-associatedLogicalS1-ConnectionItem, + ... +} + +UE-associatedLogicalS1-ConnectionItem ::= SEQUENCE { + mME-UE-S1AP-ID MME-UE-S1AP-ID OPTIONAL, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID OPTIONAL, +-- iE-Extensions ProtocolExtensionContainer { { UE-associatedLogicalS1-ConnectionItemExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +/* +UE-associatedLogicalS1-ConnectionItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +UEIdentityIndexValue ::= BIT STRING (SIZE (10)) + +UE-HistoryInformation ::= SEQUENCE (SIZE(1..maxnoofCells)) OF LastVisitedCell-Item + +UEPagingID ::= CHOICE { + s-TMSI S-TMSI, + iMSI IMSI, + ... + } + +UERadioCapability ::= OCTET STRING + +UESecurityCapabilities ::= SEQUENCE { + encryptionAlgorithms EncryptionAlgorithms, + integrityProtectionAlgorithms IntegrityProtectionAlgorithms, +-- iE-Extensions ProtocolExtensionContainer { { UESecurityCapabilities-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, +... +} +/* +UESecurityCapabilities-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +-- V +-- W + +WarningAreaList ::= CHOICE { + cellIDList ECGIList, + trackingAreaListforWarning TAIListforWarning, + emergencyAreaIDList EmergencyAreaIDList, + ... +} + + +WarningType ::= OCTET STRING (SIZE (2)) + +WarningSecurityInfo ::= OCTET STRING (SIZE (50)) + + +WarningMessageContents ::= OCTET STRING (SIZE(1..9600)) + + +-- X + + +X2TNLConfigurationInfo ::= SEQUENCE { + eNBX2TransportLayerAddresses ENBX2TLAs, +-- iE-Extensions ProtocolExtensionContainer { { X2TNLConfigurationInfo-ExtIEs} } OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} +/* +X2TNLConfigurationInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +}*/ + +-- Y +-- Z + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU-Contents.asn b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU-Contents.asn new file mode 100644 index 0000000000..1fc0f3bc5b --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU-Contents.asn @@ -0,0 +1,2069 @@ +-- ************************************************************** +-- +-- PDU definitions for S1AP. +-- +-- ************************************************************** + +S1AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-PDU-Contents (1) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + + UEAggregateMaximumBitrate, + Cause, + Cdma2000HORequiredIndication, + Cdma2000HOStatus, + Cdma2000OneXSRVCCInfo, + Cdma2000OneXRAND, + Cdma2000PDU, + Cdma2000RATType, + Cdma2000SectorID, + CNDomain, + CriticalityDiagnostics, + CSFallbackIndicator, + CSG-Id, + CSG-IdList, + Direct-Forwarding-Path-Availability, + Global-ENB-ID, + EUTRAN-CGI, + ENBname, + ENB-StatusTransfer-TransparentContainer, + ENB-UE-S1AP-ID, + GTP-TEID, + GUMMEI, + HandoverRestrictionList, + HandoverType, + MMEname, + MME-UE-S1AP-ID, + MSClassmark2, + MSClassmark3, + NAS-PDU, + NASSecurityParametersfromE-UTRAN, + NASSecurityParameterstoE-UTRAN, + OverloadResponse, + PagingDRX, + PLMNidentity, + RIMTransfer, + RelativeMMECapacity, + RequestType, + E-RAB-ID, + E-RABLevelQoSParameters, + E-RABList, + SecurityKey, + SecurityContext, + ServedGUMMEIs, + SONConfigurationTransfer, + Source-ToTarget-TransparentContainer, + SourceBSS-ToTargetBSS-TransparentContainer, + SourceeNB-ToTargeteNB-TransparentContainer, + SourceRNC-ToTargetRNC-TransparentContainer, + SubscriberProfileIDforRFP, + SRVCCOperationPossible, + SRVCCHOIndication, + SupportedTAs, + TAI, + Target-ToSource-TransparentContainer, + TargetBSS-ToSourceBSS-TransparentContainer, + TargeteNB-ToSourceeNB-TransparentContainer, + TargetID, + TargetRNC-ToSourceRNC-TransparentContainer, + TimeToWait, + TraceActivation, + E-UTRAN-Trace-ID, + TransportLayerAddress, + UEIdentityIndexValue, + UEPagingID, + UERadioCapability, + UE-S1AP-IDs, + UE-associatedLogicalS1-ConnectionItem, + UESecurityCapabilities, + S-TMSI, + MessageIdentifier, + SerialNumber, + WarningAreaList, + RepetitionPeriod, + NumberofBroadcastRequest, + WarningType, + WarningSecurityInfo, + DataCodingScheme, + WarningMessageContents, + BroadcastCompletedAreaList, + RRC-Establishment-Cause + +FROM S1AP-IEs + + + id-uEaggregateMaximumBitrate, + id-Cause, + id-cdma2000HORequiredIndication, + id-cdma2000HOStatus, + id-cdma2000OneXSRVCCInfo, + id-cdma2000OneXRAND, + id-cdma2000PDU, + id-cdma2000RATType, + id-cdma2000SectorID, + id-CNDomain, + id-CriticalityDiagnostics, + id-CSFallbackIndicator, + id-CSG-Id, + id-CSG-IdList, + id-DefaultPagingDRX, + id-Direct-Forwarding-Path-Availability, + id-Global-ENB-ID, + id-EUTRAN-CGI, + id-eNBname, + id-eNB-StatusTransfer-TransparentContainer, + id-eNB-UE-S1AP-ID, + id-GERANtoLTEHOInformationRes, + id-GUMMEI-ID, + id-HandoverRestrictionList, + id-HandoverType, + id-InitialContextSetup, + id-Inter-SystemInformationTransferTypeEDT, + id-Inter-SystemInformationTransferTypeMDT, + id-NAS-DownlinkCount, + id-MMEname, + id-MME-UE-S1AP-ID, + id-MSClassmark2, + id-MSClassmark3, + id-NAS-PDU, + id-NASSecurityParametersfromE-UTRAN, + id-NASSecurityParameterstoE-UTRAN, + id-OverloadResponse, + id-pagingDRX, + id-RelativeMMECapacity, + id-RequestType, + id-E-RABAdmittedItem, + id-E-RABAdmittedList, + id-E-RABDataForwardingItem, + id-E-RABFailedToModifyList, + id-E-RABFailedToReleaseList, + id-E-RABFailedtoSetupItemHOReqAck, + id-E-RABFailedToSetupListBearerSURes, + id-E-RABFailedToSetupListCtxtSURes, + id-E-RABFailedToSetupListHOReqAck, + id-E-RABFailedToBeReleasedList, + id-E-RABModify, + id-E-RABModifyItemBearerModRes, + id-E-RABModifyListBearerModRes, + id-E-RABRelease, + id-E-RABReleaseItemBearerRelComp, + id-E-RABReleaseItemHOCmd, + id-E-RABReleaseListBearerRelComp, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-E-RABSetupItemBearerSURes, + id-E-RABSetupItemCtxtSURes, + id-E-RABSetupListBearerSURes, + id-E-RABSetupListCtxtSURes, + id-E-RABSubjecttoDataForwardingList, + id-E-RABToBeModifiedItemBearerModReq, + id-E-RABToBeModifiedListBearerModReq, + id-E-RABToBeReleasedList, + id-E-RABReleasedList, + id-E-RABToBeSetupItemBearerSUReq, + id-E-RABToBeSetupItemCtxtSUReq, + id-E-RABToBeSetupItemHOReq, + id-E-RABToBeSetupListBearerSUReq, + id-E-RABToBeSetupListCtxtSUReq, + id-E-RABToBeSetupListHOReq, + id-E-RABToBeSwitchedDLItem, + id-E-RABToBeSwitchedDLList, + id-E-RABToBeSwitchedULList, + id-E-RABToBeSwitchedULItem, + id-E-RABtoReleaseListHOCmd, + id-SecurityKey, + id-SecurityContext, + id-ServedGUMMEIs, + id-SONConfigurationTransferECT, + id-SONConfigurationTransferMCT, + id-Source-ToTarget-TransparentContainer, + id-Source-ToTarget-TransparentContainer-Secondary, + id-SourceMME-UE-S1AP-ID, + id-SRVCCOperationPossible, + id-SRVCCHOIndication, + id-SubscriberProfileIDforRFP, + id-SupportedTAs, + id-S-TMSI, + id-TAI, + id-TAIItem, + id-TAIList, + id-Target-ToSource-TransparentContainer, + id-Target-ToSource-TransparentContainer-Secondary, + id-TargetID, + id-TimeToWait, + id-TraceActivation, + id-E-UTRAN-Trace-ID, + id-UEIdentityIndexValue, + id-UEPagingID, + id-UERadioCapability, + id-UTRANtoLTEHOInformationRes, + id-UE-associatedLogicalS1-ConnectionListResAck, + id-UE-associatedLogicalS1-ConnectionItem, + id-UESecurityCapabilities, + id-UE-S1AP-IDs, + id-ResetType, + id-MessageIdentifier, + id-SerialNumber, + id-WarningAreaList, + id-RepetitionPeriod, + id-NumberofBroadcastRequest, + id-WarningType, + id-WarningSecurityInfo, + id-DataCodingScheme, + id-WarningMessageContents, + id-BroadcastCompletedAreaList, + id-RRC-Establishment-Cause, + id-TraceCollectionEntityIPAddress, + maxnoofTAIs, + maxNrOfErrors, + maxNrOfE-RABs, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofEmergencyAreaID, + maxnoofCellID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI + + +FROM S1AP-Constants; + + +-- ************************************************************** +-- +-- Common Container Lists +-- +-- ************************************************************** + +E-RAB-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } +E-RAB-IE-ContainerPairList { S1AP-PROTOCOL-IES-PAIR : IEsSetParam } ::= ProtocolIE-ContainerPairList { 1, maxNrOfE-RABs, {IEsSetParam} } +ProtocolError-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } + +-- ************************************************************** +-- +-- HANDOVER PREPARATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Required +-- +-- ************************************************************** + +HandoverRequired ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverRequiredIEs} }, + ... +} + +HandoverRequiredIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-TargetID CRITICALITY reject TYPE TargetID PRESENCE mandatory } | + { ID id-Direct-Forwarding-Path-Availability CRITICALITY ignore TYPE Direct-Forwarding-Path-Availability PRESENCE optional } | + { ID id-SRVCCHOIndication CRITICALITY reject TYPE SRVCCHOIndication PRESENCE optional }| + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory }| + { ID id-Source-ToTarget-TransparentContainer-Secondary CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE optional }| + { ID id-MSClassmark2 CRITICALITY reject TYPE MSClassmark2 PRESENCE conditional }| + { ID id-MSClassmark3 CRITICALITY ignore TYPE MSClassmark3 PRESENCE conditional }, + ... +} + + +-- ************************************************************** +-- +-- Handover Command +-- +-- ************************************************************** + +HandoverCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCommandIEs} }, + ... +} + +HandoverCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-NASSecurityParametersfromE-UTRAN CRITICALITY reject TYPE NASSecurityParametersfromE-UTRAN PRESENCE conditional + -- This IE shall be present if HandoverType IE is set to value "LTEtoUTRAN" or "LTEtoGERAN" -- }| + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-E-RABtoReleaseListHOCmd CRITICALITY ignore TYPE E-RABList PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-Target-ToSource-TransparentContainer-Secondary CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABDataForwardingList ::= E-RAB-IE-ContainerList { {E-RABDataForwardingItemIEs} } + +E-RABDataForwardingItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABDataForwardingItem CRITICALITY ignore TYPE E-RABDataForwardingItem PRESENCE mandatory }, + ... +} + +E-RABDataForwardingItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { { E-RABDataForwardingItem-ExtIEs} } OPTIONAL, + ... +} + +E-RABDataForwardingItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- Handover Preparation Failure +-- +-- ************************************************************** + +HandoverPreparationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverPreparationFailureIEs} }, + ... +} + +HandoverPreparationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER RESOURCE ALLOCATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Request +-- +-- ************************************************************** + +HandoverRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestIEs} }, + ... +} + +HandoverRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory }| + { ID id-E-RABToBeSetupListHOReq CRITICALITY reject TYPE E-RABToBeSetupListHOReq PRESENCE mandatory } | + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory } | + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory }| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional }| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional }| + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE optional }| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional }| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-NASSecurityParameterstoE-UTRAN CRITICALITY reject TYPE NASSecurityParameterstoE-UTRAN PRESENCE conditional + -- This IE shall be present if the Handover Type IE is set to the value "UTRANtoLTE" or "GERANtoLTE" -- }, + ... +} + +E-RABToBeSetupListHOReq ::= E-RAB-IE-ContainerList { {E-RABToBeSetupItemHOReqIEs} } + +E-RABToBeSetupItemHOReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemHOReq CRITICALITY reject TYPE E-RABToBeSetupItemHOReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemHOReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + e-RABlevelQosParameters E-RABLevelQoSParameters, + iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemHOReq-ExtIEs} } OPTIONAL, + ... +} + +E-RABToBeSetupItemHOReq-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- Handover Request Acknowledge +-- +-- ************************************************************** + +HandoverRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestAcknowledgeIEs} }, + ... +} + +HandoverRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABAdmittedList CRITICALITY ignore TYPE E-RABAdmittedList PRESENCE mandatory } | + { ID id-E-RABFailedToSetupListHOReqAck CRITICALITY ignore TYPE E-RABFailedtoSetupListHOReqAck PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABAdmittedList ::= E-RAB-IE-ContainerList { {E-RABAdmittedItemIEs} } + +E-RABAdmittedItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABAdmittedItem CRITICALITY ignore TYPE E-RABAdmittedItem PRESENCE mandatory }, + ... +} + +E-RABAdmittedItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {E-RABAdmittedItem-ExtIEs} } OPTIONAL, + ... +} + +E-RABAdmittedItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABFailedtoSetupListHOReqAck ::= E-RAB-IE-ContainerList { {E-RABFailedtoSetupItemHOReqAckIEs} } + +E-RABFailedtoSetupItemHOReqAckIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABFailedtoSetupItemHOReqAck CRITICALITY ignore TYPE E-RABFailedToSetupItemHOReqAck PRESENCE mandatory }, + ... +} + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + iE-Extensions ProtocolExtensionContainer { { E-RABFailedToSetupItemHOReqAckExtIEs} } OPTIONAL, + ... +} + +E-RABFailedToSetupItemHOReqAckExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Handover Failure +-- +-- ************************************************************** + +HandoverFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverFailureIEs} }, + ... +} + +HandoverFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER NOTIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Notify +-- +-- ************************************************************** + +HandoverNotify ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverNotifyIEs} }, + ... +} + +HandoverNotifyIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- PATH SWITCH REQUEST ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Path Switch Request +-- +-- ************************************************************** + +PathSwitchRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestIEs} }, + ... +} + +PathSwitchRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABToBeSwitchedDLList CRITICALITY reject TYPE E-RABToBeSwitchedDLList PRESENCE mandatory }| + { ID id-SourceMME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY ignore TYPE UESecurityCapabilities PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedDLList ::= SEQUENCE (SIZE (0..maxProtocolIEs)) OF E-RAB-IE-ContainerList { {E-RABToBeSwitchedDLItemIEs} } + +E-RABToBeSwitchedDLItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedDLItem CRITICALITY reject TYPE E-RABToBeSwitchedDLItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedDLItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedDLItem-ExtIEs} } OPTIONAL, + ... +} + +E-RABToBeSwitchedDLItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- Path Switch Request Acknowledge +-- +-- ************************************************************** + +PathSwitchRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestAcknowledgeIEs} }, + ... +} + +PathSwitchRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeSwitchedULList CRITICALITY ignore TYPE E-RABToBeSwitchedULList PRESENCE optional }| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABToBeSwitchedULList ::= E-RAB-IE-ContainerList { {E-RABToBeSwitchedULItemIEs} } + +E-RABToBeSwitchedULItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedULItem CRITICALITY ignore TYPE E-RABToBeSwitchedULItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedULItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { { E-RABToBeSwitchedULItem-ExtIEs} } OPTIONAL, + ... +} + +E-RABToBeSwitchedULItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Path Switch Request Failure +-- +-- ************************************************************** + +PathSwitchRequestFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestFailureIEs} }, + ... +} + +PathSwitchRequestFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER CANCEL ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Cancel +-- +-- ************************************************************** + +HandoverCancel ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelIEs} }, + ... +} + +HandoverCancelIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Handover Cancel Request Acknowledge +-- +-- ************************************************************** + +HandoverCancelAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelAcknowledgeIEs} }, + ... +} + +HandoverCancelAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- E-RAB SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Setup Request +-- +-- ************************************************************** + +E-RABSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupRequestIEs} }, + ... +} + +E-RABSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeSetupListBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupListBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemBearerSUReqIEs} } + +E-RABToBeSetupItemBearerSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupItemBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemBearerSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU, + iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemBearerSUReqExtIEs} } OPTIONAL, + ... +} + + +E-RABToBeSetupItemBearerSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- E-RAB Setup Response +-- +-- ************************************************************** + +E-RABSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupResponseIEs} }, + ... +} + +E-RABSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListBearerSURes CRITICALITY ignore TYPE E-RABSetupListBearerSURes PRESENCE optional }| + { ID id-E-RABFailedToSetupListBearerSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemBearerSUResIEs} } + +E-RABSetupItemBearerSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemBearerSURes CRITICALITY ignore TYPE E-RABSetupItemBearerSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemBearerSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { {E-RABSetupItemBearerSUResExtIEs} } OPTIONAL, + ... +} + + +E-RABSetupItemBearerSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB MODIFY ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Modify Request +-- +-- ************************************************************** + +E-RABModifyRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyRequestIEs} }, + ... +} + +E-RABModifyRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeModifiedListBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedListBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeModifiedItemBearerModReqIEs} } + +E-RABToBeModifiedItemBearerModReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeModifiedItemBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedItemBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifiedItemBearerModReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABLevelQoSParameters E-RABLevelQoSParameters, + nAS-PDU NAS-PDU, + iE-Extensions ProtocolExtensionContainer { {E-RABToBeModifyItemBearerModReqExtIEs} } OPTIONAL, + ... +} + + +E-RABToBeModifyItemBearerModReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB Modify Response +-- +-- ************************************************************** + +E-RABModifyResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyResponseIEs} }, + ... +} + +E-RABModifyResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABModifyListBearerModRes CRITICALITY ignore TYPE E-RABModifyListBearerModRes PRESENCE optional }| + { ID id-E-RABFailedToModifyList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABModifyItemBearerModResIEs} } + +E-RABModifyItemBearerModResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABModifyItemBearerModRes CRITICALITY ignore TYPE E-RABModifyItemBearerModRes PRESENCE mandatory }, + ... +} + +E-RABModifyItemBearerModRes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions ProtocolExtensionContainer { {E-RABModifyItemBearerModResExtIEs} } OPTIONAL, + ... +} + + +E-RABModifyItemBearerModResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + + +-- ************************************************************** +-- +-- E-RAB RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Command +-- +-- ************************************************************** + +E-RABReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseCommandIEs} }, + ... +} + +E-RABReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }| + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- E-RAB Release Response +-- +-- ************************************************************** + +E-RABReleaseResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { E-RABReleaseResponseIEs } }, + ... +} + +E-RABReleaseResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleaseListBearerRelComp CRITICALITY ignore TYPE E-RABReleaseListBearerRelComp PRESENCE optional }| + { ID id-E-RABFailedToReleaseList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABReleaseItemBearerRelCompIEs} } + +E-RABReleaseItemBearerRelCompIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABReleaseItemBearerRelComp CRITICALITY ignore TYPE E-RABReleaseItemBearerRelComp PRESENCE mandatory }, + ... +} + +E-RABReleaseItemBearerRelComp ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions ProtocolExtensionContainer { {E-RABReleaseItemBearerRelCompExtIEs} } OPTIONAL, + ... +} + + +E-RABReleaseItemBearerRelCompExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB RELEASE INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Indication +-- +-- ************************************************************** + +E-RABReleaseIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseIndicationIEs} }, + ... +} + +E-RABReleaseIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }, + ... +} +-- ************************************************************** +-- +-- INITIAL CONTEXT SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Initial Context Setup Request +-- +-- ************************************************************** + +InitialContextSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupRequestIEs} }, + ... +} + +InitialContextSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory }| + { ID id-E-RABToBeSetupListCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupListCtxtSUReq PRESENCE mandatory }| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory }| + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE mandatory }| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional }| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional }| + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE optional }| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional }| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional }| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional }, + ... +} + + + + +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemCtxtSUReqIEs} } + +E-RABToBeSetupItemCtxtSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupItemCtxtSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemCtxtSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU OPTIONAL, + iE-Extensions ProtocolExtensionContainer { {E-RABToBeSetupItemCtxtSUReqExtIEs} } OPTIONAL, + ... +} + + +E-RABToBeSetupItemCtxtSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Initial Context Setup Response +-- +-- ************************************************************** + +InitialContextSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupResponseIEs} }, + ... +} + +InitialContextSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListCtxtSURes CRITICALITY ignore TYPE E-RABSetupListCtxtSURes PRESENCE mandatory }| + { ID id-E-RABFailedToSetupListCtxtSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemCtxtSUResIEs} } + +E-RABSetupItemCtxtSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemCtxtSURes CRITICALITY ignore TYPE E-RABSetupItemCtxtSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemCtxtSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions ProtocolExtensionContainer { {E-RABSetupItemCtxtSUResExtIEs} } OPTIONAL, + ... +} + + +E-RABSetupItemCtxtSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Initial Context Setup Failure +-- +-- ************************************************************** + +InitialContextSetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupFailureIEs} }, + ... +} + +InitialContextSetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- PAGING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + + +-- ************************************************************** +-- +-- Paging +-- +-- ************************************************************** + +Paging ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{PagingIEs}}, + ... +} + +PagingIEs S1AP-PROTOCOL-IES ::= { + { ID id-UEIdentityIndexValue CRITICALITY ignore TYPE UEIdentityIndexValue PRESENCE mandatory } | + { ID id-UEPagingID CRITICALITY ignore TYPE UEPagingID PRESENCE mandatory } | + { ID id-pagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional } | + { ID id-CNDomain CRITICALITY ignore TYPE CNDomain PRESENCE mandatory } | + { ID id-TAIList CRITICALITY ignore TYPE TAIList PRESENCE mandatory }| + { ID id-CSG-IdList CRITICALITY ignore TYPE CSG-IdList PRESENCE optional }, + ... +} + +TAIList::= SEQUENCE (SIZE(1.. maxnoofTAIs)) OF ProtocolIE-SingleContainer {{TAIItemIEs}} + +TAIItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-TAIItem CRITICALITY ignore TYPE TAIItem PRESENCE mandatory }, + ... +} + +TAIItem ::= SEQUENCE { + tAI TAI, + iE-Extensions ProtocolExtensionContainer { {TAIItemExtIEs} } OPTIONAL, + ... +} + + +TAIItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE REQUEST +-- +-- ************************************************************** + +UEContextReleaseRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseRequest-IEs}}, + ... +} + +UEContextReleaseRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UE Context Release Command +-- +-- ************************************************************** + +UEContextReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseCommand-IEs}}, + ... +} + +UEContextReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-S1AP-IDs CRITICALITY reject TYPE UE-S1AP-IDs PRESENCE mandatory} | + + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UE Context Release Complete +-- +-- ************************************************************** + +UEContextReleaseComplete ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseComplete-IEs}}, + ... +} + +UEContextReleaseCompleteIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- UE CONTEXT MODIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Context Modification Request +-- +-- ************************************************************** + +UEContextModificationRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationRequestIEs} }, + ... +} + +UEContextModificationRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE optional }| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional }| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- UE Context Modification Response +-- +-- ************************************************************** + +UEContextModificationResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationResponseIEs} }, + ... +} + +UEContextModificationResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +}-- ************************************************************** +-- +-- UE Context Modification Failure +-- +-- ************************************************************** + +UEContextModificationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationFailureIEs} }, + ... +} + +UEContextModificationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- NAS TRANSPORT ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DOWNLINK NAS TRANSPORT +-- +-- ************************************************************** + +DownlinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkNASTransport-IEs}}, + ... +} + +DownlinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- INITIAL UE MESSAGE +-- +-- ************************************************************** + +InitialUEMessage ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{InitialUEMessage-IEs}}, + ... +} + +InitialUEMessageIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-TAI CRITICALITY reject TYPE TAI PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-RRC-Establishment-Cause CRITICALITY ignore TYPE RRC-Establishment-Cause PRESENCE mandatory} | + { ID id-S-TMSI CRITICALITY reject TYPE S-TMSI PRESENCE optional} | + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional} | + { ID id-GUMMEI-ID CRITICALITY reject TYPE GUMMEI PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- UPLINK NAS TRANSPORT +-- +-- ************************************************************** + +UplinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkNASTransport-IEs}}, + ... +} + +UplinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}, + ... +} +-- ************************************************************** +-- +-- NAS NON DELIVERY INDICATION +-- +-- ************************************************************** + +NASNonDeliveryIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{NASNonDeliveryIndication-IEs}}, + ... +} + +NASNonDeliveryIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- RESET ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Reset +-- +-- ************************************************************** + +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetIEs} }, + ... +} + +ResetIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory }, + ... +} + +ResetType ::= CHOICE { + s1-Interface ResetAll, + partOfS1-Interface UE-associatedLogicalS1-ConnectionListRes, + ... +} + + + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemRes } } + +UE-associatedLogicalS1-ConnectionItemRes S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY reject TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- Reset Acknowledge +-- +-- ************************************************************** + +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetAcknowledgeIEs} }, + ... +} + +ResetAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionListResAck CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionListResAck PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemResAck } } + +UE-associatedLogicalS1-ConnectionItemResAck S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- ERROR INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Error Indication +-- +-- ************************************************************** + +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndicationIEs}}, + ... +} + +ErrorIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE optional } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + +-- ************************************************************** +-- +-- S1 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- S1 Setup Request +-- +-- ************************************************************** + +S1SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupRequestIEs} }, + ... +} + +S1SetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-Global-ENB-ID CRITICALITY reject TYPE Global-ENB-ID PRESENCE mandatory}| + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional}| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE mandatory}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE mandatory}| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Response +-- +-- ************************************************************** + +S1SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupResponseIEs} }, + ... +} + + +S1SetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional }| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE mandatory }| + { ID id-RelativeMMECapacity CRITICALITY ignore TYPE RelativeMMECapacity PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Failure +-- +-- ************************************************************** + +S1SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupFailureIEs} }, + ... +} + +S1SetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Update +-- +-- ************************************************************** + +ENBConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateIEs} }, + ... +} + +ENBConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional }| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE optional }| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Acknowledge +-- +-- ************************************************************** + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +ENBConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Failure +-- +-- ************************************************************** + +ENBConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateFailureIEs} }, + ... +} + +ENBConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, +... +} + + +-- ************************************************************** +-- +-- MME Configuration UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Update +-- +-- ************************************************************** + +MMEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateIEs} }, + ... +} + +MMEConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional }| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE optional }| + { ID id-RelativeMMECapacity CRITICALITY reject TYPE RelativeMMECapacity PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Acknowledge +-- +-- ************************************************************** + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +MMEConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Failure +-- +-- ************************************************************** + +MMEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateFailureIEs} }, + ... +} + +MMEConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- DOWNLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Downlink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {DownlinkS1cdma2000tunnelingIEs} }, + ... +} + +DownlinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-cdma2000HOStatus CRITICALITY ignore TYPE Cdma2000HOStatus PRESENCE optional } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- UPLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Uplink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +UplinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {UplinkS1cdma2000tunnelingIEs} }, + ... +} + +UplinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000SectorID CRITICALITY reject TYPE Cdma2000SectorID PRESENCE mandatory } | + { ID id-cdma2000HORequiredIndication CRITICALITY ignore TYPE Cdma2000HORequiredIndication PRESENCE optional } | + { ID id-cdma2000OneXSRVCCInfo CRITICALITY reject TYPE Cdma2000OneXSRVCCInfo PRESENCE optional } | + { ID id-cdma2000OneXRAND CRITICALITY reject TYPE Cdma2000OneXRAND PRESENCE optional } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- UE CAPABILITY INFO INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Capability Info Indication +-- +-- ************************************************************** + +UECapabilityInfoIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UECapabilityInfoIndicationIEs} }, + ... +} + +UECapabilityInfoIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- eNB STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Status Transfer +-- +-- ************************************************************** + +ENBStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBStatusTransferIEs} }, + ... +} + +ENBStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- MME STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Status Transfer +-- +-- ************************************************************** + +MMEStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEStatusTransferIEs} }, + ... +} + +MMEStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- TRACE ELEMENTARY PROCEDURES +-- +-- ************************************************************** +-- ************************************************************** +-- +-- Trace Start +-- +-- ************************************************************** + +TraceStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceStartIEs} }, + ... +} + +TraceStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Trace Failure Indication +-- +-- ************************************************************** + +TraceFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceFailureIndicationIEs} }, + ... +} + +TraceFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- DEACTIVATE TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DEACTIVATE TRACE +-- +-- ************************************************************** + +DeactivateTrace ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { DeactivateTraceIEs} }, + ... +} + +DeactivateTraceIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE +-- +-- ************************************************************** + +CellTrafficTrace ::= SEQUENCE { +protocolIEs ProtocolIE-Container { { CellTrafficTraceIEs } }, +... +} + +CellTrafficTraceIEs S1AP-PROTOCOL-IES ::= { + {ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + {ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + {ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory}| + {ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + {ID id-TraceCollectionEntityIPAddress CRITICALITY ignore TYPE TransportLayerAddress PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- LOCATION ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Location Reporting Control +-- +-- ************************************************************** + +LocationReportingControl ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingControlIEs} }, + ... +} + +LocationReportingControlIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- Location Report Failure Indication +-- +-- ************************************************************** + +LocationReportingFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingFailureIndicationIEs} }, + ... +} + +LocationReportingFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- Location Report +-- +-- ************************************************************** + +LocationReport ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportIEs} }, + ... +} + +LocationReportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- OVERLOAD ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Overload Start +-- +-- ************************************************************** + +OverloadStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStartIEs} }, + ... +} + +OverloadStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-OverloadResponse CRITICALITY reject TYPE OverloadResponse PRESENCE mandatory }, + ... +} +-- ************************************************************** +-- +-- Overload Stop +-- +-- ************************************************************** + +OverloadStop ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStopIEs} }, + ... +} + +OverloadStopIEs S1AP-PROTOCOL-IES ::= { + ... +} +-- ************************************************************** +-- +-- WRITE-REPLACE WARNING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Write-Replace Warning Request +-- +-- ************************************************************** + + +WriteReplaceWarningRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningRequestIEs} }, + ... +} + +WriteReplaceWarningRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-WarningAreaList CRITICALITY ignore TYPE WarningAreaList PRESENCE optional }| + { ID id-RepetitionPeriod CRITICALITY reject TYPE RepetitionPeriod PRESENCE mandatory }| + { ID id-NumberofBroadcastRequest CRITICALITY reject TYPE NumberofBroadcastRequest PRESENCE mandatory }| + { ID id-WarningType CRITICALITY ignore TYPE WarningType PRESENCE optional }| + { ID id-WarningSecurityInfo CRITICALITY ignore TYPE WarningSecurityInfo PRESENCE optional }| + { ID id-DataCodingScheme CRITICALITY ignore TYPE DataCodingScheme PRESENCE optional }| + { ID id-WarningMessageContents CRITICALITY ignore TYPE WarningMessageContents PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- Write-Replace Warning Response +-- +-- ************************************************************** + +WriteReplaceWarningResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningResponseIEs} }, + ... +} + +WriteReplaceWarningResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-BroadcastCompletedAreaList CRITICALITY ignore TYPE BroadcastCompletedAreaList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- eNB DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Direct Information Transfer +-- +-- ************************************************************** + +ENBDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBDirectInformationTransferIEs}}, + ... +} + +ENBDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeEDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} + +Inter-SystemInformationTransferType ::= CHOICE { + rIMTransfer RIMTransfer, + ... +} + +-- ************************************************************** +-- +-- MME DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Direct Information Transfer +-- +-- ************************************************************** + +MMEDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEDirectInformationTransferIEs}}, + ... +} + +MMEDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeMDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} +-- ************************************************************** +-- +-- eNB CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Transfer +-- +-- ************************************************************** + +ENBConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBConfigurationTransferIEs}}, + ... +} + +ENBConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferECT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- MME CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Transfer +-- +-- ************************************************************** + +MMEConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEConfigurationTransferIEs}}, + ... +} + +MMEConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferMCT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- PRIVATE MESSAGE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Private Message +-- +-- ************************************************************** + +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessageIEs}}, + ... +} + +PrivateMessageIEs S1AP-PRIVATE-IES ::= { + ... +} + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU.asn b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU.asn new file mode 100644 index 0000000000..d2c50b417c --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R8.10/S1AP-PDU.asn @@ -0,0 +1,663 @@ +S1AP-PDU { + itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) + eps-Access (21) modules (3) s1ap (1) version1 (1) +} + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + + UEAggregateMaximumBitrate, + Cause, + Cdma2000HORequiredIndication, + Cdma2000HOStatus, + Cdma2000OneXSRVCCInfo, + Cdma2000OneXRAND, + Cdma2000PDU, + Cdma2000RATType, + Cdma2000SectorID, + CNDomain, + CriticalityDiagnostics, + CSFallbackIndicator, + CSG-Id, + CSG-IdList, + Direct-Forwarding-Path-Availability, + Global-ENB-ID, + EUTRAN-CGI, + ENBname, + ENB-StatusTransfer-TransparentContainer, + ENB-UE-S1AP-ID, + GTP-TEID, + GUMMEI, + HandoverRestrictionList, + HandoverType, + MMEname, + MME-UE-S1AP-ID, + MSClassmark2, + MSClassmark3, + NAS-PDU, + NASSecurityParametersfromE-UTRAN, + NASSecurityParameterstoE-UTRAN, + OverloadResponse, + PagingDRX, + PLMNidentity, + RIMTransfer, + RelativeMMECapacity, + RequestType, + E-RAB-ID, + E-RABLevelQoSParameters, + E-RABList, + SecurityKey, + SecurityContext, + ServedGUMMEIs, + SONConfigurationTransfer, + Source-ToTarget-TransparentContainer, + SourceBSS-ToTargetBSS-TransparentContainer, + SourceeNB-ToTargeteNB-TransparentContainer, + SourceRNC-ToTargetRNC-TransparentContainer, + SubscriberProfileIDforRFP, + SRVCCOperationPossible, + SRVCCHOIndication, + SupportedTAs, + TAI, + Target-ToSource-TransparentContainer, + TargetBSS-ToSourceBSS-TransparentContainer, + TargeteNB-ToSourceeNB-TransparentContainer, + TargetID, + TargetRNC-ToSourceRNC-TransparentContainer, + TimeToWait, + TraceActivation, + E-UTRAN-Trace-ID, + TransportLayerAddress, + UEIdentityIndexValue, + UEPagingID, + UERadioCapability, + UE-S1AP-IDs, + UE-associatedLogicalS1-ConnectionItem, + UESecurityCapabilities, + S-TMSI, + MessageIdentifier, + SerialNumber, + WarningAreaList, + RepetitionPeriod, + NumberofBroadcastRequest, + WarningType, + WarningSecurityInfo, + DataCodingScheme, + WarningMessageContents, + BroadcastCompletedAreaList, + RRC-Establishment-Cause + +FROM S1AP-IEs + + ProcedureCode, + Criticality, + ProtocolIE-ID + +FROM S1AP-CommonDataTypes + + + id-uEaggregateMaximumBitrate, + id-Cause, + id-cdma2000HORequiredIndication, + id-cdma2000HOStatus, + id-cdma2000OneXSRVCCInfo, + id-cdma2000OneXRAND, + id-cdma2000PDU, + id-cdma2000RATType, + id-cdma2000SectorID, + id-CNDomain, + id-CriticalityDiagnostics, + id-CSFallbackIndicator, + id-CSG-Id, + id-CSG-IdList, + id-DefaultPagingDRX, + id-Direct-Forwarding-Path-Availability, + id-Global-ENB-ID, + id-EUTRAN-CGI, + id-eNBname, + id-eNB-StatusTransfer-TransparentContainer, + id-eNB-UE-S1AP-ID, + id-GERANtoLTEHOInformationRes, + id-GUMMEI-ID, + id-HandoverRestrictionList, + id-HandoverType, + id-InitialContextSetup, + id-Inter-SystemInformationTransferTypeEDT, + id-Inter-SystemInformationTransferTypeMDT, + id-NAS-DownlinkCount, + id-MMEname, + id-MME-UE-S1AP-ID, + id-MSClassmark2, + id-MSClassmark3, + id-NAS-PDU, + id-NASSecurityParametersfromE-UTRAN, + id-NASSecurityParameterstoE-UTRAN, + id-OverloadResponse, + id-pagingDRX, + id-RelativeMMECapacity, + id-RequestType, + id-E-RABAdmittedItem, + id-E-RABAdmittedList, + id-E-RABDataForwardingItem, + id-E-RABFailedToModifyList, + id-E-RABFailedToReleaseList, + id-E-RABFailedtoSetupItemHOReqAck, + id-E-RABFailedToSetupListBearerSURes, + id-E-RABFailedToSetupListCtxtSURes, + id-E-RABFailedToSetupListHOReqAck, + id-E-RABFailedToBeReleasedList, + id-E-RABModify, + id-E-RABModifyItemBearerModRes, + id-E-RABModifyListBearerModRes, + id-E-RABRelease, + id-E-RABReleaseItemBearerRelComp, + id-E-RABReleaseItemHOCmd, + id-E-RABReleaseListBearerRelComp, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-E-RABSetupItemBearerSURes, + id-E-RABSetupItemCtxtSURes, + id-E-RABSetupListBearerSURes, + id-E-RABSetupListCtxtSURes, + id-E-RABSubjecttoDataForwardingList, + id-E-RABToBeModifiedItemBearerModReq, + id-E-RABToBeModifiedListBearerModReq, + id-E-RABToBeReleasedList, + id-E-RABReleasedList, + id-E-RABToBeSetupItemBearerSUReq, + id-E-RABToBeSetupItemCtxtSUReq, + id-E-RABToBeSetupItemHOReq, + id-E-RABToBeSetupListBearerSUReq, + id-E-RABToBeSetupListCtxtSUReq, + id-E-RABToBeSetupListHOReq, + id-E-RABToBeSwitchedDLItem, + id-E-RABToBeSwitchedDLList, + id-E-RABToBeSwitchedULList, + id-E-RABToBeSwitchedULItem, + id-E-RABtoReleaseListHOCmd, + id-SecurityKey, + id-SecurityContext, + id-ServedGUMMEIs, + id-SONConfigurationTransferECT, + id-SONConfigurationTransferMCT, + id-Source-ToTarget-TransparentContainer, + id-Source-ToTarget-TransparentContainer-Secondary, + id-SourceMME-UE-S1AP-ID, + id-SRVCCOperationPossible, + id-SRVCCHOIndication, + id-SubscriberProfileIDforRFP, + id-SupportedTAs, + id-S-TMSI, + id-TAI, + id-TAIItem, + id-TAIList, + id-Target-ToSource-TransparentContainer, + id-Target-ToSource-TransparentContainer-Secondary, + id-TargetID, + id-TimeToWait, + id-TraceActivation, + id-E-UTRAN-Trace-ID, + id-UEIdentityIndexValue, + id-UEPagingID, + id-UERadioCapability, + id-UTRANtoLTEHOInformationRes, + id-UE-associatedLogicalS1-ConnectionListResAck, + id-UE-associatedLogicalS1-ConnectionItem, + id-UESecurityCapabilities, + id-UE-S1AP-IDs, + id-ResetType, + id-MessageIdentifier, + id-SerialNumber, + id-WarningAreaList, + id-RepetitionPeriod, + id-NumberofBroadcastRequest, + id-WarningType, + id-WarningSecurityInfo, + id-DataCodingScheme, + id-WarningMessageContents, + id-BroadcastCompletedAreaList, + id-RRC-Establishment-Cause, + id-TraceCollectionEntityIPAddress, + maxnoofTAIs, + maxNrOfErrors, + maxNrOfE-RABs, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofEmergencyAreaID, + maxnoofCellID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + + id-CellTrafficTrace, + id-DeactivateTrace, + id-downlinkNASTransport, + id-DownlinkS1cdma2000tunneling, + id-eNBStatusTransfer, + id-ErrorIndication, + id-HandoverCancel, + id-HandoverNotification, + id-HandoverPreparation, + id-HandoverResourceAllocation, + id-InitialContextSetup, + id-initialUEMessage, + id-ENBConfigurationUpdate, + id-LocationReportingControl, + id-LocationReportingFailureIndication, + id-LocationReport, + id-eNBDirectInformationTransfer, + id-MMEConfigurationUpdate, + id-MMEDirectInformationTransfer, + id-MMEStatusTransfer, + id-NASNonDeliveryIndication, + id-OverloadStart, + id-OverloadStop, + id-Paging, + id-PathSwitchRequest, + id-PrivateMessage, + id-Reset, + id-S1Setup, + id-E-RABModify, + id-E-RABRelease, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-TraceFailureIndication, + id-TraceStart, + id-UECapabilityInfoIndication, + id-UEContextModification, + id-UEContextRelease, + id-UEContextReleaseRequest, + id-uplinkNASTransport, + id-UplinkS1cdma2000tunneling, + id-WriteReplaceWarning, + id-eNBConfigurationTransfer, + id-MMEConfigurationTransfer, + maxProtocolIEs +FROM S1AP-Constants; + +-- ************************************************************** +-- +-- S1 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +S1AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} + +S1AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +HandoverRequired ::= SEQUENCE { + handoverRequired-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCommand ::= SEQUENCE { + handoverCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverPreparationFailure ::= SEQUENCE { + handoverPreparationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequest ::= SEQUENCE { + handoverRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequestAcknowledge ::= SEQUENCE { + handoverRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverFailure ::= SEQUENCE { + handoverFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverNotify ::= SEQUENCE { + handoverNotify-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequest ::= SEQUENCE { + pathSwitchRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestAcknowledge ::= SEQUENCE { + pathSwitchRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestFailure ::= SEQUENCE { + pathSwitchRequestFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupRequest ::= SEQUENCE { + e-RABSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupResponse ::= SEQUENCE { + e-RABSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyRequest ::= SEQUENCE { + e-RABModifyRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyResponse ::= SEQUENCE { + e-RABModifyResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseIndication ::= SEQUENCE { + e-RABReleaseIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseCommand ::= SEQUENCE { + e-RABReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseResponse ::= SEQUENCE { + e-RABReleaseResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupRequest ::= SEQUENCE { + initialContextSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupResponse ::= SEQUENCE { + initialContextSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupFailure ::= SEQUENCE { + initialContextSetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseRequest ::= SEQUENCE { + ueContextReleaseRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Paging ::= SEQUENCE { + paging-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkNASTransport ::= SEQUENCE { + downlinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialUEMessage ::= SEQUENCE { + initialUEMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkNASTransport ::= SEQUENCE { + uplinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +NASNonDeliveryIndication ::= SEQUENCE { + nasNonDeliveryIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancel ::= SEQUENCE { + handoverCancel-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancelAcknowledge ::= SEQUENCE { + handoverCancelAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Reset ::= SEQUENCE { + reset-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ResetAcknowledge ::= SEQUENCE { + resetAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupResponse ::= SEQUENCE { + s1SetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupRequest ::= SEQUENCE { + s1SetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupFailure ::= SEQUENCE +{ + s1SetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ErrorIndication ::= SEQUENCE { + errorIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdate ::= SEQUENCE { + eNBConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + eNBConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateFailure ::= SEQUENCE { + eNBConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdate ::= SEQUENCE { + mmeConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + mmeConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateFailure ::= SEQUENCE { + mmeConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + downlinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkS1cdma2000tunneling ::= SEQUENCE { + uplinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationRequest ::= SEQUENCE { + ueContextModificationRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationResponse ::= SEQUENCE { + ueContextModificationResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationFailure ::= SEQUENCE { + ueContextModificationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UECapabilityInfoIndication ::= SEQUENCE { + ueCapabilityInfoIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseCommand ::= SEQUENCE { + ueContextReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseComplete ::= SEQUENCE { + ueContextReleaseComplete-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBStatusTransfer ::= SEQUENCE { + eNBStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEStatusTransfer ::= SEQUENCE { + mmeStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DeactivateTrace ::= SEQUENCE { + deactivateTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceStart ::= SEQUENCE { + traceStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceFailureIndication ::= SEQUENCE { + traceFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +CellTrafficTrace ::= SEQUENCE { + cellTrafficTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingControl ::= SEQUENCE { + locationReportingControl-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingFailureIndication ::= SEQUENCE { + locationReportingFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReport ::= SEQUENCE { + locationReport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStart ::= SEQUENCE { + overloadStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStop ::= SEQUENCE { + overloadStop-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningRequest ::= SEQUENCE { + writeReplaceWarningRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningResponse ::= SEQUENCE { + writeReplaceWarningResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBDirectInformationTransfer ::= SEQUENCE { + eNBDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEDirectInformationTransfer ::= SEQUENCE { + mmeDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationTransfer ::= SEQUENCE { + eNBConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationTransfer ::= SEQUENCE { + mmeConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PrivateMessage ::= SEQUENCE { + privateMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +IE ::= SEQUENCE { + id ProtocolIE-ID, + criticality Criticality, + value ANY +} + +END diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-CommonDataTypes.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-CommonDataTypes.asn new file mode 100644 index 0000000000..b1295c34ff --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-CommonDataTypes.asn @@ -0,0 +1,217 @@ +-- ************************************************************** +-- +-- Common definitions +-- +-- ************************************************************** + +S1AP-CommonDataTypes { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-CommonDataTypes (3) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +Criticality ::= ENUMERATED { reject, ignore, notify } + +Presence ::= ENUMERATED { optional, conditional, mandatory } + +PrivateIE-ID ::= CHOICE { + local INTEGER (0..65535), + global OBJECT IDENTIFIER +} + +ProcedureCode ::= INTEGER { + id-HandoverPreparation(0), + id-HandoverResourceAllocation(1), + id-HandoverNotification(2), + id-PathSwitchRequest(3), + id-HandoverCancel(4), + id-E-RABSetup(5), + id-E-RABModify(6), + id-E-RABRelease(7), + id-E-RABReleaseIndication(8), + id-InitialContextSetup(9), + id-Paging(10), + id-downlinkNASTransport(11), + id-initialUEMessage(12), + id-uplinkNASTransport(13), + id-Reset(14), + id-ErrorIndication(15), + id-NASNonDeliveryIndication(16), + id-S1Setup(17), + id-UEContextReleaseRequest(18), + id-DownlinkS1cdma2000tunneling(19), + id-UplinkS1cdma2000tunneling(20), + id-UEContextModification(21), + id-UECapabilityInfoIndication(22), + id-UEContextRelease(23), + id-eNBStatusTransfer(24), + id-MMEStatusTransfer(25), + id-DeactivateTrace(26), + id-TraceStart(27), + id-TraceFailureIndication(28), + id-ENBConfigurationUpdate(29), + id-MMEConfigurationUpdate(30), + id-LocationReportingControl(31), + id-LocationReportingFailureIndication(32), + id-LocationReport(33), + id-OverloadStart(34), + id-OverloadStop(35), + id-WriteReplaceWarning(36), + id-eNBDirectInformationTransfer(37), + id-MMEDirectInformationTransfer(38), + id-PrivateMessage(39), + id-eNBConfigurationTransfer(40), + id-MMEConfigurationTransfer(41), + id-CellTrafficTrace(42), + id-Kill(43), + id-downlinkUEAssociatedLPPaTransport(44), + id-uplinkUEAssociatedLPPaTransport(45), + id-downlinkNonUEAssociatedLPPaTransport(46), + id-uplinkNonUEAssociatedLPPaTransport(47) +} (0..255) + +ProtocolExtensionID ::= INTEGER (0..65535) + +ProtocolIE-ID ::= INTEGER { + id-MME-UE-S1AP-ID(0), + id-HandoverType(1), + id-Cause(2), + id-SourceID(3), + id-TargetID (4), + id-eNB-UE-S1AP-ID(8), + id-E-RABSubjecttoDataForwardingList(12), + id-E-RABtoReleaseListHOCmd(13), + id-E-RABDataForwardingItem(14), + id-E-RABReleaseItemBearerRelComp(15), + id-E-RABToBeSetupListBearerSUReq(16), + id-E-RABToBeSetupItemBearerSUReq(17), + id-E-RABAdmittedList(18), + id-E-RABFailedToSetupListHOReqAck(19), + id-E-RABAdmittedItem(20), + id-E-RABFailedtoSetupItemHOReqAck(21), + id-E-RABToBeSwitchedDLList(22), + id-E-RABToBeSwitchedDLItem(23), + id-E-RABToBeSetupListCtxtSUReq(24), + id-TraceActivation(25), + id-NAS-PDU(26), + id-E-RABToBeSetupItemHOReq(27), + id-E-RABSetupListBearerSURes(28), + id-E-RABFailedToSetupListBearerSURes(29), + id-E-RABToBeModifiedListBearerModReq(30), + id-E-RABModifyListBearerModRes(31), + id-E-RABFailedToModifyList(32), + id-E-RABToBeReleasedList(33), + id-E-RABFailedToReleaseList(34), + id-E-RABItem(35), + id-E-RABToBeModifiedItemBearerModReq(36), + id-E-RABModifyItemBearerModRes(37), + id-E-RABReleaseItem(38), + id-E-RABSetupItemBearerSURes(39), + id-SecurityContext(40), + id-HandoverRestrictionList(41), + id-UEPagingID(43), + id-pagingDRX(44), + id-TAIList(46), + id-TAIItem(47), + id-E-RABFailedToSetupListCtxtSURes(48), + id-E-RABReleaseItemHOCmd(49), + id-E-RABSetupItemCtxtSURes(50), + id-E-RABSetupListCtxtSURes(51), + id-E-RABToBeSetupItemCtxtSUReq(52), + id-E-RABToBeSetupListHOReq(53), + id-GERANtoLTEHOInformationRes(55), + id-UTRANtoLTEHOInformationRes(57), + id-CriticalityDiagnostics(58), + id-Global-ENB-ID(59), + id-eNBname(60), + id-MMEname(61), + id-ServedPLMNs(63), + id-SupportedTAs(64), + id-TimeToWait(65), + id-uEaggregateMaximumBitrate(66), + id-TAI(67), + id-E-RABReleaseListBearerRelComp(69), + id-cdma2000PDU(70), + id-cdma2000RATType(71), + id-cdma2000SectorID(72), + id-SecurityKey(73), + id-UERadioCapability(74), + id-GUMMEI-ID(75), + id-E-RABInformationListItem(78), + id-Direct-Forwarding-Path-Availability(79), + id-UEIdentityIndexValue(80), + id-cdma2000HOStatus(83), + id-cdma2000HORequiredIndication(84), + id-E-UTRAN-Trace-ID(86), + id-RelativeMMECapacity(87), + id-SourceMME-UE-S1AP-ID(88), + id-Bearers-SubjectToStatusTransfer-Item(89), + id-eNB-StatusTransfer-TransparentContainer(90), + id-UE-associatedLogicalS1-ConnectionItem(91), + id-ResetType(92), + id-UE-associatedLogicalS1-ConnectionListResAck(93), + id-E-RABToBeSwitchedULItem(94), + id-E-RABToBeSwitchedULList(95), + id-S-TMSI(96), + id-cdma2000OneXRAND(97), + id-RequestType(98), + id-UE-S1AP-IDs(99), + id-EUTRAN-CGI(100), + id-OverloadResponse(101), + id-cdma2000OneXSRVCCInfo(102), + id-E-RABFailedToBeReleasedList(103), + id-Source-ToTarget-TransparentContainer(104), + id-ServedGUMMEIs(105), + id-SubscriberProfileIDforRFP(106), + id-UESecurityCapabilities(107), + id-CSFallbackIndicator(108), + id-CNDomain(109), + id-E-RABReleasedList(110), + id-MessageIdentifier(111), + id-SerialNumber(112), + id-WarningAreaList(113), + id-RepetitionPeriod(114), + id-NumberofBroadcastRequest(115), + id-WarningType(116), + id-WarningSecurityInfo(117), + id-DataCodingScheme(118), + id-WarningMessageContents(119), + id-BroadcastCompletedAreaList(120), + id-Inter-SystemInformationTransferTypeEDT(121), + id-Inter-SystemInformationTransferTypeMDT(122), + id-Target-ToSource-TransparentContainer(123), + id-SRVCCOperationPossible(124), + id-SRVCCHOIndication(125), + id-NAS-DownlinkCount(126), + id-CSG-Id(127), + id-CSG-IdList(128), + id-SONConfigurationTransferECT(129), + id-SONConfigurationTransferMCT(130), + id-TraceCollectionEntityIPAddress(131), + id-MSClassmark2(132), + id-MSClassmark3(133), + id-RRC-Establishment-Cause(134), + id-NASSecurityParametersfromE-UTRAN(135), + id-NASSecurityParameterstoE-UTRAN(136), + id-DefaultPagingDRX(137), + id-Source-ToTarget-TransparentContainer-Secondary(138), + id-Target-ToSource-TransparentContainer-Secondary(139), + id-EUTRANRoundTripDelayEstimationInfo(140), + id-BroadcastCancelledAreaList(141), + id-ConcurrentWarningMessageIndicator(142), + id-Data-Forwarding-Not-Possible(143), + id-ExtendedRepetitionPeriod(144), + id-CellAccessMode(145), + id-CSGMembershipStatus(146), + id-LPPa-PDU(147), + id-Routing-ID(148), + id-Time-Synchronization-Info(149), + id-PS-ServiceNotAvailable(150), + id-RegisteredLAI(159) +} (0..65535) + +TriggeringMessage ::= ENUMERATED { initiating-message, successful-outcome, unsuccessfull-outcome } + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Constants.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Constants.asn new file mode 100644 index 0000000000..d8b56eebb8 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Constants.asn @@ -0,0 +1,265 @@ +-- ************************************************************** +-- +-- Constant definitions +-- +-- ************************************************************** + +S1AP-Constants { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Constants (4) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + ProcedureCode, + ProtocolIE-ID + +FROM S1AP-CommonDataTypes; + + +-- ************************************************************** +-- +-- Elementary Procedures +-- +-- ************************************************************** + +id-HandoverPreparation ProcedureCode ::= 0 +id-HandoverResourceAllocation ProcedureCode ::= 1 +id-HandoverNotification ProcedureCode ::= 2 +id-PathSwitchRequest ProcedureCode ::= 3 +id-HandoverCancel ProcedureCode ::= 4 +id-E-RABSetup ProcedureCode ::= 5 +id-E-RABModify ProcedureCode ::= 6 +id-E-RABRelease ProcedureCode ::= 7 +id-E-RABReleaseIndication ProcedureCode ::= 8 +id-InitialContextSetup ProcedureCode ::= 9 +id-Paging ProcedureCode ::= 10 +id-downlinkNASTransport ProcedureCode ::= 11 +id-initialUEMessage ProcedureCode ::= 12 +id-uplinkNASTransport ProcedureCode ::= 13 +id-Reset ProcedureCode::= 14 +id-ErrorIndication ProcedureCode ::= 15 +id-NASNonDeliveryIndication ProcedureCode ::= 16 +id-S1Setup ProcedureCode ::= 17 +id-UEContextReleaseRequest ProcedureCode ::= 18 +id-DownlinkS1cdma2000tunneling ProcedureCode ::= 19 +id-UplinkS1cdma2000tunneling ProcedureCode ::= 20 +id-UEContextModification ProcedureCode ::= 21 +id-UECapabilityInfoIndication ProcedureCode ::= 22 +id-UEContextRelease ProcedureCode ::= 23 +id-eNBStatusTransfer ProcedureCode ::= 24 +id-MMEStatusTransfer ProcedureCode ::= 25 +id-DeactivateTrace ProcedureCode ::= 26 +id-TraceStart ProcedureCode ::= 27 +id-TraceFailureIndication ProcedureCode ::= 28 +id-ENBConfigurationUpdate ProcedureCode ::= 29 +id-MMEConfigurationUpdate ProcedureCode ::= 30 +id-LocationReportingControl ProcedureCode ::= 31 +id-LocationReportingFailureIndication ProcedureCode ::= 32 +id-LocationReport ProcedureCode ::= 33 +id-OverloadStart ProcedureCode ::= 34 +id-OverloadStop ProcedureCode ::= 35 +id-WriteReplaceWarning ProcedureCode ::= 36 +id-eNBDirectInformationTransfer ProcedureCode ::= 37 +id-MMEDirectInformationTransfer ProcedureCode ::= 38 +id-PrivateMessage ProcedureCode ::= 39 +id-eNBConfigurationTransfer ProcedureCode ::= 40 +id-MMEConfigurationTransfer ProcedureCode ::= 41 +id-CellTrafficTrace ProcedureCode ::= 42 +id-Kill ProcedureCode ::= 43 +id-downlinkUEAssociatedLPPaTransport ProcedureCode ::= 44 +id-uplinkUEAssociatedLPPaTransport ProcedureCode ::= 45 +id-downlinkNonUEAssociatedLPPaTransport ProcedureCode ::= 46 +id-uplinkNonUEAssociatedLPPaTransport ProcedureCode ::= 47 + +-- ************************************************************** +-- +-- Extension constants +-- +-- ************************************************************** + +maxPrivateIEs INTEGER ::= 65535 +maxProtocolExtensions INTEGER ::= 65535 +maxProtocolIEs INTEGER ::= 65535 +-- ************************************************************** +-- +-- Lists +-- +-- ************************************************************** + +maxNrOfCSGs INTEGER ::= 256 +maxNrOfE-RABs INTEGER ::= 256 +maxnoofTAIs INTEGER ::= 256 +maxnoofTACs INTEGER ::= 256 +maxNrOfErrors INTEGER ::= 256 +maxnoofBPLMNs INTEGER ::= 6 +maxnoofPLMNsPerMME INTEGER ::= 32 +maxnoofEPLMNs INTEGER ::= 15 +maxnoofEPLMNsPlusOne INTEGER ::= 16 +maxnoofForbLACs INTEGER ::= 4096 +maxnoofForbTACs INTEGER ::= 4096 +maxNrOfIndividualS1ConnectionsToReset INTEGER ::= 256 +maxnoofCells INTEGER ::= 16 +maxnoofTAIforWarning INTEGER ::= 65535 +maxnoofCellID INTEGER ::= 65535 +maxnoofEmergencyAreaID INTEGER ::= 65535 +maxnoofCellinTAI INTEGER ::= 65535 +maxnoofCellinEAI INTEGER ::= 65535 +maxnoofeNBX2TLAs INTEGER ::= 2 +maxnoofRATs INTEGER ::= 8 +maxnoofGroupIDs INTEGER ::= 65535 +maxnoofMMECs INTEGER ::= 256 + + + +-- ************************************************************** +-- +-- IEs +-- +-- ************************************************************** + +id-MME-UE-S1AP-ID ProtocolIE-ID ::= 0 +id-HandoverType ProtocolIE-ID ::= 1 +id-Cause ProtocolIE-ID ::= 2 +id-SourceID ProtocolIE-ID ::= 3 +id-TargetID ProtocolIE-ID ::= 4 +id-eNB-UE-S1AP-ID ProtocolIE-ID ::= 8 +id-E-RABSubjecttoDataForwardingList ProtocolIE-ID ::= 12 +id-E-RABtoReleaseListHOCmd ProtocolIE-ID ::= 13 +id-E-RABDataForwardingItem ProtocolIE-ID ::= 14 +id-E-RABReleaseItemBearerRelComp ProtocolIE-ID ::= 15 +id-E-RABToBeSetupListBearerSUReq ProtocolIE-ID ::= 16 +id-E-RABToBeSetupItemBearerSUReq ProtocolIE-ID ::= 17 +id-E-RABAdmittedList ProtocolIE-ID ::= 18 +id-E-RABFailedToSetupListHOReqAck ProtocolIE-ID ::= 19 +id-E-RABAdmittedItem ProtocolIE-ID ::= 20 +id-E-RABFailedtoSetupItemHOReqAck ProtocolIE-ID ::= 21 +id-E-RABToBeSwitchedDLList ProtocolIE-ID ::= 22 +id-E-RABToBeSwitchedDLItem ProtocolIE-ID ::= 23 +id-E-RABToBeSetupListCtxtSUReq ProtocolIE-ID ::= 24 +id-TraceActivation ProtocolIE-ID ::= 25 +id-NAS-PDU ProtocolIE-ID ::= 26 +id-E-RABToBeSetupItemHOReq ProtocolIE-ID ::= 27 +id-E-RABSetupListBearerSURes ProtocolIE-ID ::= 28 +id-E-RABFailedToSetupListBearerSURes ProtocolIE-ID ::= 29 +id-E-RABToBeModifiedListBearerModReq ProtocolIE-ID ::= 30 +id-E-RABModifyListBearerModRes ProtocolIE-ID ::= 31 +id-E-RABFailedToModifyList ProtocolIE-ID ::= 32 +id-E-RABToBeReleasedList ProtocolIE-ID ::= 33 +id-E-RABFailedToReleaseList ProtocolIE-ID ::= 34 +id-E-RABItem ProtocolIE-ID ::= 35 +id-E-RABToBeModifiedItemBearerModReq ProtocolIE-ID ::= 36 +id-E-RABModifyItemBearerModRes ProtocolIE-ID ::= 37 +id-E-RABReleaseItem ProtocolIE-ID ::= 38 +id-E-RABSetupItemBearerSURes ProtocolIE-ID ::= 39 +id-SecurityContext ProtocolIE-ID ::= 40 +id-HandoverRestrictionList ProtocolIE-ID ::= 41 +id-UEPagingID ProtocolIE-ID ::= 43 +id-pagingDRX ProtocolIE-ID ::= 44 +id-TAIList ProtocolIE-ID ::= 46 +id-TAIItem ProtocolIE-ID ::= 47 +id-E-RABFailedToSetupListCtxtSURes ProtocolIE-ID ::= 48 +id-E-RABReleaseItemHOCmd ProtocolIE-ID ::= 49 +id-E-RABSetupItemCtxtSURes ProtocolIE-ID ::= 50 +id-E-RABSetupListCtxtSURes ProtocolIE-ID ::= 51 +id-E-RABToBeSetupItemCtxtSUReq ProtocolIE-ID ::= 52 +id-E-RABToBeSetupListHOReq ProtocolIE-ID ::= 53 +id-GERANtoLTEHOInformationRes ProtocolIE-ID ::= 55 +id-UTRANtoLTEHOInformationRes ProtocolIE-ID ::= 57 +id-CriticalityDiagnostics ProtocolIE-ID ::= 58 +id-Global-ENB-ID ProtocolIE-ID ::= 59 +id-eNBname ProtocolIE-ID ::= 60 +id-MMEname ProtocolIE-ID ::= 61 +id-ServedPLMNs ProtocolIE-ID ::= 63 +id-SupportedTAs ProtocolIE-ID ::= 64 +id-TimeToWait ProtocolIE-ID ::= 65 +id-uEaggregateMaximumBitrate ProtocolIE-ID ::= 66 +id-TAI ProtocolIE-ID ::= 67 +id-E-RABReleaseListBearerRelComp ProtocolIE-ID ::= 69 +id-cdma2000PDU ProtocolIE-ID ::= 70 +id-cdma2000RATType ProtocolIE-ID ::= 71 +id-cdma2000SectorID ProtocolIE-ID ::= 72 +id-SecurityKey ProtocolIE-ID ::= 73 +id-UERadioCapability ProtocolIE-ID ::= 74 +id-GUMMEI-ID ProtocolIE-ID ::= 75 +id-E-RABInformationListItem ProtocolIE-ID ::= 78 +id-Direct-Forwarding-Path-Availability ProtocolIE-ID ::= 79 +id-UEIdentityIndexValue ProtocolIE-ID ::= 80 +id-cdma2000HOStatus ProtocolIE-ID ::= 83 +id-cdma2000HORequiredIndication ProtocolIE-ID ::= 84 +id-E-UTRAN-Trace-ID ProtocolIE-ID ::= 86 +id-RelativeMMECapacity ProtocolIE-ID ::= 87 +id-SourceMME-UE-S1AP-ID ProtocolIE-ID ::= 88 +id-Bearers-SubjectToStatusTransfer-Item ProtocolIE-ID ::= 89 +id-eNB-StatusTransfer-TransparentContainer ProtocolIE-ID ::= 90 +id-UE-associatedLogicalS1-ConnectionItem ProtocolIE-ID ::= 91 +id-ResetType ProtocolIE-ID ::= 92 +id-UE-associatedLogicalS1-ConnectionListResAck ProtocolIE-ID ::= 93 +id-E-RABToBeSwitchedULItem ProtocolIE-ID ::= 94 +id-E-RABToBeSwitchedULList ProtocolIE-ID ::= 95 +id-S-TMSI ProtocolIE-ID ::= 96 +id-cdma2000OneXRAND ProtocolIE-ID ::= 97 +id-RequestType ProtocolIE-ID ::= 98 +id-UE-S1AP-IDs ProtocolIE-ID ::= 99 +id-EUTRAN-CGI ProtocolIE-ID ::= 100 +id-OverloadResponse ProtocolIE-ID ::= 101 +id-cdma2000OneXSRVCCInfo ProtocolIE-ID ::= 102 +id-E-RABFailedToBeReleasedList ProtocolIE-ID ::= 103 +id-Source-ToTarget-TransparentContainer ProtocolIE-ID ::= 104 +id-ServedGUMMEIs ProtocolIE-ID ::= 105 +id-SubscriberProfileIDforRFP ProtocolIE-ID ::= 106 +id-UESecurityCapabilities ProtocolIE-ID ::= 107 +id-CSFallbackIndicator ProtocolIE-ID ::= 108 +id-CNDomain ProtocolIE-ID ::= 109 +id-E-RABReleasedList ProtocolIE-ID ::= 110 +id-MessageIdentifier ProtocolIE-ID ::= 111 +id-SerialNumber ProtocolIE-ID ::= 112 +id-WarningAreaList ProtocolIE-ID ::= 113 +id-RepetitionPeriod ProtocolIE-ID ::= 114 +id-NumberofBroadcastRequest ProtocolIE-ID ::= 115 +id-WarningType ProtocolIE-ID ::= 116 +id-WarningSecurityInfo ProtocolIE-ID ::= 117 +id-DataCodingScheme ProtocolIE-ID ::= 118 +id-WarningMessageContents ProtocolIE-ID ::= 119 +id-BroadcastCompletedAreaList ProtocolIE-ID ::= 120 +id-Inter-SystemInformationTransferTypeEDT ProtocolIE-ID ::= 121 +id-Inter-SystemInformationTransferTypeMDT ProtocolIE-ID ::= 122 +id-Target-ToSource-TransparentContainer ProtocolIE-ID ::= 123 +id-SRVCCOperationPossible ProtocolIE-ID ::= 124 +id-SRVCCHOIndication ProtocolIE-ID ::= 125 +id-NAS-DownlinkCount ProtocolIE-ID ::= 126 +id-CSG-Id ProtocolIE-ID ::= 127 +id-CSG-IdList ProtocolIE-ID ::= 128 +id-SONConfigurationTransferECT ProtocolIE-ID ::= 129 +id-SONConfigurationTransferMCT ProtocolIE-ID ::= 130 +id-TraceCollectionEntityIPAddress ProtocolIE-ID ::= 131 +id-MSClassmark2 ProtocolIE-ID ::= 132 +id-MSClassmark3 ProtocolIE-ID ::= 133 +id-RRC-Establishment-Cause ProtocolIE-ID ::= 134 +id-NASSecurityParametersfromE-UTRAN ProtocolIE-ID ::= 135 +id-NASSecurityParameterstoE-UTRAN ProtocolIE-ID ::= 136 +id-DefaultPagingDRX ProtocolIE-ID ::= 137 +id-Source-ToTarget-TransparentContainer-Secondary ProtocolIE-ID ::= 138 +id-Target-ToSource-TransparentContainer-Secondary ProtocolIE-ID ::= 139 +id-EUTRANRoundTripDelayEstimationInfo ProtocolIE-ID ::= 140 +id-BroadcastCancelledAreaList ProtocolIE-ID ::= 141 +id-ConcurrentWarningMessageIndicator ProtocolIE-ID ::= 142 +id-Data-Forwarding-Not-Possible ProtocolIE-ID ::= 143 +id-ExtendedRepetitionPeriod ProtocolIE-ID ::= 144 +id-CellAccessMode ProtocolIE-ID ::= 145 +id-CSGMembershipStatus ProtocolIE-ID ::= 146 +id-LPPa-PDU ProtocolIE-ID ::= 147 +id-Routing-ID ProtocolIE-ID ::= 148 +id-Time-Synchronization-Info ProtocolIE-ID ::= 149 +id-PS-ServiceNotAvailable ProtocolIE-ID ::= 150 +id-RegisteredLAI ProtocolIE-ID ::= 159 + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Containers.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Containers.asn new file mode 100644 index 0000000000..1e356a29a4 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-Containers.asn @@ -0,0 +1,197 @@ +-- ************************************************************** +-- +-- Container definitions +-- +-- ************************************************************** + +S1AP-Containers { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-Containers (5) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + Presence, + PrivateIE-ID, + ProtocolExtensionID, + ProtocolIE-ID +FROM S1AP-CommonDataTypes + + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs +FROM S1AP-Constants; + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +S1AP-PROTOCOL-IES ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol IEs +-- +-- ************************************************************** + +S1AP-PROTOCOL-IES-PAIR ::= CLASS { + &id ProtocolIE-ID UNIQUE, + &firstCriticality Criticality, + &FirstValue, + &secondCriticality Criticality, + &SecondValue, + &presence Presence +} +WITH SYNTAX { + ID &id + FIRST CRITICALITY &firstCriticality + FIRST TYPE &FirstValue + SECOND CRITICALITY &secondCriticality + SECOND TYPE &SecondValue + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Protocol Extensions +-- +-- ************************************************************** + +S1AP-PROTOCOL-EXTENSION ::= CLASS { + &id ProtocolExtensionID UNIQUE, + &criticality Criticality, + &Extension, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + EXTENSION &Extension + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Class Definition for Private IEs +-- +-- ************************************************************** + +S1AP-PRIVATE-IES ::= CLASS { + &id PrivateIE-ID, + &criticality Criticality, + &Value, + &presence Presence +} +WITH SYNTAX { + ID &id + CRITICALITY &criticality + TYPE &Value + PRESENCE &presence +} + +-- ************************************************************** +-- +-- Container for Protocol IEs +-- +-- ************************************************************** + +ProtocolIE-Container {S1AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-SingleContainer {S1AP-PROTOCOL-IES : IEsSetParam} ::= + ProtocolIE-Field {{IEsSetParam}} + +ProtocolIE-Field {S1AP-PROTOCOL-IES : IEsSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-IES.&id ({IEsSetParam}), + criticality S1AP-PROTOCOL-IES.&criticality ({IEsSetParam}{@id}), + value S1AP-PROTOCOL-IES.&Value ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Protocol IE Pairs +-- +-- ************************************************************** + +ProtocolIE-ContainerPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (0..maxProtocolIEs)) OF + ProtocolIE-FieldPair {{IEsSetParam}} + +ProtocolIE-FieldPair {S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-IES-PAIR.&id ({IEsSetParam}), + firstCriticality S1AP-PROTOCOL-IES-PAIR.&firstCriticality ({IEsSetParam}{@id}), + firstValue S1AP-PROTOCOL-IES-PAIR.&FirstValue ({IEsSetParam}{@id}), + secondCriticality S1AP-PROTOCOL-IES-PAIR.&secondCriticality ({IEsSetParam}{@id}), + secondValue S1AP-PROTOCOL-IES-PAIR.&SecondValue ({IEsSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container Lists for Protocol IE Containers +-- +-- ************************************************************** + +ProtocolIE-ContainerList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-SingleContainer {{IEsSetParam}} + +ProtocolIE-ContainerPairList {INTEGER : lowerBound, INTEGER : upperBound, S1AP-PROTOCOL-IES-PAIR : IEsSetParam} ::= + SEQUENCE (SIZE (lowerBound..upperBound)) OF + ProtocolIE-ContainerPair {{IEsSetParam}} + +-- ************************************************************** +-- +-- Container for Protocol Extensions +-- +-- ************************************************************** + +ProtocolExtensionContainer {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= + SEQUENCE (SIZE (1..maxProtocolExtensions)) OF + ProtocolExtensionField {{ExtensionSetParam}} + +ProtocolExtensionField {S1AP-PROTOCOL-EXTENSION : ExtensionSetParam} ::= SEQUENCE { + id S1AP-PROTOCOL-EXTENSION.&id ({ExtensionSetParam}), + criticality S1AP-PROTOCOL-EXTENSION.&criticality ({ExtensionSetParam}{@id}), + extensionValue S1AP-PROTOCOL-EXTENSION.&Extension ({ExtensionSetParam}{@id}) +} + +-- ************************************************************** +-- +-- Container for Private IEs +-- +-- ************************************************************** + +PrivateIE-Container {S1AP-PRIVATE-IES : IEsSetParam } ::= + SEQUENCE (SIZE (1.. maxPrivateIEs)) OF + PrivateIE-Field {{IEsSetParam}} + +PrivateIE-Field {S1AP-PRIVATE-IES : IEsSetParam} ::= SEQUENCE { + id S1AP-PRIVATE-IES.&id ({IEsSetParam}), + criticality S1AP-PRIVATE-IES.&criticality ({IEsSetParam}{@id}), + value S1AP-PRIVATE-IES.&Value ({IEsSetParam}{@id}) +} + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-IEs.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-IEs.asn new file mode 100644 index 0000000000..535aa91ee0 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-IEs.asn @@ -0,0 +1,1213 @@ +-- ************************************************************** +-- +-- Information Element Definitions +-- +-- ************************************************************** + +S1AP-IEs { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-IEs (2) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + id-E-RABInformationListItem, + id-E-RABItem, + id-Bearers-SubjectToStatusTransfer-Item, + id-Time-Synchronization-Info, + maxNrOfCSGs, + maxNrOfE-RABs, + maxNrOfErrors, + maxnoofBPLMNs, + maxnoofPLMNsPerMME, + maxnoofTACs, + maxnoofEPLMNs, + maxnoofEPLMNsPlusOne, + maxnoofForbLACs, + maxnoofForbTACs, + maxnoofCells, + maxnoofCellID, + maxnoofEmergencyAreaID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + maxnoofeNBX2TLAs, + maxnoofRATs, + maxnoofGroupIDs, + maxnoofMMECs, + maxProtocolExtensions, + maxnoofTAIs, + maxNrOfIndividualS1ConnectionsToReset + + +FROM S1AP-Constants + + IE +FROM S1AP-PDU + + Criticality, + ProcedureCode, + ProtocolIE-ID, + TriggeringMessage +FROM S1AP-CommonDataTypes; + +IE-Extensions ::= SEQUENCE (SIZE (1..maxProtocolExtensions)) OF IE + +-- A + + +AllocationAndRetentionPriority ::= SEQUENCE { + priorityLevel PriorityLevel, + pre-emptionCapability Pre-emptionCapability, + pre-emptionVulnerability Pre-emptionVulnerability, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- B + +Bearers-SubjectToStatusTransfer-List ::= SEQUENCE (SIZE (1..maxNrOfE-RABs)) OF IE + +Bearers-SubjectToStatusTransfer-Item ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + uL-COUNTvalue COUNTvalue, + dL-COUNTvalue COUNTvalue, + receiveStatusofULPDCPSDUs ReceiveStatusofULPDCPSDUs OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +BitRate ::= INTEGER (0..10000000000) + +BPLMNs ::= SEQUENCE (SIZE(1.. maxnoofBPLMNs)) OF PLMNidentity + +BroadcastCancelledAreaList ::= CHOICE { + cellID-Cancelled CellID-Cancelled, + tAI-Cancelled TAI-Cancelled, + emergencyAreaID-Cancelled EmergencyAreaID-Cancelled, + ... +} + +BroadcastCompletedAreaList ::= CHOICE { + cellID-Broadcast CellID-Broadcast, + tAI-Broadcast TAI-Broadcast, + emergencyAreaID-Broadcast EmergencyAreaID-Broadcast, + ... +} + + +-- C + +CancelledCellinEAI ::= SEQUENCE (SIZE(1..maxnoofCellinEAI)) OF CancelledCellinEAI-Item + +CancelledCellinEAI-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CancelledCellinTAI ::= SEQUENCE (SIZE(1..maxnoofCellinTAI)) OF CancelledCellinTAI-Item + +CancelledCellinTAI-Item ::= SEQUENCE{ + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Cause ::= CHOICE { + radioNetwork CauseRadioNetwork, + transport CauseTransport, + nas CauseNas, + protocol CauseProtocol, + misc CauseMisc, + ... +} + +CauseMisc ::= ENUMERATED { + control-processing-overload, + not-enough-user-plane-processing-resources, + hardware-failure, + om-intervention, + unspecified, + unknown-PLMN, +... +} + +CauseProtocol ::= ENUMERATED { + transfer-syntax-error, + abstract-syntax-error-reject, + abstract-syntax-error-ignore-and-notify, + message-not-compatible-with-receiver-state, + semantic-error, + abstract-syntax-error-falsely-constructed-message, + unspecified, + ... +} + +CauseRadioNetwork ::= ENUMERATED { + unspecified, + tx2relocoverall-expiry, + successful-handover, + release-due-to-eutran-generated-reason, + handover-cancelled, + partial-handover, + ho-failure-in-target-EPC-eNB-or-target-system, + ho-target-not-allowed, + tS1relocoverall-expiry, + tS1relocprep-expiry, + cell-not-available, + unknown-targetID, + no-radio-resources-available-in-target-cell, + unknown-mme-ue-s1ap-id, + unknown-enb-ue-s1ap-id, + unknown-pair-ue-s1ap-id, + handover-desirable-for-radio-reason, + time-critical-handover, + resource-optimisation-handover, + reduce-load-in-serving-cell, + user-inactivity, + radio-connection-with-ue-lost, + load-balancing-tau-required, + cs-fallback-triggered, + ue-not-available-for-ps-service, + radio-resources-not-available, + failure-in-radio-interface-procedure, + invalid-qos-combination, + interrat-redirection, + interaction-with-other-procedure, + unknown-E-RAB-ID, + multiple-E-RAB-ID-instances, + encryption-and-or-integrity-protection-algorithms-not-supported, + s1-intra-system-handover-triggered, + s1-inter-system-handover-triggered, + x2-handover-triggered, + ..., + redirection-towards-1xRTT, + not-supported-QCI-value, + invalid-CSG-Id + +} + +CauseTransport ::= ENUMERATED { + transport-resource-unavailable, + unspecified, + ... +} + +CauseNas ::= ENUMERATED { + normal-release, + authentication-failure, + detach, + unspecified, + ..., + csg-subscription-expiry +} + +CellAccessMode ::= ENUMERATED { + hybrid, + ... +} + +CellIdentity ::= BIT STRING (SIZE (28)) + +CellID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF CellID-Broadcast-Item + +CellID-Broadcast-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CellID-Cancelled::= SEQUENCE (SIZE(1..maxnoofCellID)) OF CellID-Cancelled-Item + +CellID-Cancelled-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + numberOfBroadcasts NumberOfBroadcasts, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Cdma2000PDU ::= OCTET STRING + +Cdma2000RATType ::= ENUMERATED { + hRPD, + onexRTT, + ... +} + +Cdma2000SectorID ::= OCTET STRING + +Cdma2000HOStatus ::= ENUMERATED { + hOSuccess, + hOFailure, + ... +} + +Cdma2000HORequiredIndication ::= ENUMERATED { + true, + ... +} + +Cdma2000OneXSRVCCInfo ::= SEQUENCE { + cdma2000OneXMEID Cdma2000OneXMEID, + cdma2000OneXMSI Cdma2000OneXMSI, + cdma2000OneXPilot Cdma2000OneXPilot, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Cdma2000OneXMEID ::= OCTET STRING + +Cdma2000OneXMSI ::= OCTET STRING + +Cdma2000OneXPilot ::= OCTET STRING + +Cdma2000OneXRAND ::= OCTET STRING + + +Cell-Size ::= ENUMERATED {verysmall, small, medium, large, ...} + +CellType ::= SEQUENCE { + cell-Size Cell-Size, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, + cI CI, + rAC RAC OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CI ::= OCTET STRING (SIZE (2)) + +CNDomain ::= ENUMERATED { + ps, + cs +} + +ConcurrentWarningMessageIndicator ::= ENUMERATED { + true +} +CSFallbackIndicator ::= ENUMERATED { + cs-fallback-required, + ..., + cs-fallback-high-priority +} + +CSG-Id ::= BIT STRING (SIZE (27)) + + +CSG-IdList ::= SEQUENCE (SIZE (1..maxNrOfCSGs)) OF CSG-IdList-Item + +CSG-IdList-Item ::= SEQUENCE { + cSG-Id CSG-Id, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CSGMembershipStatus ::= ENUMERATED { + member, + not-member +} + + +COUNTvalue ::= SEQUENCE { + pDCP-SN PDCP-SN, + hFN HFN, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CriticalityDiagnostics ::= SEQUENCE { + procedureCode ProcedureCode OPTIONAL, + triggeringMessage TriggeringMessage OPTIONAL, + procedureCriticality Criticality OPTIONAL, + iEsCriticalityDiagnostics CriticalityDiagnostics-IE-List OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CriticalityDiagnostics-IE-List ::= SEQUENCE (SIZE (1..maxNrOfErrors)) OF CriticalityDiagnostics-IE-Item + +CriticalityDiagnostics-IE-Item ::= SEQUENCE { + iECriticality Criticality, + iE-ID ProtocolIE-ID, + typeOfError TypeOfError, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- D + +DataCodingScheme ::= BIT STRING (SIZE (8)) + +DL-Forwarding ::= ENUMERATED { + dL-Forwarding-proposed, + ... +} + +Direct-Forwarding-Path-Availability ::= ENUMERATED { + directPathAvailable, + ... +} + +Data-Forwarding-Not-Possible ::= ENUMERATED { + data-Forwarding-not-Possible, + ... +} + +-- E + +ECGIList ::= SEQUENCE (SIZE(1..maxnoofCellID)) OF EUTRAN-CGI + +EmergencyAreaIDList ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID + +EmergencyAreaID ::= OCTET STRING (SIZE (3)) + +EmergencyAreaID-Broadcast ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID-Broadcast-Item + +EmergencyAreaID-Broadcast-Item ::= SEQUENCE { + emergencyAreaID EmergencyAreaID, + completedCellinEAI CompletedCellinEAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EmergencyAreaID-Cancelled ::= SEQUENCE (SIZE(1..maxnoofEmergencyAreaID)) OF EmergencyAreaID-Cancelled-Item + +EmergencyAreaID-Cancelled-Item ::= SEQUENCE { + emergencyAreaID EmergencyAreaID, + cancelledCellinEAI CancelledCellinEAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSwitchedULList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSwitchedDLList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABDataForwardingList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSetupListHOReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABAdmittedList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABFailedtoSetupListHOReqAck ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF IE + +E-RABModifyItemBearerModRes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemCtxtSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeModifiedItemBearerModReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABLevelQoSParameters E-RABLevelQoSParameters, + nAS-PDU NAS-PDU, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupItemCtxtSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABSetupItemBearerSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedDLItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSwitchedULItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemHOReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + e-RABlevelQosParameters E-RABLevelQoSParameters, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemBearerSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABDataForwardingItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABAdmittedItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABReleaseItemBearerRelComp ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CompletedCellinEAI ::= SEQUENCE (SIZE(1..maxnoofCellinEAI)) OF CompletedCellinEAI-Item + +CompletedCellinEAI-Item ::= SEQUENCE { + eCGI EUTRAN-CGI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-ID ::= CHOICE { + macroENB-ID BIT STRING (SIZE(20)), + homeENB-ID BIT STRING (SIZE(28)), + ... +} + +GERAN-Cell-ID ::= SEQUENCE { + lAI LAI, + rAC RAC, + cI CI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Global-ENB-ID ::= SEQUENCE { + pLMNidentity PLMNidentity, + eNB-ID ENB-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-StatusTransfer-TransparentContainer ::= SEQUENCE { + bearers-SubjectToStatusTransfer-List Bearers-SubjectToStatusTransfer-List, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ENB-UE-S1AP-ID ::= INTEGER (0..16777215) + +ENBname ::= PrintableString (SIZE (1..150,...)) + +ENBX2TLAs ::= SEQUENCE (SIZE(1.. maxnoofeNBX2TLAs)) OF TransportLayerAddress + +EncryptionAlgorithms ::= BIT STRING (SIZE (16,...)) + +EPLMNs ::= SEQUENCE (SIZE(1..maxnoofEPLMNs)) OF PLMNidentity +EventType ::= ENUMERATED { + direct, + change-of-serve-cell, + stop-change-of-serve-cell, + ... +} + +E-RAB-ID ::= INTEGER (0..15, ...) + +E-RABInformationListItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + dL-Forwarding DL-Forwarding OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABLevelQoSParameters ::= SEQUENCE { + qCI QCI, + allocationRetentionPriority AllocationAndRetentionPriority, + gbrQosInformation GBR-QosInformation OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EUTRAN-CGI ::= SEQUENCE { + pLMNidentity PLMNidentity, + cell-ID CellIdentity, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +EUTRANRoundTripDelayEstimationInfo ::= INTEGER (0..2047) + +ExtendedRNC-ID ::= INTEGER (4096..65535) + +ExtendedRepetitionPeriod ::= INTEGER (4096..131071) + +-- F + +ForbiddenInterRATs ::= ENUMERATED { + all, + geran, + utran, + cdma2000, + ..., + geranandutran, + cdma2000andutran + +} + +ForbiddenTAs ::= SEQUENCE (SIZE(1.. maxnoofEPLMNsPlusOne)) OF ForbiddenTAs-Item + +ForbiddenTAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenTACs ForbiddenTACs, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ForbiddenTACs ::= SEQUENCE (SIZE(1..maxnoofForbTACs)) OF TAC + +ForbiddenLAs ::= SEQUENCE (SIZE(1..maxnoofEPLMNsPlusOne)) OF ForbiddenLAs-Item + +ForbiddenLAs-Item ::= SEQUENCE { + pLMN-Identity PLMNidentity, + forbiddenLACs ForbiddenLACs, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ForbiddenLACs ::= SEQUENCE (SIZE(1..maxnoofForbLACs)) OF LAC + +-- G + +GBR-QosInformation ::= SEQUENCE { + e-RAB-MaximumBitrateDL BitRate, + e-RAB-MaximumBitrateUL BitRate, + e-RAB-GuaranteedBitrateDL BitRate, + e-RAB-GuaranteedBitrateUL BitRate, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +GTP-TEID ::= OCTET STRING (SIZE (4)) + +GUMMEI ::= SEQUENCE { + pLMN-Identity PLMNidentity, + mME-Group-ID MME-Group-ID, + mME-Code MME-Code, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- H + +HandoverRestrictionList ::= SEQUENCE { + servingPLMN PLMNidentity, + equivalentPLMNs EPLMNs OPTIONAL, + forbiddenTAs ForbiddenTAs OPTIONAL, + forbiddenLAs ForbiddenLAs OPTIONAL, + forbiddenInterRATs ForbiddenInterRATs OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +HandoverType ::= ENUMERATED { + intralte, + ltetoutran, + ltetogeran, + utrantolte, + gerantolte, + ... +} + +HFN ::= INTEGER (0..1048575) + +-- I + +IMSI ::= OCTET STRING (SIZE (3..8)) + +IntegrityProtectionAlgorithms ::= BIT STRING (SIZE (16,...)) + +InterfacesToTrace ::= BIT STRING (SIZE (8)) + +Inter-SystemInformationTransferType ::= CHOICE { + rIMTransfer RIMTransfer, + ... +} + +-- J +-- K +-- L + + +LAC ::= OCTET STRING (SIZE (2)) + +LAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + lAC LAC, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +LastVisitedCell-Item ::= CHOICE { + e-UTRAN-Cell LastVisitedEUTRANCellInformation, + uTRAN-Cell LastVisitedUTRANCellInformation, + gERAN-Cell LastVisitedGERANCellInformation, + ... +} +LastVisitedEUTRANCellInformation ::= SEQUENCE { + global-Cell-ID EUTRAN-CGI, + cellType CellType, + time-UE-StayedInCell Time-UE-StayedInCell, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +LastVisitedUTRANCellInformation ::= OCTET STRING + +LastVisitedGERANCellInformation ::= CHOICE { + undefined NULL, + ... +} + +L3-Information ::= OCTET STRING + +LPPa-PDU ::= OCTET STRING + +-- M + +MessageIdentifier ::= BIT STRING (SIZE (16)) + +MMEname ::= PrintableString (SIZE (1..150,...)) + +MME-Group-ID ::= OCTET STRING (SIZE (2)) + +MME-Code ::= OCTET STRING (SIZE (1)) + +MME-UE-S1AP-ID ::= INTEGER (0..4294967295) +M-TMSI ::= OCTET STRING (SIZE (4)) + +MSClassmark2 ::= OCTET STRING +MSClassmark3 ::= OCTET STRING + +-- N + +NAS-PDU ::= OCTET STRING + +NASSecurityParametersfromE-UTRAN ::= OCTET STRING + +NASSecurityParameterstoE-UTRAN ::= OCTET STRING + +NumberofBroadcastRequest ::= INTEGER (0..65535) + +NumberOfBroadcasts ::= INTEGER (0..65535) + +-- O +OldBSS-ToNewBSS-Information ::= OCTET STRING + +OverloadAction ::= ENUMERATED { +reject-non-emergency-mo-dt, +reject-all-rrc-cr-signalling, +permit-emergency-sessions-and-mobile-terminated-services-only, + ... +} + +OverloadResponse ::= CHOICE { + overloadAction OverloadAction, + ... +} + + +-- P + +PagingDRX ::= ENUMERATED { + v32, + v64, + v128, + v256, + ... + } + +PDCP-SN ::= INTEGER (0..4095) + +PLMNidentity ::= TBCD-STRING + +Pre-emptionCapability ::= ENUMERATED { + shall-not-trigger-pre-emption, + may-trigger-pre-emption +} + +Pre-emptionVulnerability ::= ENUMERATED { + not-pre-emptable, + pre-emptable +} + +PriorityLevel ::= INTEGER { spare (0), highest (1), lowest (14), no-priority (15) } (0..15) + +PS-ServiceNotAvailable ::= ENUMERATED { + ps-service-not-available, + ... +} + +-- Q + +QCI ::= INTEGER (0..255) + +-- R + +ResetType ::= CHOICE { + s1-Interface ResetAll, + partOfS1-Interface UE-associatedLogicalS1-ConnectionListRes, + ... +} + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +ReceiveStatusofULPDCPSDUs ::= BIT STRING (SIZE(4096)) + +RelativeMMECapacity ::= INTEGER (0..255) + +RAC ::= OCTET STRING (SIZE (1)) + + +RequestType ::= SEQUENCE { + eventType EventType, + reportArea ReportArea, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +RIMTransfer ::= SEQUENCE { + rIMInformation RIMInformation, + rIMRoutingAddress RIMRoutingAddress OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +RIMInformation ::= OCTET STRING + +RIMRoutingAddress ::= CHOICE { + gERAN-Cell-ID GERAN-Cell-ID, + ..., + targetRNC-ID TargetRNC-ID +} + +ReportArea ::= ENUMERATED { + ecgi, + ... +} + +RepetitionPeriod ::= INTEGER (0..4095) + + +RNC-ID ::= INTEGER (0..4095) + +RRC-Container ::= OCTET STRING + +RRC-Establishment-Cause ::= ENUMERATED { + emergency, + highPriorityAccess, + mt-Access, + mo-Signalling, + mo-Data, + ... +} + +Routing-ID ::= INTEGER (0..255) + +-- S + + +SecurityKey ::= BIT STRING (SIZE(256)) + + + +SecurityContext ::= SEQUENCE { + nextHopChainingCount INTEGER (0..7), + nextHopParameter SecurityKey, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +SerialNumber ::= BIT STRING (SIZE (16)) + +SONInformation ::= CHOICE{ + sONInformationRequest SONInformationRequest, + sONInformationReply SONInformationReply, + ... +} + +SONInformationRequest ::= ENUMERATED { + x2TNL-Configuration-Info, + ..., + time-Synchronization-Info} + +SONInformationReply ::= SEQUENCE { + x2TNLConfigurationInfo X2TNLConfigurationInfo OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +SONConfigurationTransfer ::= SEQUENCE { + targeteNB-ID TargeteNB-ID, + sourceeNB-ID SourceeNB-ID, + sONInformation SONInformation, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Source-ToTarget-TransparentContainer ::= OCTET STRING + +SourceBSS-ToTargetBSS-TransparentContainer ::= OCTET STRING + +SourceeNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, + iE-Extensions IE-Extensions OPTIONAL +} + +SRVCCOperationPossible ::= ENUMERATED { + possible, + ... +} + +SRVCCHOIndication ::= ENUMERATED { + pSandCS, + cSonly, + ... +} + +SourceeNB-ToTargeteNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, + e-RABInformationList E-RABInformationList OPTIONAL, + targetCell-ID EUTRAN-CGI, + subscriberProfileIDforRFP SubscriberProfileIDforRFP OPTIONAL, + uE-HistoryInformation UE-HistoryInformation, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF IE + +SourceRNC-ToTargetRNC-TransparentContainer ::= OCTET STRING + + +ServedGUMMEIs ::= SEQUENCE (SIZE (1.. maxnoofRATs)) OF ServedGUMMEIsItem + +ServedGUMMEIsItem ::= SEQUENCE { + servedPLMNs ServedPLMNs, + servedGroupIDs ServedGroupIDs, + servedMMECs ServedMMECs, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +ServedGroupIDs ::= SEQUENCE (SIZE(1.. maxnoofGroupIDs)) OF MME-Group-ID +ServedMMECs ::= SEQUENCE (SIZE(1.. maxnoofMMECs)) OF MME-Code + +ServedPLMNs ::= SEQUENCE (SIZE(1.. maxnoofPLMNsPerMME)) OF PLMNidentity + +SubscriberProfileIDforRFP ::= INTEGER (1..256) + +SupportedTAs ::= SEQUENCE (SIZE(1.. maxnoofTACs)) OF SupportedTAs-Item + +SupportedTAs-Item ::= SEQUENCE { + tAC TAC, + broadcastPLMNs BPLMNs, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +StratumLevel ::= INTEGER (0..3, ...) + +SynchronizationStatus ::= ENUMERATED { synchronous, asynchronous, ... } + +TimeSynchronizationInfo ::= SEQUENCE { + stratumLevel StratumLevel, + synchronizationStatus SynchronizationStatus, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +S-TMSI ::= SEQUENCE { + mMEC MME-Code, + m-TMSI M-TMSI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- T + +TAC ::= OCTET STRING (SIZE (2)) + +TAIListforWarning ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI + +TAI ::= SEQUENCE { + pLMNidentity PLMNidentity, + tAC TAC, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAI-Broadcast ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI-Broadcast-Item + +TAI-Broadcast-Item ::= SEQUENCE { + tAI TAI, + completedCellinTAI CompletedCellinTAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAI-Cancelled ::= SEQUENCE (SIZE(1..maxnoofTAIforWarning)) OF TAI-Cancelled-Item + +TAI-Cancelled-Item ::= SEQUENCE { + tAI TAI, + cancelledCellinTAI CancelledCellinTAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TAIList ::= SEQUENCE (SIZE(1..maxnoofTAIs)) OF IE + +TAIItem ::= SEQUENCE { + tAI TAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +CompletedCellinTAI ::= SEQUENCE (SIZE(1..maxnoofCellinTAI)) OF CompletedCellinTAI-Item + +CompletedCellinTAI-Item ::= SEQUENCE{ + eCGI EUTRAN-CGI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TBCD-STRING ::= OCTET STRING (SIZE (3)) + +TargetID ::= CHOICE { + targeteNB-ID TargeteNB-ID, + targetRNC-ID TargetRNC-ID, + cGI CGI, + ... +} + +TargeteNB-ID ::= SEQUENCE { + global-ENB-ID Global-ENB-ID, + selected-TAI TAI, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TargetRNC-ID ::= SEQUENCE { + lAI LAI, + rAC RAC OPTIONAL, + rNC-ID RNC-ID, + extendedRNC-ID ExtendedRNC-ID OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TargeteNB-ToSourceeNB-TransparentContainer ::= SEQUENCE { + rRC-Container RRC-Container, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +Target-ToSource-TransparentContainer ::= OCTET STRING +TargetRNC-ToSourceRNC-TransparentContainer ::= OCTET STRING +TargetBSS-ToSourceBSS-TransparentContainer ::= OCTET STRING + +TimeToWait ::= ENUMERATED {v1s, v2s, v5s, v10s, v20s, v60s, ...} + +Time-UE-StayedInCell ::= INTEGER (0..4095) + +TransportLayerAddress ::= BIT STRING (SIZE(1..160, ...)) + +TraceActivation ::= SEQUENCE { + e-UTRAN-Trace-ID E-UTRAN-Trace-ID, + interfacesToTrace InterfacesToTrace, +traceDepth TraceDepth, +traceCollectionEntityIPAddress TransportLayerAddress, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +TraceDepth ::= ENUMERATED { + minimum, + medium, + maximum, + minimumWithoutVendorSpecificExtension, + mediumWithoutVendorSpecificExtension, + maximumWithoutVendorSpecificExtension, + ... +} + +E-UTRAN-Trace-ID ::= OCTET STRING (SIZE (8)) + +TypeOfError ::= ENUMERATED { + not-understood, + missing, + ... +} + +-- U + +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE + +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF IE + +UEAggregateMaximumBitrate ::= SEQUENCE { + uEaggregateMaximumBitRateDL BitRate, + uEaggregateMaximumBitRateUL BitRate, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UE-S1AP-IDs ::= CHOICE{ + uE-S1AP-ID-pair UE-S1AP-ID-pair, + mME-UE-S1AP-ID MME-UE-S1AP-ID, + ... +} + +UE-S1AP-ID-pair ::= SEQUENCE{ + mME-UE-S1AP-ID MME-UE-S1AP-ID, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UE-associatedLogicalS1-ConnectionItem ::= SEQUENCE { + mME-UE-S1AP-ID MME-UE-S1AP-ID OPTIONAL, + eNB-UE-S1AP-ID ENB-UE-S1AP-ID OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +UEIdentityIndexValue ::= BIT STRING (SIZE (10)) + +UE-HistoryInformation ::= SEQUENCE (SIZE(1..maxnoofCells)) OF LastVisitedCell-Item + +UEPagingID ::= CHOICE { + s-TMSI S-TMSI, + iMSI IMSI, + ... + } + +UERadioCapability ::= OCTET STRING + +UESecurityCapabilities ::= SEQUENCE { + encryptionAlgorithms EncryptionAlgorithms, + integrityProtectionAlgorithms IntegrityProtectionAlgorithms, + iE-Extensions IE-Extensions OPTIONAL, +... +} + +-- V +-- W + +WarningAreaList ::= CHOICE { + cellIDList ECGIList, + trackingAreaListforWarning TAIListforWarning, + emergencyAreaIDList EmergencyAreaIDList, + ... +} + + +WarningType ::= OCTET STRING (SIZE (2)) + +WarningSecurityInfo ::= OCTET STRING (SIZE (50)) + + +WarningMessageContents ::= OCTET STRING (SIZE(1..9600)) + + +-- X + + +X2TNLConfigurationInfo ::= SEQUENCE { + eNBX2TransportLayerAddresses ENBX2TLAs, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +-- Y +-- Z + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Contents.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Contents.asn new file mode 100644 index 0000000000..d3d4189e0f --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Contents.asn @@ -0,0 +1,2419 @@ +-- ************************************************************** +-- +-- PDU definitions for S1AP. +-- +-- ************************************************************** + +S1AP-PDU-Contents { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-PDU-Contents (1) } + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + + UEAggregateMaximumBitrate, + Cause, + CellAccessMode, + Cdma2000HORequiredIndication, + Cdma2000HOStatus, + Cdma2000OneXSRVCCInfo, + Cdma2000OneXRAND, + Cdma2000PDU, + Cdma2000RATType, + Cdma2000SectorID, + EUTRANRoundTripDelayEstimationInfo, + CNDomain, + ConcurrentWarningMessageIndicator, + CriticalityDiagnostics, + CSFallbackIndicator, + CSG-Id, + CSG-IdList, + CSGMembershipStatus, + Data-Forwarding-Not-Possible, + Direct-Forwarding-Path-Availability, + Global-ENB-ID, + EUTRAN-CGI, + ENBname, + ENB-StatusTransfer-TransparentContainer, + ENB-UE-S1AP-ID, + ExtendedRepetitionPeriod, + GTP-TEID, + GUMMEI, + HandoverRestrictionList, + HandoverType, + LAI, + LPPa-PDU, + MMEname, + MME-UE-S1AP-ID, + MSClassmark2, + MSClassmark3, + NAS-PDU, + NASSecurityParametersfromE-UTRAN, + NASSecurityParameterstoE-UTRAN, + OverloadResponse, + PagingDRX, + PLMNidentity, + RIMTransfer, + RelativeMMECapacity, + RequestType, + E-RAB-ID, + E-RABLevelQoSParameters, + E-RABList, +Routing-ID, + SecurityKey, + SecurityContext, + ServedGUMMEIs, + SONConfigurationTransfer, + Source-ToTarget-TransparentContainer, + SourceBSS-ToTargetBSS-TransparentContainer, + SourceeNB-ToTargeteNB-TransparentContainer, + SourceRNC-ToTargetRNC-TransparentContainer, + SubscriberProfileIDforRFP, + SRVCCOperationPossible, + SRVCCHOIndication, + SupportedTAs, + TAI, + Target-ToSource-TransparentContainer, + TargetBSS-ToSourceBSS-TransparentContainer, + TargeteNB-ToSourceeNB-TransparentContainer, + TargetID, + TargetRNC-ToSourceRNC-TransparentContainer, + TimeToWait, + TraceActivation, + E-UTRAN-Trace-ID, + TransportLayerAddress, + UEIdentityIndexValue, + UEPagingID, + UERadioCapability, + UE-S1AP-IDs, + UE-associatedLogicalS1-ConnectionItem, + UESecurityCapabilities, + S-TMSI, + MessageIdentifier, + SerialNumber, + WarningAreaList, + RepetitionPeriod, + NumberofBroadcastRequest, + WarningType, + WarningSecurityInfo, + DataCodingScheme, + WarningMessageContents, + BroadcastCompletedAreaList, + RRC-Establishment-Cause, + BroadcastCancelledAreaList, + PS-ServiceNotAvailable + +FROM S1AP-IEs + + PrivateIE-Container{}, + ProtocolExtensionContainer{}, + ProtocolIE-Container{}, + ProtocolIE-ContainerList{}, + ProtocolIE-ContainerPair{}, + ProtocolIE-ContainerPairList{}, + ProtocolIE-SingleContainer{}, + S1AP-PRIVATE-IES, + S1AP-PROTOCOL-EXTENSION, + S1AP-PROTOCOL-IES, + S1AP-PROTOCOL-IES-PAIR +FROM S1AP-Containers + + + id-uEaggregateMaximumBitrate, + id-Cause, + id-CellAccessMode, + id-cdma2000HORequiredIndication, + id-cdma2000HOStatus, + id-cdma2000OneXSRVCCInfo, + id-cdma2000OneXRAND, + id-cdma2000PDU, + id-cdma2000RATType, + id-cdma2000SectorID, + id-EUTRANRoundTripDelayEstimationInfo, + id-CNDomain, + id-ConcurrentWarningMessageIndicator, + id-CriticalityDiagnostics, + id-CSFallbackIndicator, + id-CSG-Id, + id-CSG-IdList, + id-CSGMembershipStatus, + id-Data-Forwarding-Not-Possible, + id-DefaultPagingDRX, + id-Direct-Forwarding-Path-Availability, + id-Global-ENB-ID, + id-EUTRAN-CGI, + id-eNBname, + id-eNB-StatusTransfer-TransparentContainer, + id-eNB-UE-S1AP-ID, + id-GERANtoLTEHOInformationRes, + id-GUMMEI-ID, + id-HandoverRestrictionList, + id-HandoverType, + id-InitialContextSetup, + id-Inter-SystemInformationTransferTypeEDT, + id-Inter-SystemInformationTransferTypeMDT, + id-LPPa-PDU, + id-NAS-DownlinkCount, + id-MMEname, + id-MME-UE-S1AP-ID, + id-MSClassmark2, + id-MSClassmark3, + id-NAS-PDU, + id-NASSecurityParametersfromE-UTRAN, + id-NASSecurityParameterstoE-UTRAN, + id-OverloadResponse, + id-pagingDRX, + id-RelativeMMECapacity, + id-RequestType, + id-Routing-ID, + id-E-RABAdmittedItem, + id-E-RABAdmittedList, + id-E-RABDataForwardingItem, + id-E-RABFailedToModifyList, + id-E-RABFailedToReleaseList, + id-E-RABFailedtoSetupItemHOReqAck, + id-E-RABFailedToSetupListBearerSURes, + id-E-RABFailedToSetupListCtxtSURes, + id-E-RABFailedToSetupListHOReqAck, + id-E-RABFailedToBeReleasedList, + id-E-RABModify, + id-E-RABModifyItemBearerModRes, + id-E-RABModifyListBearerModRes, + id-E-RABRelease, + id-E-RABReleaseItemBearerRelComp, + id-E-RABReleaseItemHOCmd, + id-E-RABReleaseListBearerRelComp, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-E-RABSetupItemBearerSURes, + id-E-RABSetupItemCtxtSURes, + id-E-RABSetupListBearerSURes, + id-E-RABSetupListCtxtSURes, + id-E-RABSubjecttoDataForwardingList, + id-E-RABToBeModifiedItemBearerModReq, + id-E-RABToBeModifiedListBearerModReq, + id-E-RABToBeReleasedList, + id-E-RABReleasedList, + id-E-RABToBeSetupItemBearerSUReq, + id-E-RABToBeSetupItemCtxtSUReq, + id-E-RABToBeSetupItemHOReq, + id-E-RABToBeSetupListBearerSUReq, + id-E-RABToBeSetupListCtxtSUReq, + id-E-RABToBeSetupListHOReq, + id-E-RABToBeSwitchedDLItem, + id-E-RABToBeSwitchedDLList, + id-E-RABToBeSwitchedULList, + id-E-RABToBeSwitchedULItem, + id-E-RABtoReleaseListHOCmd, + id-SecurityKey, + id-SecurityContext, + id-ServedGUMMEIs, + id-SONConfigurationTransferECT, + id-SONConfigurationTransferMCT, + id-Source-ToTarget-TransparentContainer, + id-Source-ToTarget-TransparentContainer-Secondary, + id-SourceMME-UE-S1AP-ID, + id-SRVCCOperationPossible, + id-SRVCCHOIndication, + id-SubscriberProfileIDforRFP, + id-SupportedTAs, + id-S-TMSI, + id-TAI, + id-TAIItem, + id-TAIList, + id-Target-ToSource-TransparentContainer, + id-Target-ToSource-TransparentContainer-Secondary, + id-TargetID, + id-TimeToWait, + id-TraceActivation, + id-E-UTRAN-Trace-ID, + id-UEIdentityIndexValue, + id-UEPagingID, + id-UERadioCapability, + id-UTRANtoLTEHOInformationRes, + id-UE-associatedLogicalS1-ConnectionListResAck, + id-UE-associatedLogicalS1-ConnectionItem, + id-UESecurityCapabilities, + id-UE-S1AP-IDs, + id-ResetType, + id-MessageIdentifier, + id-SerialNumber, + id-WarningAreaList, + id-RepetitionPeriod, + id-NumberofBroadcastRequest, + id-WarningType, + id-WarningSecurityInfo, + id-DataCodingScheme, + id-WarningMessageContents, + id-BroadcastCompletedAreaList, + id-BroadcastCancelledAreaList, + id-RRC-Establishment-Cause, + id-TraceCollectionEntityIPAddress, maxnoofTAIs, + maxNrOfErrors, + maxNrOfE-RABs, + maxNrOfIndividualS1ConnectionsToReset, + maxnoofEmergencyAreaID, + maxnoofCellID, + maxnoofTAIforWarning, + maxnoofCellinTAI, + maxnoofCellinEAI, + id-ExtendedRepetitionPeriod, + id-PS-ServiceNotAvailable, + id-RegisteredLAI + + +FROM S1AP-Constants; + +-- ************************************************************** +-- +-- Common Container Lists +-- +-- ************************************************************** + +E-RAB-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } +E-RAB-IE-ContainerPairList { S1AP-PROTOCOL-IES-PAIR : IEsSetParam } ::= ProtocolIE-ContainerPairList { 1, maxNrOfE-RABs, {IEsSetParam} } +ProtocolError-IE-ContainerList { S1AP-PROTOCOL-IES : IEsSetParam } ::= ProtocolIE-ContainerList { 1, maxNrOfE-RABs, {IEsSetParam} } + +-- ************************************************************** +-- +-- HANDOVER PREPARATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Required +-- +-- ************************************************************** + +HandoverRequired ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverRequiredIEs} }, + ... +} + +HandoverRequiredIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TargetID CRITICALITY reject TYPE TargetID PRESENCE mandatory }| + { ID id-Direct-Forwarding-Path-Availability CRITICALITY ignore TYPE Direct-Forwarding-Path-Availability PRESENCE optional }| + { ID id-SRVCCHOIndication CRITICALITY reject TYPE SRVCCHOIndication PRESENCE optional }| + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory }| + { ID id-Source-ToTarget-TransparentContainer-Secondary CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE optional }| + { ID id-MSClassmark2 CRITICALITY reject TYPE MSClassmark2 PRESENCE conditional }| + { ID id-MSClassmark3 CRITICALITY ignore TYPE MSClassmark3 PRESENCE conditional }| + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional }| + { ID id-CellAccessMode CRITICALITY reject TYPE CellAccessMode PRESENCE optional }| + { ID id-PS-ServiceNotAvailable CRITICALITY ignore TYPE PS-ServiceNotAvailable PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- Handover Command +-- +-- ************************************************************** + +HandoverCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCommandIEs} }, + ... +} + +HandoverCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-NASSecurityParametersfromE-UTRAN CRITICALITY reject TYPE NASSecurityParametersfromE-UTRAN PRESENCE conditional + -- This IE shall be present if HandoverType IE is set to value "LTEtoUTRAN" or "LTEtoGERAN" -- }| + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-E-RABtoReleaseListHOCmd CRITICALITY ignore TYPE E-RABList PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-Target-ToSource-TransparentContainer-Secondary CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABDataForwardingList ::= E-RAB-IE-ContainerList { {E-RABDataForwardingItemIEs} } + +E-RABDataForwardingItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABDataForwardingItem CRITICALITY ignore TYPE E-RABDataForwardingItem PRESENCE mandatory }, + ... +} + +E-RABDataForwardingItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- Handover Preparation Failure +-- +-- ************************************************************** + +HandoverPreparationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverPreparationFailureIEs} }, + ... +} + +HandoverPreparationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER RESOURCE ALLOCATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Request +-- +-- ************************************************************** + +HandoverRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestIEs} }, + ... +} + +HandoverRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-HandoverType CRITICALITY reject TYPE HandoverType PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory } | + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory }| + { ID id-E-RABToBeSetupListHOReq CRITICALITY reject TYPE E-RABToBeSetupListHOReq PRESENCE mandatory } | + { ID id-Source-ToTarget-TransparentContainer CRITICALITY reject TYPE Source-ToTarget-TransparentContainer PRESENCE mandatory } | + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory }| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional }| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional }| + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE optional }| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional }| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-NASSecurityParameterstoE-UTRAN CRITICALITY reject TYPE NASSecurityParameterstoE-UTRAN PRESENCE conditional + -- This IE shall be present if the Handover Type IE is set to the value "UTRANtoLTE" or "GERANtoLTE" -- } | + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional} | + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional} , + ... +} + +E-RABToBeSetupListHOReq ::= E-RAB-IE-ContainerList { {E-RABToBeSetupItemHOReqIEs} } + +E-RABToBeSetupItemHOReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemHOReq CRITICALITY reject TYPE E-RABToBeSetupItemHOReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemHOReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + e-RABlevelQosParameters E-RABLevelQoSParameters, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABToBeSetupItemHOReq-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + {ID id-Data-Forwarding-Not-Possible CRITICALITY ignore EXTENSION Data-Forwarding-Not-Possible PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- Handover Request Acknowledge +-- +-- ************************************************************** + +HandoverRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {HandoverRequestAcknowledgeIEs} }, + ... +} + +HandoverRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABAdmittedList CRITICALITY ignore TYPE E-RABAdmittedList PRESENCE mandatory } | + { ID id-E-RABFailedToSetupListHOReqAck CRITICALITY ignore TYPE E-RABFailedtoSetupListHOReqAck PRESENCE optional } | + { ID id-Target-ToSource-TransparentContainer CRITICALITY reject TYPE Target-ToSource-TransparentContainer PRESENCE mandatory }| + { ID id-CSG-Id CRITICALITY ignore TYPE CSG-Id PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABAdmittedList ::= E-RAB-IE-ContainerList { {E-RABAdmittedItemIEs} } + +E-RABAdmittedItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABAdmittedItem CRITICALITY ignore TYPE E-RABAdmittedItem PRESENCE mandatory }, + ... +} + +E-RABAdmittedItem ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + dL-transportLayerAddress TransportLayerAddress OPTIONAL, + dL-gTP-TEID GTP-TEID OPTIONAL, + uL-TransportLayerAddress TransportLayerAddress OPTIONAL, + uL-GTP-TEID GTP-TEID OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABAdmittedItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABFailedtoSetupListHOReqAck ::= E-RAB-IE-ContainerList { {E-RABFailedtoSetupItemHOReqAckIEs} } + +E-RABFailedtoSetupItemHOReqAckIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABFailedtoSetupItemHOReqAck CRITICALITY ignore TYPE E-RABFailedToSetupItemHOReqAck PRESENCE mandatory }, + ... +} + +E-RABFailedToSetupItemHOReqAck ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + cause Cause, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + +E-RABFailedToSetupItemHOReqAckExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Handover Failure +-- +-- ************************************************************** + +HandoverFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverFailureIEs} }, + ... +} + +HandoverFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER NOTIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Notify +-- +-- ************************************************************** + +HandoverNotify ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverNotifyIEs} }, + ... +} + +HandoverNotifyIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- PATH SWITCH REQUEST ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Path Switch Request +-- +-- ************************************************************** + +PathSwitchRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestIEs} }, + ... +} + +PathSwitchRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABToBeSwitchedDLList CRITICALITY reject TYPE E-RABToBeSwitchedDLList PRESENCE mandatory }| + { ID id-SourceMME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY ignore TYPE UESecurityCapabilities PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedDLList ::= E-RAB-IE-ContainerList { {E-RABToBeSwitchedDLItemIEs} } + +E-RABToBeSwitchedDLItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedDLItem CRITICALITY reject TYPE E-RABToBeSwitchedDLItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedDLItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- Path Switch Request Acknowledge +-- +-- ************************************************************** + +PathSwitchRequestAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestAcknowledgeIEs} }, + ... +} + +PathSwitchRequestAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeSwitchedULList CRITICALITY ignore TYPE E-RABToBeSwitchedULList PRESENCE optional }| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-SecurityContext CRITICALITY reject TYPE SecurityContext PRESENCE mandatory}| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +E-RABToBeSwitchedULList ::= E-RAB-IE-ContainerList { {E-RABToBeSwitchedULItemIEs} } + +E-RABToBeSwitchedULItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSwitchedULItem CRITICALITY ignore TYPE E-RABToBeSwitchedULItem PRESENCE mandatory }, + ... +} + +E-RABToBeSwitchedULItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Path Switch Request Failure +-- +-- ************************************************************** + +PathSwitchRequestFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { PathSwitchRequestFailureIEs} }, + ... +} + +PathSwitchRequestFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- HANDOVER CANCEL ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Handover Cancel +-- +-- ************************************************************** + +HandoverCancel ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelIEs} }, + ... +} + +HandoverCancelIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Handover Cancel Request Acknowledge +-- +-- ************************************************************** + +HandoverCancelAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { HandoverCancelAcknowledgeIEs} }, + ... +} + +HandoverCancelAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- E-RAB SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Setup Request +-- +-- ************************************************************** + +E-RABSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupRequestIEs} }, + ... +} + +E-RABSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeSetupListBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupListBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupListBearerSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemBearerSUReqIEs} } + +E-RABToBeSetupItemBearerSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemBearerSUReq CRITICALITY reject TYPE E-RABToBeSetupItemBearerSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemBearerSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- E-RAB Setup Response +-- +-- ************************************************************** + +E-RABSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABSetupResponseIEs} }, + ... +} + +E-RABSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListBearerSURes CRITICALITY ignore TYPE E-RABSetupListBearerSURes PRESENCE optional }| + { ID id-E-RABFailedToSetupListBearerSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABSetupListBearerSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemBearerSUResIEs} } + +E-RABSetupItemBearerSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemBearerSURes CRITICALITY ignore TYPE E-RABSetupItemBearerSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemBearerSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + + +E-RABSetupItemBearerSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB MODIFY ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Modify Request +-- +-- ************************************************************** + +E-RABModifyRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyRequestIEs} }, + ... +} + +E-RABModifyRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeModifiedListBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedListBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifiedListBearerModReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeModifiedItemBearerModReqIEs} } + +E-RABToBeModifiedItemBearerModReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeModifiedItemBearerModReq CRITICALITY reject TYPE E-RABToBeModifiedItemBearerModReq PRESENCE mandatory }, + ... +} + +E-RABToBeModifiedItemBearerModReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABLevelQoSParameters E-RABLevelQoSParameters, + nAS-PDU NAS-PDU, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + + +E-RABToBeModifyItemBearerModReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB Modify Response +-- +-- ************************************************************** + +E-RABModifyResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABModifyResponseIEs} }, + ... +} + +E-RABModifyResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABModifyListBearerModRes CRITICALITY ignore TYPE E-RABModifyListBearerModRes PRESENCE optional }| + { ID id-E-RABFailedToModifyList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABModifyListBearerModRes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABModifyItemBearerModResIEs} } + +E-RABModifyItemBearerModResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABModifyItemBearerModRes CRITICALITY ignore TYPE E-RABModifyItemBearerModRes PRESENCE mandatory }, + ... +} + +E-RABModifyItemBearerModRes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + + +E-RABModifyItemBearerModResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + + +-- ************************************************************** +-- +-- E-RAB RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Command +-- +-- ************************************************************** + +E-RABReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseCommandIEs} }, + ... +} + +E-RABReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE optional }| + { ID id-E-RABToBeReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }| + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- E-RAB Release Response +-- +-- ************************************************************** + +E-RABReleaseResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { E-RABReleaseResponseIEs } }, + ... +} + +E-RABReleaseResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleaseListBearerRelComp CRITICALITY ignore TYPE E-RABReleaseListBearerRelComp PRESENCE optional }| + { ID id-E-RABFailedToReleaseList CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABReleaseListBearerRelComp ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABReleaseItemBearerRelCompIEs} } + +E-RABReleaseItemBearerRelCompIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABReleaseItemBearerRelComp CRITICALITY ignore TYPE E-RABReleaseItemBearerRelComp PRESENCE mandatory }, + ... +} + +E-RABReleaseItemBearerRelCompExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + + +-- ************************************************************** +-- +-- E-RAB RELEASE INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- E-RAB Release Indication +-- +-- ************************************************************** + +E-RABReleaseIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {E-RABReleaseIndicationIEs} }, + ... +} + +E-RABReleaseIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABReleasedList CRITICALITY ignore TYPE E-RABList PRESENCE mandatory }, + ... +} +-- ************************************************************** +-- +-- INITIAL CONTEXT SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Initial Context Setup Request +-- +-- ************************************************************** + +InitialContextSetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupRequestIEs} }, + ... +} + +InitialContextSetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-uEaggregateMaximumBitrate CRITICALITY reject TYPE UEAggregateMaximumBitrate PRESENCE mandatory}| + { ID id-E-RABToBeSetupListCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupListCtxtSUReq PRESENCE mandatory}| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE mandatory}| + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE mandatory}| + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE optional}| + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional}| + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE optional}| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional}| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional}| + { ID id-SRVCCOperationPossible CRITICALITY ignore TYPE SRVCCOperationPossible PRESENCE optional}| + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional}| + { ID id-RegisteredLAI CRITICALITY ignore TYPE LAI PRESENCE optional}, + ... +} + + + + +E-RABToBeSetupListCtxtSUReq ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABToBeSetupItemCtxtSUReqIEs} } + +E-RABToBeSetupItemCtxtSUReqIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABToBeSetupItemCtxtSUReq CRITICALITY reject TYPE E-RABToBeSetupItemCtxtSUReq PRESENCE mandatory }, + ... +} + +E-RABToBeSetupItemCtxtSUReq ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + e-RABlevelQoSParameters E-RABLevelQoSParameters, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + nAS-PDU NAS-PDU OPTIONAL, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + + +E-RABToBeSetupItemCtxtSUReqExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Initial Context Setup Response +-- +-- ************************************************************** + +InitialContextSetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupResponseIEs} }, + ... +} + +InitialContextSetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-E-RABSetupListCtxtSURes CRITICALITY ignore TYPE E-RABSetupListCtxtSURes PRESENCE mandatory }| + { ID id-E-RABFailedToSetupListCtxtSURes CRITICALITY ignore TYPE E-RABList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +E-RABSetupListCtxtSURes ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABSetupItemCtxtSUResIEs} } + +E-RABSetupItemCtxtSUResIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABSetupItemCtxtSURes CRITICALITY ignore TYPE E-RABSetupItemCtxtSURes PRESENCE mandatory }, + ... +} + +E-RABSetupItemCtxtSURes ::= SEQUENCE { + e-RAB-ID E-RAB-ID, + transportLayerAddress TransportLayerAddress, + gTP-TEID GTP-TEID, + iE-Extensions IE-Extensions OPTIONAL, + ... +} + + +E-RABSetupItemCtxtSUResExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + + +-- ************************************************************** +-- +-- Initial Context Setup Failure +-- +-- ************************************************************** + +InitialContextSetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {InitialContextSetupFailureIEs} }, + ... +} + +InitialContextSetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory }| + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- PAGING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + + +-- ************************************************************** +-- +-- Paging +-- +-- ************************************************************** + +Paging ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{PagingIEs}}, + ... +} + +PagingIEs S1AP-PROTOCOL-IES ::= { + { ID id-UEIdentityIndexValue CRITICALITY ignore TYPE UEIdentityIndexValue PRESENCE mandatory } | + { ID id-UEPagingID CRITICALITY ignore TYPE UEPagingID PRESENCE mandatory } | + { ID id-pagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional } | + { ID id-CNDomain CRITICALITY ignore TYPE CNDomain PRESENCE mandatory } | + { ID id-TAIList CRITICALITY ignore TYPE TAIList PRESENCE mandatory }| + { ID id-CSG-IdList CRITICALITY ignore TYPE CSG-IdList PRESENCE optional }, + ... +} + +TAIList::= SEQUENCE (SIZE(1.. maxnoofTAIs)) OF ProtocolIE-SingleContainer {{TAIItemIEs}} + +TAIItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-TAIItem CRITICALITY ignore TYPE TAIItem PRESENCE mandatory }, + ... +} + +TAIItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE CONTEXT RELEASE REQUEST +-- +-- ************************************************************** + +UEContextReleaseRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseRequestIEs}}, + ... +} + +UEContextReleaseRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UE Context Release Command +-- +-- ************************************************************** + +UEContextReleaseCommand ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseCommandIEs}}, + ... +} + +UEContextReleaseCommandIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-S1AP-IDs CRITICALITY reject TYPE UE-S1AP-IDs PRESENCE mandatory} | + + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UE Context Release Complete +-- +-- ************************************************************** + +UEContextReleaseComplete ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UEContextReleaseCompleteIEs}}, + ... +} + +UEContextReleaseCompleteIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- UE CONTEXT MODIFICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Context Modification Request +-- +-- ************************************************************** + +UEContextModificationRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationRequestIEs} }, + ... +} + +UEContextModificationRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory}| + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory}| + { ID id-SecurityKey CRITICALITY reject TYPE SecurityKey PRESENCE optional}| + { ID id-SubscriberProfileIDforRFP CRITICALITY ignore TYPE SubscriberProfileIDforRFP PRESENCE optional}| + { ID id-uEaggregateMaximumBitrate CRITICALITY ignore TYPE UEAggregateMaximumBitrate PRESENCE optional}| + { ID id-CSFallbackIndicator CRITICALITY reject TYPE CSFallbackIndicator PRESENCE optional}| + { ID id-UESecurityCapabilities CRITICALITY reject TYPE UESecurityCapabilities PRESENCE optional}| + { ID id-CSGMembershipStatus CRITICALITY ignore TYPE CSGMembershipStatus PRESENCE optional}| + { ID id-RegisteredLAI CRITICALITY ignore TYPE LAI PRESENCE optional}, + ... +} +-- ************************************************************** +-- +-- UE Context Modification Response +-- +-- ************************************************************** + +UEContextModificationResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationResponseIEs} }, + ... +} + +UEContextModificationResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +}-- ************************************************************** +-- +-- UE Context Modification Failure +-- +-- ************************************************************** + +UEContextModificationFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UEContextModificationFailureIEs} }, + ... +} + +UEContextModificationFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- NAS TRANSPORT ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DOWNLINK NAS TRANSPORT +-- +-- ************************************************************** + +DownlinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkNASTransportIEs}}, + ... +} + +DownlinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-HandoverRestrictionList CRITICALITY ignore TYPE HandoverRestrictionList PRESENCE optional }, + ... +} + + +-- ************************************************************** +-- +-- INITIAL UE MESSAGE +-- +-- ************************************************************** + +InitialUEMessage ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{InitialUEMessageIEs}}, + ... +} + +InitialUEMessageIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-TAI CRITICALITY reject TYPE TAI PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-RRC-Establishment-Cause CRITICALITY ignore TYPE RRC-Establishment-Cause PRESENCE mandatory} | + { ID id-S-TMSI CRITICALITY reject TYPE S-TMSI PRESENCE optional} | + { ID id-CSG-Id CRITICALITY reject TYPE CSG-Id PRESENCE optional} | + { ID id-GUMMEI-ID CRITICALITY reject TYPE GUMMEI PRESENCE optional} | + { ID id-CellAccessMode CRITICALITY reject TYPE CellAccessMode PRESENCE optional}, + ... +} + + +-- ************************************************************** +-- +-- UPLINK NAS TRANSPORT +-- +-- ************************************************************** + +UplinkNASTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkNASTransportIEs}}, + ... +} + +UplinkNASTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY reject TYPE NAS-PDU PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory}, + ... +} +-- ************************************************************** +-- +-- NAS NON DELIVERY INDICATION +-- +-- ************************************************************** + +NASNonDeliveryIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{NASNonDeliveryIndicationIEs}}, + ... +} + +NASNonDeliveryIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-NAS-PDU CRITICALITY ignore TYPE NAS-PDU PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- RESET ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Reset +-- +-- ************************************************************** + +Reset ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetIEs} }, + ... +} + +ResetIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-ResetType CRITICALITY reject TYPE ResetType PRESENCE mandatory }, + ... +} + +ResetType ::= CHOICE { + s1-Interface ResetAll, + partOfS1-Interface UE-associatedLogicalS1-ConnectionListRes, + ... +} + + + +ResetAll ::= ENUMERATED { + reset-all, + ... +} + +UE-associatedLogicalS1-ConnectionListRes ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemRes } } + +UE-associatedLogicalS1-ConnectionItemRes S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY reject TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + + +-- ************************************************************** +-- +-- Reset Acknowledge +-- +-- ************************************************************** + +ResetAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ResetAcknowledgeIEs} }, + ... +} + +ResetAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionListResAck CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionListResAck PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +UE-associatedLogicalS1-ConnectionListResAck ::= SEQUENCE (SIZE(1.. maxNrOfIndividualS1ConnectionsToReset)) OF ProtocolIE-SingleContainer { { UE-associatedLogicalS1-ConnectionItemResAck } } + +UE-associatedLogicalS1-ConnectionItemResAck S1AP-PROTOCOL-IES ::= { + { ID id-UE-associatedLogicalS1-ConnectionItem CRITICALITY ignore TYPE UE-associatedLogicalS1-ConnectionItem PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- ERROR INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Error Indication +-- +-- ************************************************************** + +ErrorIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ErrorIndicationIEs}}, + ... +} + +ErrorIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY ignore TYPE MME-UE-S1AP-ID PRESENCE optional } | + { ID id-eNB-UE-S1AP-ID CRITICALITY ignore TYPE ENB-UE-S1AP-ID PRESENCE optional } | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE optional } | + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional } , + ... +} + +-- ************************************************************** +-- +-- S1 SETUP ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- S1 Setup Request +-- +-- ************************************************************** + +S1SetupRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupRequestIEs} }, + ... +} + +S1SetupRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-Global-ENB-ID CRITICALITY reject TYPE Global-ENB-ID PRESENCE mandatory}| + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional}| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE mandatory}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE mandatory}| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Response +-- +-- ************************************************************** + +S1SetupResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupResponseIEs} }, + ... +} + + +S1SetupResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional }| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE mandatory }| + { ID id-RelativeMMECapacity CRITICALITY ignore TYPE RelativeMMECapacity PRESENCE mandatory }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- S1 Setup Failure +-- +-- ************************************************************** + +S1SetupFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {S1SetupFailureIEs} }, + ... +} + +S1SetupFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- ENB CONFIGURATION UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Update +-- +-- ************************************************************** + +ENBConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateIEs} }, + ... +} + +ENBConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-eNBname CRITICALITY ignore TYPE ENBname PRESENCE optional }| + { ID id-SupportedTAs CRITICALITY reject TYPE SupportedTAs PRESENCE optional }| + { ID id-CSG-IdList CRITICALITY reject TYPE CSG-IdList PRESENCE optional}| + { ID id-DefaultPagingDRX CRITICALITY ignore TYPE PagingDRX PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Acknowledge +-- +-- ************************************************************** + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +ENBConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB Configuration Update Failure +-- +-- ************************************************************** + +ENBConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBConfigurationUpdateFailureIEs} }, + ... +} + +ENBConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, +... +} + + +-- ************************************************************** +-- +-- MME Configuration UPDATE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Update +-- +-- ************************************************************** + +MMEConfigurationUpdate ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateIEs} }, + ... +} + +MMEConfigurationUpdateIEs S1AP-PROTOCOL-IES ::= { + { ID id-MMEname CRITICALITY ignore TYPE MMEname PRESENCE optional }| + { ID id-ServedGUMMEIs CRITICALITY reject TYPE ServedGUMMEIs PRESENCE optional }| + { ID id-RelativeMMECapacity CRITICALITY reject TYPE RelativeMMECapacity PRESENCE optional}, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Acknowledge +-- +-- ************************************************************** + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateAcknowledgeIEs} }, + ... +} + + +MMEConfigurationUpdateAcknowledgeIEs S1AP-PROTOCOL-IES ::= { + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- MME Configuration Update Failure +-- +-- ************************************************************** + +MMEConfigurationUpdateFailure ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEConfigurationUpdateFailureIEs} }, + ... +} + +MMEConfigurationUpdateFailureIEs S1AP-PROTOCOL-IES ::= { + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory }| + { ID id-TimeToWait CRITICALITY ignore TYPE TimeToWait PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- DOWNLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Downlink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {DownlinkS1cdma2000tunnelingIEs} }, + ... +} + +DownlinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-E-RABSubjecttoDataForwardingList CRITICALITY ignore TYPE E-RABDataForwardingList PRESENCE optional } | + { ID id-cdma2000HOStatus CRITICALITY ignore TYPE Cdma2000HOStatus PRESENCE optional } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- UPLINK S1 CDMA2000 TUNNELING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Uplink S1 CDMA2000 Tunneling +-- +-- ************************************************************** + +UplinkS1cdma2000tunneling ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {UplinkS1cdma2000tunnelingIEs} }, + ... +} + +UplinkS1cdma2000tunnelingIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-cdma2000RATType CRITICALITY reject TYPE Cdma2000RATType PRESENCE mandatory } | + { ID id-cdma2000SectorID CRITICALITY reject TYPE Cdma2000SectorID PRESENCE mandatory } | + { ID id-cdma2000HORequiredIndication CRITICALITY ignore TYPE Cdma2000HORequiredIndication PRESENCE optional } | + { ID id-cdma2000OneXSRVCCInfo CRITICALITY reject TYPE Cdma2000OneXSRVCCInfo PRESENCE optional } | + { ID id-cdma2000OneXRAND CRITICALITY reject TYPE Cdma2000OneXRAND PRESENCE optional } | + { ID id-cdma2000PDU CRITICALITY reject TYPE Cdma2000PDU PRESENCE mandatory }| + { ID id-EUTRANRoundTripDelayEstimationInfo CRITICALITY ignore TYPE EUTRANRoundTripDelayEstimationInfo PRESENCE optional}, + -- Extension for Release 9 to assist target HRPD access with the acquisition of the UE -- + ... +} + + +-- ************************************************************** +-- +-- UE CAPABILITY INFO INDICATION ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- UE Capability Info Indication +-- +-- ************************************************************** + +UECapabilityInfoIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { UECapabilityInfoIndicationIEs} }, + ... +} + +UECapabilityInfoIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-UERadioCapability CRITICALITY ignore TYPE UERadioCapability PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- eNB STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Status Transfer +-- +-- ************************************************************** + +ENBStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {ENBStatusTransferIEs} }, + ... +} + +ENBStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- MME STATUS TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Status Transfer +-- +-- ************************************************************** + +MMEStatusTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {MMEStatusTransferIEs} }, + ... +} + +MMEStatusTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-StatusTransfer-TransparentContainer CRITICALITY reject TYPE ENB-StatusTransfer-TransparentContainer PRESENCE mandatory} , + ... +} + + +-- ************************************************************** +-- +-- TRACE ELEMENTARY PROCEDURES +-- +-- ************************************************************** +-- ************************************************************** +-- +-- Trace Start +-- +-- ************************************************************** + +TraceStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceStartIEs} }, + ... +} + +TraceStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-TraceActivation CRITICALITY ignore TYPE TraceActivation PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- Trace Failure Indication +-- +-- ************************************************************** + +TraceFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {TraceFailureIndicationIEs} }, + ... +} + +TraceFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- DEACTIVATE TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DEACTIVATE TRACE +-- +-- ************************************************************** + +DeactivateTrace ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { DeactivateTraceIEs} }, + ... +} + +DeactivateTraceIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- CELL TRAFFIC TRACE +-- +-- ************************************************************** + +CellTrafficTrace ::= SEQUENCE { +protocolIEs ProtocolIE-Container { { CellTrafficTraceIEs } }, +... +} + +CellTrafficTraceIEs S1AP-PROTOCOL-IES ::= { + {ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + {ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + {ID id-E-UTRAN-Trace-ID CRITICALITY ignore TYPE E-UTRAN-Trace-ID PRESENCE mandatory}| + {ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory}| + {ID id-TraceCollectionEntityIPAddress CRITICALITY ignore TYPE TransportLayerAddress PRESENCE mandatory }, + ... +} + +-- ************************************************************** +-- +-- LOCATION ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Location Reporting Control +-- +-- ************************************************************** + +LocationReportingControl ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingControlIEs} }, + ... +} + +LocationReportingControlIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- Location Report Failure Indication +-- +-- ************************************************************** + +LocationReportingFailureIndication ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportingFailureIndicationIEs} }, + ... +} + +LocationReportingFailureIndicationIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Cause CRITICALITY ignore TYPE Cause PRESENCE mandatory}, + ... +} + +-- ************************************************************** +-- +-- Location Report +-- +-- ************************************************************** + +LocationReport ::= SEQUENCE { + protocolIEs ProtocolIE-Container { { LocationReportIEs} }, + ... +} + +LocationReportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-EUTRAN-CGI CRITICALITY ignore TYPE EUTRAN-CGI PRESENCE mandatory} | + { ID id-TAI CRITICALITY ignore TYPE TAI PRESENCE mandatory} | + { ID id-RequestType CRITICALITY ignore TYPE RequestType PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- OVERLOAD ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Overload Start +-- +-- ************************************************************** + +OverloadStart ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStartIEs} }, + ... +} + +OverloadStartIEs S1AP-PROTOCOL-IES ::= { + { ID id-OverloadResponse CRITICALITY reject TYPE OverloadResponse PRESENCE mandatory }, + ... +} +-- ************************************************************** +-- +-- Overload Stop +-- +-- ************************************************************** + +OverloadStop ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {OverloadStopIEs} }, + ... +} + +OverloadStopIEs S1AP-PROTOCOL-IES ::= { + ... +} +-- ************************************************************** +-- +-- WRITE-REPLACE WARNING ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Write-Replace Warning Request +-- +-- ************************************************************** + + +WriteReplaceWarningRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningRequestIEs} }, + ... +} + +WriteReplaceWarningRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-WarningAreaList CRITICALITY ignore TYPE WarningAreaList PRESENCE optional }| + { ID id-RepetitionPeriod CRITICALITY reject TYPE RepetitionPeriod PRESENCE mandatory }| + { ID id-ExtendedRepetitionPeriod CRITICALITY reject TYPE ExtendedRepetitionPeriod PRESENCE optional }| + { ID id-NumberofBroadcastRequest CRITICALITY reject TYPE NumberofBroadcastRequest PRESENCE mandatory }| + { ID id-WarningType CRITICALITY ignore TYPE WarningType PRESENCE optional }| + { ID id-WarningSecurityInfo CRITICALITY ignore TYPE WarningSecurityInfo PRESENCE optional }| + { ID id-DataCodingScheme CRITICALITY ignore TYPE DataCodingScheme PRESENCE optional }| + { ID id-WarningMessageContents CRITICALITY ignore TYPE WarningMessageContents PRESENCE optional }| + { ID id-ConcurrentWarningMessageIndicator CRITICALITY reject TYPE ConcurrentWarningMessageIndicator PRESENCE optional }, + ... +} +-- ************************************************************** +-- +-- Write-Replace Warning Response +-- +-- ************************************************************** + +WriteReplaceWarningResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {WriteReplaceWarningResponseIEs} }, + ... +} + +WriteReplaceWarningResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-BroadcastCompletedAreaList CRITICALITY ignore TYPE BroadcastCompletedAreaList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- eNB DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Direct Information Transfer +-- +-- ************************************************************** + +ENBDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBDirectInformationTransferIEs}}, + ... +} + +ENBDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeEDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- MME DIRECT INFORMATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Direct Information Transfer +-- +-- ************************************************************** + +MMEDirectInformationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEDirectInformationTransferIEs}}, + ... +} + +MMEDirectInformationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-Inter-SystemInformationTransferTypeMDT CRITICALITY reject TYPE Inter-SystemInformationTransferType PRESENCE mandatory} , + ... +} +-- ************************************************************** +-- +-- eNB CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- eNB Configuration Transfer +-- +-- ************************************************************** + +ENBConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ ENBConfigurationTransferIEs}}, + ... +} + +ENBConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferECT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- MME CONFIGURATION TRANSFER ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- MME Configuration Transfer +-- +-- ************************************************************** + +MMEConfigurationTransfer ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{ MMEConfigurationTransferIEs}}, + ... +} + +MMEConfigurationTransferIEs S1AP-PROTOCOL-IES ::= { + { ID id-SONConfigurationTransferMCT CRITICALITY ignore TYPE SONConfigurationTransfer PRESENCE optional} , + ... +} + +-- ************************************************************** +-- +-- PRIVATE MESSAGE ELEMENTARY PROCEDURE +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- Private Message +-- +-- ************************************************************** + +PrivateMessage ::= SEQUENCE { + privateIEs PrivateIE-Container {{PrivateMessageIEs}}, + ... +} + +PrivateMessageIEs S1AP-PRIVATE-IES ::= { + ... +} + +-- ************************************************************** +-- +-- Kill Request +-- +-- ************************************************************** + + +KillRequest ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {KillRequestIEs} }, + ... +} + +KillRequestIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-WarningAreaList CRITICALITY ignore TYPE WarningAreaList PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- Kill Response +-- +-- ************************************************************** + +KillResponse ::= SEQUENCE { + protocolIEs ProtocolIE-Container { {KillResponseIEs} }, + ... +} + +KillResponseIEs S1AP-PROTOCOL-IES ::= { + { ID id-MessageIdentifier CRITICALITY reject TYPE MessageIdentifier PRESENCE mandatory }| + { ID id-SerialNumber CRITICALITY reject TYPE SerialNumber PRESENCE mandatory }| + { ID id-BroadcastCancelledAreaList CRITICALITY ignore TYPE BroadcastCancelledAreaList PRESENCE optional }| + { ID id-CriticalityDiagnostics CRITICALITY ignore TYPE CriticalityDiagnostics PRESENCE optional }, + ... +} + +-- ************************************************************** +-- +-- LPPA TRANSPORT ELEMENTARY PROCEDURES +-- +-- ************************************************************** + +-- ************************************************************** +-- +-- DOWNLINK UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +DownlinkUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkUEAssociatedLPPaTransportIEs}}, + ... +} + +DownlinkUEAssociatedLPPaTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory } | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory } | + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory } | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory } , + ... +} + +-- ************************************************************** +-- +-- UPLINK UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +UplinkUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkUEAssociatedLPPaTransportIEs}}, + ... +} + +UplinkUEAssociatedLPPaTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-MME-UE-S1AP-ID CRITICALITY reject TYPE MME-UE-S1AP-ID PRESENCE mandatory} | + { ID id-eNB-UE-S1AP-ID CRITICALITY reject TYPE ENB-UE-S1AP-ID PRESENCE mandatory} | + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- DOWNLINK NON UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +DownlinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{DownlinkNonUEAssociatedLPPaTransportIEs}}, + ... +} + +DownlinkNonUEAssociatedLPPaTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +-- ************************************************************** +-- +-- UPLINK NON UE ASSOCIATED LPPA TRANSPORT +-- +-- ************************************************************** + +UplinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + protocolIEs ProtocolIE-Container {{UplinkNonUEAssociatedLPPaTransportIEs}}, + ... +} + +UplinkNonUEAssociatedLPPaTransportIEs S1AP-PROTOCOL-IES ::= { + { ID id-Routing-ID CRITICALITY reject TYPE Routing-ID PRESENCE mandatory} | + { ID id-LPPa-PDU CRITICALITY reject TYPE LPPa-PDU PRESENCE mandatory} , + ... +} + +Bearers-SubjectToStatusTransfer-List ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { Bearers-SubjectToStatusTransfer-ItemIEs } } + +Bearers-SubjectToStatusTransfer-ItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-Bearers-SubjectToStatusTransfer-Item CRITICALITY ignore TYPE Bearers-SubjectToStatusTransfer-Item PRESENCE mandatory }, + ... +} + +E-RABInformationList ::= SEQUENCE (SIZE (1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { { E-RABInformationItemIEs } } + +E-RABInformationItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABInformationListItem CRITICALITY ignore TYPE E-RABInformationListItem PRESENCE mandatory }, + ... +} + +E-RABList ::= SEQUENCE (SIZE(1.. maxNrOfE-RABs)) OF ProtocolIE-SingleContainer { {E-RABItemIEs} } + +E-RABItemIEs S1AP-PROTOCOL-IES ::= { + { ID id-E-RABItem CRITICALITY ignore TYPE E-RABItem PRESENCE mandatory }, + ... +} + + +SONInformationReply-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + -- Extension for Release 9 to transfer Time synchronization information -- + {ID id-Time-Synchronization-Info CRITICALITY ignore EXTENSION TimeSynchronizationInfo PRESENCE optional}, + ... +} + +AllocationAndRetentionPriority-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +Bearers-SubjectToStatusTransfer-ItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CancelledCellinEAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CancelledCellinTAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellID-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +Cdma2000OneXSRVCCInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CellType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CSG-IdList-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +COUNTvalue-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CriticalityDiagnostics-IE-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EmergencyAreaID-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EmergencyAreaID-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CompletedCellinEAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GERAN-Cell-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ENB-StatusTransfer-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABInformationListItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +E-RABQoSParameters-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +EUTRAN-CGI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ForbiddenTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ForbiddenLAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GBR-QosInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GUMMEI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +HandoverRestrictionList-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +LAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +LastVisitedEUTRANCellInformation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +RequestType-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +RIMTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SecurityContext-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SONConfigurationTransfer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SourceeNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SourceeNB-ToTargeteNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +ServedGUMMEIsItem-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +SupportedTAs-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TimeSynchronizationInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-Broadcast-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TAI-Cancelled-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +CompletedCellinTAI-Item-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +S-TMSI-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargeteNB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargetRNC-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TargeteNB-ToSourceeNB-TransparentContainer-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +TraceActivation-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UEAggregate-MaximumBitrates-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UE-associatedLogicalS1-ConnectionItemExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UESecurityCapabilities-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +GlobalENB-ID-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +X2TNLConfigurationInfo-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +UE-S1AP-ID-pair-ExtIEs S1AP-PROTOCOL-EXTENSION ::= { + ... +} + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Descriptions.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Descriptions.asn new file mode 100644 index 0000000000..cf7114f480 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU-Descriptions.asn @@ -0,0 +1,591 @@ +-- ************************************************************** +-- +-- Elementary Procedure definitions +-- +-- ************************************************************** + +S1AP-PDU-Descriptions { +itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) +eps-Access (21) modules (3) s1ap (1) version1 (1) s1ap-PDU-Descriptions (0)} + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +-- ************************************************************** +-- +-- IE parameter types from other modules. +-- +-- ************************************************************** + +IMPORTS + Criticality, + ProcedureCode +FROM S1AP-CommonDataTypes + + CellTrafficTrace, + DeactivateTrace, + DownlinkUEAssociatedLPPaTransport, + DownlinkNASTransport, + DownlinkNonUEAssociatedLPPaTransport, + DownlinkS1cdma2000tunneling, + ENBDirectInformationTransfer, + ENBStatusTransfer, + ENBConfigurationUpdate, + ENBConfigurationUpdateAcknowledge, + ENBConfigurationUpdateFailure, + ErrorIndication, + HandoverCancel, + HandoverCancelAcknowledge, + HandoverCommand, + HandoverFailure, + HandoverNotify, + HandoverPreparationFailure, + HandoverRequest, + HandoverRequestAcknowledge, + HandoverRequired, + InitialContextSetupFailure, + InitialContextSetupRequest, + InitialContextSetupResponse, + InitialUEMessage, + KillRequest, + KillResponse, + LocationReportingControl, + LocationReportingFailureIndication, + LocationReport, + MMEConfigurationUpdate, + MMEConfigurationUpdateAcknowledge, + MMEConfigurationUpdateFailure, + MMEDirectInformationTransfer, + MMEStatusTransfer, + NASNonDeliveryIndication, + OverloadStart, + OverloadStop, + Paging, + PathSwitchRequest, + PathSwitchRequestAcknowledge, + PathSwitchRequestFailure, + PrivateMessage, + Reset, + ResetAcknowledge, + S1SetupFailure, + S1SetupRequest, + S1SetupResponse, + E-RABModifyRequest, + E-RABModifyResponse, + E-RABReleaseCommand, + E-RABReleaseResponse, + E-RABReleaseIndication, + E-RABSetupRequest, + E-RABSetupResponse, + TraceFailureIndication, + TraceStart, + UECapabilityInfoIndication, + UEContextModificationFailure, + UEContextModificationRequest, + UEContextModificationResponse, + UEContextReleaseCommand, + UEContextReleaseComplete, + UEContextReleaseRequest, + UplinkUEAssociatedLPPaTransport, + UplinkNASTransport, + UplinkNonUEAssociatedLPPaTransport, + UplinkS1cdma2000tunneling, + WriteReplaceWarningRequest, + WriteReplaceWarningResponse, + ENBConfigurationTransfer, + MMEConfigurationTransfer + + +FROM S1AP-PDU-Contents + + id-CellTrafficTrace, + id-DeactivateTrace, + id-downlinkUEAssociatedLPPaTransport, + id-downlinkNASTransport, + id-downlinkNonUEAssociatedLPPaTransport, + id-DownlinkS1cdma2000tunneling, + id-eNBStatusTransfer, + id-ErrorIndication, + id-HandoverCancel, + id-HandoverNotification, + id-HandoverPreparation, + id-HandoverResourceAllocation, + id-InitialContextSetup, + id-initialUEMessage, + id-ENBConfigurationUpdate, + id-Kill, + id-LocationReportingControl, + id-LocationReportingFailureIndication, + id-LocationReport, + id-eNBDirectInformationTransfer, + id-MMEConfigurationUpdate, + id-MMEDirectInformationTransfer, + id-MMEStatusTransfer, + id-NASNonDeliveryIndication, + id-OverloadStart, + id-OverloadStop, + id-Paging, + id-PathSwitchRequest, + id-PrivateMessage, + id-Reset, + id-S1Setup, + id-E-RABModify, + id-E-RABRelease, + id-E-RABReleaseIndication, + id-E-RABSetup, + id-TraceFailureIndication, + id-TraceStart, + id-UECapabilityInfoIndication, + id-UEContextModification, + id-UEContextRelease, + id-UEContextReleaseRequest, + id-uplinkUEAssociatedLPPaTransport, + id-uplinkNASTransport, + id-uplinkNonUEAssociatedLPPaTransport, + id-UplinkS1cdma2000tunneling, + id-WriteReplaceWarning, + id-eNBConfigurationTransfer, + id-MMEConfigurationTransfer +FROM S1AP-Constants; + + +-- ************************************************************** +-- +-- Interface Elementary Procedure Class +-- +-- ************************************************************** + +S1AP-ELEMENTARY-PROCEDURE ::= CLASS { + &InitiatingMessage , + &SuccessfulOutcome OPTIONAL, + &UnsuccessfulOutcome OPTIONAL, + &procedureCode ProcedureCode UNIQUE, + &criticality Criticality DEFAULT ignore +} +WITH SYNTAX { + INITIATING MESSAGE &InitiatingMessage + [SUCCESSFUL OUTCOME &SuccessfulOutcome] + [UNSUCCESSFUL OUTCOME &UnsuccessfulOutcome] + PROCEDURE CODE &procedureCode + [CRITICALITY &criticality] +} + +-- ************************************************************** +-- +-- Interface PDU Definition +-- +-- ************************************************************** + +S1AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&InitiatingMessage ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&SuccessfulOutcome ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode S1AP-ELEMENTARY-PROCEDURE.&procedureCode ({S1AP-ELEMENTARY-PROCEDURES}), + criticality S1AP-ELEMENTARY-PROCEDURE.&criticality ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}), + value S1AP-ELEMENTARY-PROCEDURE.&UnsuccessfulOutcome ({S1AP-ELEMENTARY-PROCEDURES}{@procedureCode}) +} + +-- ************************************************************** +-- +-- Interface Elementary Procedure List +-- +-- ************************************************************** + +S1AP-ELEMENTARY-PROCEDURES S1AP-ELEMENTARY-PROCEDURE ::= { + S1AP-ELEMENTARY-PROCEDURES-CLASS-1 | + S1AP-ELEMENTARY-PROCEDURES-CLASS-2, + ... +} + + +S1AP-ELEMENTARY-PROCEDURES-CLASS-1 S1AP-ELEMENTARY-PROCEDURE ::= { + handoverPreparation | + handoverResourceAllocation | + pathSwitchRequest | + e-RABSetup | + e-RABModify | + e-RABRelease | + initialContextSetup | + handoverCancel | + kill | + reset | + s1Setup | + uEContextModification | + uEContextRelease | + eNBConfigurationUpdate | + mMEConfigurationUpdate | + writeReplaceWarning , + ... +} + +S1AP-ELEMENTARY-PROCEDURES-CLASS-2 S1AP-ELEMENTARY-PROCEDURE ::= { + handoverNotification | + e-RABReleaseIndication | + paging | + downlinkNASTransport | + initialUEMessage | + uplinkNASTransport | + errorIndication | + nASNonDeliveryIndication | + uEContextReleaseRequest | + downlinkS1cdma2000tunneling | + uplinkS1cdma2000tunneling | + uECapabilityInfoIndication | + eNBStatusTransfer | + mMEStatusTransfer | + deactivateTrace | + traceStart | + traceFailureIndication | + cellTrafficTrace | + locationReportingControl | + locationReportingFailureIndication | + locationReport | + overloadStart | + overloadStop | + eNBDirectInformationTransfer | + mMEDirectInformationTransfer | + eNBConfigurationTransfer | + mMEConfigurationTransfer | + privateMessage , + ..., + downlinkUEAssociatedLPPaTransport | + uplinkUEAssociatedLPPaTransport | + downlinkNonUEAssociatedLPPaTransport | + uplinkNonUEAssociatedLPPaTransport +} + +-- ************************************************************** +-- +-- Interface Elementary Procedures +-- +-- ************************************************************** + +handoverPreparation S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverRequired + SUCCESSFUL OUTCOME HandoverCommand + UNSUCCESSFUL OUTCOME HandoverPreparationFailure + PROCEDURE CODE id-HandoverPreparation + CRITICALITY reject +} + +handoverResourceAllocation S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverRequest + SUCCESSFUL OUTCOME HandoverRequestAcknowledge + UNSUCCESSFUL OUTCOME HandoverFailure + PROCEDURE CODE id-HandoverResourceAllocation + CRITICALITY reject +} + +handoverNotification S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverNotify + PROCEDURE CODE id-HandoverNotification + CRITICALITY ignore +} + +pathSwitchRequest S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PathSwitchRequest + SUCCESSFUL OUTCOME PathSwitchRequestAcknowledge + UNSUCCESSFUL OUTCOME PathSwitchRequestFailure + PROCEDURE CODE id-PathSwitchRequest + CRITICALITY reject +} + +e-RABSetup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABSetupRequest + SUCCESSFUL OUTCOME E-RABSetupResponse + PROCEDURE CODE id-E-RABSetup + CRITICALITY reject +} + +e-RABModify S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABModifyRequest + SUCCESSFUL OUTCOME E-RABModifyResponse + PROCEDURE CODE id-E-RABModify + CRITICALITY reject +} + +e-RABRelease S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABReleaseCommand + SUCCESSFUL OUTCOME E-RABReleaseResponse + PROCEDURE CODE id-E-RABRelease + CRITICALITY reject +} + +e-RABReleaseIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE E-RABReleaseIndication + PROCEDURE CODE id-E-RABReleaseIndication + CRITICALITY ignore +} + +initialContextSetup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE InitialContextSetupRequest + SUCCESSFUL OUTCOME InitialContextSetupResponse + UNSUCCESSFUL OUTCOME InitialContextSetupFailure + PROCEDURE CODE id-InitialContextSetup + CRITICALITY reject +} + +uEContextReleaseRequest S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextReleaseRequest + PROCEDURE CODE id-UEContextReleaseRequest + CRITICALITY ignore +} + +paging S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Paging + PROCEDURE CODE id-Paging + CRITICALITY ignore +} + +downlinkNASTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkNASTransport + PROCEDURE CODE id-downlinkNASTransport + CRITICALITY ignore +} + +initialUEMessage S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE InitialUEMessage + PROCEDURE CODE id-initialUEMessage + CRITICALITY ignore +} + +uplinkNASTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkNASTransport + PROCEDURE CODE id-uplinkNASTransport + CRITICALITY ignore +} +nASNonDeliveryIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE NASNonDeliveryIndication + PROCEDURE CODE id-NASNonDeliveryIndication + CRITICALITY ignore +} + +handoverCancel S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE HandoverCancel + SUCCESSFUL OUTCOME HandoverCancelAcknowledge + PROCEDURE CODE id-HandoverCancel + CRITICALITY reject +} + +reset S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE Reset + SUCCESSFUL OUTCOME ResetAcknowledge + PROCEDURE CODE id-Reset + CRITICALITY reject +} + +errorIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ErrorIndication + PROCEDURE CODE id-ErrorIndication + CRITICALITY ignore +} + +s1Setup S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE S1SetupRequest + SUCCESSFUL OUTCOME S1SetupResponse + UNSUCCESSFUL OUTCOME S1SetupFailure + PROCEDURE CODE id-S1Setup + CRITICALITY reject +} + +eNBConfigurationUpdate S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBConfigurationUpdate + SUCCESSFUL OUTCOME ENBConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME ENBConfigurationUpdateFailure + PROCEDURE CODE id-ENBConfigurationUpdate + CRITICALITY reject +} + +mMEConfigurationUpdate S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEConfigurationUpdate + SUCCESSFUL OUTCOME MMEConfigurationUpdateAcknowledge + UNSUCCESSFUL OUTCOME MMEConfigurationUpdateFailure + PROCEDURE CODE id-MMEConfigurationUpdate + CRITICALITY reject +} + +downlinkS1cdma2000tunneling S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkS1cdma2000tunneling + PROCEDURE CODE id-DownlinkS1cdma2000tunneling + CRITICALITY ignore +} + +uplinkS1cdma2000tunneling S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkS1cdma2000tunneling + PROCEDURE CODE id-UplinkS1cdma2000tunneling + CRITICALITY ignore +} + +uEContextModification S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextModificationRequest + SUCCESSFUL OUTCOME UEContextModificationResponse + UNSUCCESSFUL OUTCOME UEContextModificationFailure + + PROCEDURE CODE id-UEContextModification + CRITICALITY reject +} + +uECapabilityInfoIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UECapabilityInfoIndication + PROCEDURE CODE id-UECapabilityInfoIndication + CRITICALITY ignore +} + +uEContextRelease S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UEContextReleaseCommand + SUCCESSFUL OUTCOME UEContextReleaseComplete + PROCEDURE CODE id-UEContextRelease + CRITICALITY reject +} + +eNBStatusTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBStatusTransfer + PROCEDURE CODE id-eNBStatusTransfer + CRITICALITY ignore +} + +mMEStatusTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEStatusTransfer + PROCEDURE CODE id-MMEStatusTransfer + CRITICALITY ignore +} + +deactivateTrace S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DeactivateTrace + PROCEDURE CODE id-DeactivateTrace + CRITICALITY ignore +} + +traceStart S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE TraceStart + PROCEDURE CODE id-TraceStart + CRITICALITY ignore +} + +traceFailureIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE TraceFailureIndication + PROCEDURE CODE id-TraceFailureIndication + CRITICALITY ignore +} +cellTrafficTrace S1AP-ELEMENTARY-PROCEDURE ::={ + INITIATING MESSAGE CellTrafficTrace + PROCEDURE CODE id-CellTrafficTrace + CRITICALITY ignore +} + +locationReportingControl S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReportingControl + PROCEDURE CODE id-LocationReportingControl + CRITICALITY ignore +} + +locationReportingFailureIndication S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReportingFailureIndication + PROCEDURE CODE id-LocationReportingFailureIndication + CRITICALITY ignore +} + +locationReport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE LocationReport + PROCEDURE CODE id-LocationReport + CRITICALITY ignore +} + +overloadStart S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE OverloadStart + PROCEDURE CODE id-OverloadStart + CRITICALITY ignore +} + +overloadStop S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE OverloadStop + PROCEDURE CODE id-OverloadStop + CRITICALITY reject +} + +writeReplaceWarning S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE WriteReplaceWarningRequest + SUCCESSFUL OUTCOME WriteReplaceWarningResponse + PROCEDURE CODE id-WriteReplaceWarning + CRITICALITY reject +} + +eNBDirectInformationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBDirectInformationTransfer + PROCEDURE CODE id-eNBDirectInformationTransfer + CRITICALITY ignore +} + +mMEDirectInformationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEDirectInformationTransfer + PROCEDURE CODE id-MMEDirectInformationTransfer + CRITICALITY ignore +} + +eNBConfigurationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE ENBConfigurationTransfer + PROCEDURE CODE id-eNBConfigurationTransfer + CRITICALITY ignore +} + +mMEConfigurationTransfer S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE MMEConfigurationTransfer + PROCEDURE CODE id-MMEConfigurationTransfer + CRITICALITY ignore +} + + +privateMessage S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE PrivateMessage + PROCEDURE CODE id-PrivateMessage + CRITICALITY ignore +} + +kill S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE KillRequest + SUCCESSFUL OUTCOME KillResponse + PROCEDURE CODE id-Kill + CRITICALITY reject +} + +downlinkUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkUEAssociatedLPPaTransport + PROCEDURE CODE id-downlinkUEAssociatedLPPaTransport + CRITICALITY ignore +} + +uplinkUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkUEAssociatedLPPaTransport + PROCEDURE CODE id-uplinkUEAssociatedLPPaTransport + CRITICALITY ignore +} +downlinkNonUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE DownlinkNonUEAssociatedLPPaTransport + PROCEDURE CODE id-downlinkNonUEAssociatedLPPaTransport + CRITICALITY ignore +} + +uplinkNonUEAssociatedLPPaTransport S1AP-ELEMENTARY-PROCEDURE ::= { + INITIATING MESSAGE UplinkNonUEAssociatedLPPaTransport + PROCEDURE CODE id-uplinkNonUEAssociatedLPPaTransport + CRITICALITY ignore +} + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU.asn b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU.asn new file mode 100644 index 0000000000..9a818d4e24 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/R9.8/S1AP-PDU.asn @@ -0,0 +1,413 @@ +S1AP-PDU { + itu-t (0) identified-organization (4) etsi (0) mobileDomain (0) + eps-Access (21) modules (3) s1ap (1) version1 (1) +} + +DEFINITIONS AUTOMATIC TAGS ::= + +BEGIN + +IMPORTS + Criticality, + ProcedureCode, + ProtocolIE-ID + +FROM S1AP-CommonDataTypes + + maxProtocolIEs + +FROM S1AP-Constants; + +S1AP-PDU ::= CHOICE { + initiatingMessage InitiatingMessage, + successfulOutcome SuccessfulOutcome, + unsuccessfulOutcome UnsuccessfulOutcome, + ... +} + +InitiatingMessage ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +SuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +UnsuccessfulOutcome ::= SEQUENCE { + procedureCode ProcedureCode, + criticality Criticality, + value ANY +} + +HandoverRequired ::= SEQUENCE { + handoverRequired-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCommand ::= SEQUENCE { + handoverCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverPreparationFailure ::= SEQUENCE { + handoverPreparationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequest ::= SEQUENCE { + handoverRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverRequestAcknowledge ::= SEQUENCE { + handoverRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverFailure ::= SEQUENCE { + handoverFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverNotify ::= SEQUENCE { + handoverNotify-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequest ::= SEQUENCE { + pathSwitchRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestAcknowledge ::= SEQUENCE { + pathSwitchRequestAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PathSwitchRequestFailure ::= SEQUENCE { + pathSwitchRequestFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupRequest ::= SEQUENCE { + e-RABSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABSetupResponse ::= SEQUENCE { + e-RABSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyRequest ::= SEQUENCE { + e-RABModifyRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABModifyResponse ::= SEQUENCE { + e-RABModifyResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseIndication ::= SEQUENCE { + e-RABReleaseIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseCommand ::= SEQUENCE { + e-RABReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +E-RABReleaseResponse ::= SEQUENCE { + e-RABReleaseResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupRequest ::= SEQUENCE { + initialContextSetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupResponse ::= SEQUENCE { + initialContextSetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialContextSetupFailure ::= SEQUENCE { + initialContextSetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseRequest ::= SEQUENCE { + ueContextReleaseRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Paging ::= SEQUENCE { + paging-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkNASTransport ::= SEQUENCE { + downlinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +InitialUEMessage ::= SEQUENCE { + initialUEMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkNASTransport ::= SEQUENCE { + uplinkNASTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +NASNonDeliveryIndication ::= SEQUENCE { + nasNonDeliveryIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancel ::= SEQUENCE { + handoverCancel-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +HandoverCancelAcknowledge ::= SEQUENCE { + handoverCancelAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +Reset ::= SEQUENCE { + reset-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ResetAcknowledge ::= SEQUENCE { + resetAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupResponse ::= SEQUENCE { + s1SetupResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupRequest ::= SEQUENCE { + s1SetupRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +S1SetupFailure ::= SEQUENCE +{ + s1SetupFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ErrorIndication ::= SEQUENCE { + errorIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdate ::= SEQUENCE { + eNBConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateAcknowledge ::= SEQUENCE { + eNBConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationUpdateFailure ::= SEQUENCE { + eNBConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdate ::= SEQUENCE { + mmeConfigurationUpdate-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateAcknowledge ::= SEQUENCE { + mmeConfigurationUpdateAcknowledge-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationUpdateFailure ::= SEQUENCE { + mmeConfigurationUpdateFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkS1cdma2000tunneling ::= SEQUENCE { + downlinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkS1cdma2000tunneling ::= SEQUENCE { + uplinkS1cdma2000tunneling-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationRequest ::= SEQUENCE { + ueContextModificationRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationResponse ::= SEQUENCE { + ueContextModificationResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextModificationFailure ::= SEQUENCE { + ueContextModificationFailure-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UECapabilityInfoIndication ::= SEQUENCE { + ueCapabilityInfoIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseCommand ::= SEQUENCE { + ueContextReleaseCommand-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UEContextReleaseComplete ::= SEQUENCE { + ueContextReleaseComplete-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBStatusTransfer ::= SEQUENCE { + eNBStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEStatusTransfer ::= SEQUENCE { + mmeStatusTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DeactivateTrace ::= SEQUENCE { + deactivateTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceStart ::= SEQUENCE { + traceStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +TraceFailureIndication ::= SEQUENCE { + traceFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +CellTrafficTrace ::= SEQUENCE { + cellTrafficTrace-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingControl ::= SEQUENCE { + locationReportingControl-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReportingFailureIndication ::= SEQUENCE { + locationReportingFailureIndication-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +LocationReport ::= SEQUENCE { + locationReport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStart ::= SEQUENCE { + overloadStart-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +OverloadStop ::= SEQUENCE { + overloadStop-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningRequest ::= SEQUENCE { + writeReplaceWarningRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +WriteReplaceWarningResponse ::= SEQUENCE { + writeReplaceWarningResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBDirectInformationTransfer ::= SEQUENCE { + eNBDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEDirectInformationTransfer ::= SEQUENCE { + mmeDirectInformationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +ENBConfigurationTransfer ::= SEQUENCE { + eNBConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +MMEConfigurationTransfer ::= SEQUENCE { + mmeConfigurationTransfer-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +PrivateMessage ::= SEQUENCE { + privateMessage-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +KillRequest ::= SEQUENCE { + killRequest-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +KillResponse ::= SEQUENCE { + killResponse-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkUEAssociatedLPPaTransport ::= SEQUENCE { + downlinkUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkUEAssociatedLPPaTransport ::= SEQUENCE { + uplinkUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +DownlinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + downlinkNonUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +UplinkNonUEAssociatedLPPaTransport ::= SEQUENCE { + uplinkNonUEAssociatedLPPaTransport-ies SEQUENCE (SIZE (0..maxProtocolIEs)) OF IE, + ... +} + +IE ::= SEQUENCE { + id ProtocolIE-ID, + criticality Criticality, + value ANY +} + +END \ No newline at end of file diff --git a/openair-cn/S1AP/MESSAGES/ASN1/README b/openair-cn/S1AP/MESSAGES/ASN1/README new file mode 100644 index 0000000000..c1d981ee5f --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/README @@ -0,0 +1,15 @@ +ASN1 message from S1AP TS 36.413-8a0 + +To successfully parse messages, the asn1c util should be patched with the patch provided (asn1cpatch.p0). +To do so: +1) Get the last revision of asn1c: svn co https://asn1c.svn.sourceforge.net/svnroot/asn1c/trunk asn1c +2) Go to asn1c directory +3) patch -p0 asn1cpatch.p0 +4) ./configure +5) make +6) make install + +Aligned PER support is now included when parsing and generating asn1 code. + +To generate S1AP ASN1 descriptions: +Files are automatically generated when changes are made on ASN1 files via Make build system. diff --git a/openair-cn/S1AP/MESSAGES/ASN1/asn1cpatch.p0 b/openair-cn/S1AP/MESSAGES/ASN1/asn1cpatch.p0 new file mode 100644 index 0000000000..17c13dfb53 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/asn1cpatch.p0 @@ -0,0 +1,4240 @@ +Index: skeletons/GeneralString.c +=================================================================== +--- skeletons/GeneralString.c (revision 1410) ++++ skeletons/GeneralString.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GeneralString_tags, + sizeof(asn_DEF_GeneralString_tags) +Index: skeletons/OCTET_STRING.c +=================================================================== +--- skeletons/OCTET_STRING.c (revision 1410) ++++ skeletons/OCTET_STRING.c (working copy) +@@ -36,6 +36,8 @@ + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ ++ OCTET_STRING_decode_aper, /* Aligned PER decoder */ ++ OCTET_STRING_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_OCTET_STRING_tags, + sizeof(asn_DEF_OCTET_STRING_tags) +@@ -86,7 +88,7 @@ + void *ptr; \ + /* Be nice and round to the memory allocator */ \ + do { _ns = _ns ? _ns << 1 : 16; } \ +- while(_ns <= _es); \ ++ while(_ns <= _es); \ + /* int is really a typeof(st->size): */ \ + if((int)_ns < 0) RETURN(RC_FAIL); \ + ptr = REALLOC(st->buf, _ns); \ +@@ -416,7 +418,7 @@ + ASN_DEBUG("Phase 2: Need %ld bytes, size=%ld, alrg=%ld, wn=%d", + (long)sel->left, (long)size, (long)sel->got, + sel->want_nulls); +- { ++ { + ber_tlv_len_t len; + + assert(sel->left >= 0); +@@ -446,7 +448,7 @@ + + PREV_PHASE(ctx); + goto phase1; +- } ++ } + break; + case 3: + phase3: +@@ -1194,14 +1196,14 @@ + static int + OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, +- long lb, long ub, asn_per_constraints_t *pc) { ++ int64_t lb, int64_t ub, asn_per_constraints_t *pc) { + uint8_t *end = buf + units * bpc; + +- ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", ++ ASN_DEBUG("Expanding %d characters into (%lld..%lld):%d", + (int)units, lb, ub, unit_bits); + + /* X.691: 27.5.4 */ +- if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { ++ if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) { + /* Decode without translation */ + lb = 0; + } else if(pc && pc->code2value) { +@@ -1216,7 +1218,7 @@ + value = pc->code2value(code); + if(value < 0) { + ASN_DEBUG("Code %d (0x%02x) is" +- " not in map (%ld..%ld)", ++ " not in map (%lld..%lld)", + code, code, lb, ub); + return 1; /* FATAL */ + } +@@ -1240,7 +1242,7 @@ + int ch = code + lb; + if(code < 0) return -1; /* WMORE */ + if(ch > ub) { +- ASN_DEBUG("Code %d is out of range (%ld..%ld)", ++ ASN_DEBUG("Code %d is out of range (%lld..%lld)", + ch, lb, ub); + return 1; /* FATAL */ + } +@@ -1258,14 +1260,14 @@ + static int + OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, + size_t units, unsigned int bpc, unsigned int unit_bits, +- long lb, long ub, asn_per_constraints_t *pc) { ++ int64_t lb, int64_t ub, asn_per_constraints_t *pc) { + const uint8_t *end = buf + units * bpc; + +- ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", ++ ASN_DEBUG("Squeezing %d characters into (%lld..%lld):%d (%d bpc)", + (int)units, lb, ub, unit_bits, bpc); + + /* X.691: 27.5.4 */ +- if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { ++ if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) { + /* Encode as is */ + lb = 0; + } else if(pc && pc->value2code) { +@@ -1282,7 +1284,7 @@ + code = pc->value2code(value); + if(code < 0) { + ASN_DEBUG("Character %d (0x%02x) is" +- " not in map (%ld..%ld)", ++ " not in map (%lld..%lld)", + *buf, *buf, lb, ub); + return -1; + } +@@ -1309,7 +1311,7 @@ + ch = value - lb; + if(ch < 0 || ch > ub) { + ASN_DEBUG("Character %d (0x%02x)" +- " is out of range (%ld..%ld)", ++ " is out of range (%lld..%lld)", + *buf, *buf, lb, ub + lb); + return -1; + } +@@ -1392,7 +1394,7 @@ + if(!st) RETURN(RC_FAIL); + } + +- ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", ++ ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); + +@@ -1423,17 +1425,17 @@ + if(csiz->effective_bits == 0) { + int ret; + if(bpc) { +- ASN_DEBUG("Encoding OCTET STRING size %ld", ++ ASN_DEBUG("Encoding OCTET STRING size %lld", + csiz->upper_bound); + ret = OCTET_STRING_per_get_characters(pd, st->buf, + csiz->upper_bound, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { +- ASN_DEBUG("Encoding BIT STRING size %ld", ++ ASN_DEBUG("Encoding BIT STRING size %lld", + csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, +- unit_bits * csiz->upper_bound); ++ unit_bits * csiz->upper_bound); + } + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += unit_bits * csiz->upper_bound; +@@ -1492,9 +1494,197 @@ + return rval; + } + ++asn_dec_rval_t ++OCTET_STRING_decode_aper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **sptr, asn_per_data_t *pd) { ++ ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ asn_per_constraints_t *pc = constraints ? constraints ++ : td->per_constraints; ++ asn_per_constraint_t *cval; ++ asn_per_constraint_t *csiz; ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ BIT_STRING_t *st = (BIT_STRING_t *)*sptr; ++ ssize_t consumed_myself = 0; ++ int repeat; ++ enum { ++ OS__BPC_BIT = 0, ++ OS__BPC_CHAR = 1, ++ OS__BPC_U16 = 2, ++ OS__BPC_U32 = 4 ++ } bpc; /* Bytes per character */ ++ unsigned int unit_bits; ++ unsigned int canonical_unit_bits; ++ ++ (void)opt_codec_ctx; ++ ++ if(pc) { ++ cval = &pc->value; ++ csiz = &pc->size; ++ } else { ++ cval = &asn_DEF_OCTET_STRING_constraints.value; ++ csiz = &asn_DEF_OCTET_STRING_constraints.size; ++ } ++ ++ switch(specs->subvariant) { ++ default: ++// case ASN_OSUBV_ANY: ++// ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); ++// RETURN(RC_FAIL); ++ case ASN_OSUBV_BIT: ++ canonical_unit_bits = unit_bits = 1; ++ bpc = OS__BPC_BIT; ++ break; ++ case ASN_OSUBV_ANY: ++ case ASN_OSUBV_STR: ++ canonical_unit_bits = unit_bits = 8; ++// if(cval->flags & APC_CONSTRAINED) ++// unit_bits = cval->range_bits; ++ bpc = OS__BPC_CHAR; ++ break; ++ case ASN_OSUBV_U16: ++ canonical_unit_bits = unit_bits = 16; ++ if(cval->flags & APC_CONSTRAINED) ++ unit_bits = cval->range_bits; ++ bpc = OS__BPC_U16; ++ break; ++ case ASN_OSUBV_U32: ++ canonical_unit_bits = unit_bits = 32; ++ if(cval->flags & APC_CONSTRAINED) ++ unit_bits = cval->range_bits; ++ bpc = OS__BPC_U32; ++ break; ++ } ++ ++ /* ++ * Allocate the string. ++ */ ++ if(!st) { ++ st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); ++ if(!st) RETURN(RC_FAIL); ++ } ++ ++ ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d", ++ csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", ++ csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); ++ ++ if(csiz->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) RETURN(RC_WMORE); ++ if(inext) { ++ csiz = &asn_DEF_OCTET_STRING_constraints.size; ++ cval = &asn_DEF_OCTET_STRING_constraints.value; ++ unit_bits = canonical_unit_bits; ++ } ++ } ++ ++ if(csiz->effective_bits >= 0) { ++ FREEMEM(st->buf); ++ if(bpc) { ++ st->size = csiz->upper_bound * bpc; ++ } else { ++ st->size = (csiz->upper_bound + 7) >> 3; ++ } ++ st->buf = (uint8_t *)MALLOC(st->size + 1); ++ if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } ++ } ++ ++ /* X.691, #16.5: zero-length encoding */ ++ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ ++ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ ++ if(csiz->effective_bits == 0) { ++ int ret; ++ if (st->size > 2) { /* X.691 #16 NOTE 1 */ ++ if (aper_get_align(pd) < 0) ++ RETURN(RC_FAIL); ++ } ++ if(bpc) { ++ ASN_DEBUG("Decoding OCTET STRING size %lld", ++ csiz->upper_bound); ++ ret = OCTET_STRING_per_get_characters(pd, st->buf, ++ csiz->upper_bound, bpc, unit_bits, ++ cval->lower_bound, cval->upper_bound, pc); ++ if(ret > 0) RETURN(RC_FAIL); ++ } else { ++ ASN_DEBUG("Decoding BIT STRING size %lld", ++ csiz->upper_bound); ++ ret = per_get_many_bits(pd, st->buf, 0, ++ unit_bits * csiz->upper_bound); ++ } ++ if(ret < 0) RETURN(RC_WMORE); ++ consumed_myself += unit_bits * csiz->upper_bound; ++ st->buf[st->size] = 0; ++ if(bpc == 0) { ++ int ubs = (csiz->upper_bound & 0x7); ++ st->bits_unused = ubs ? 8 - ubs : 0; ++ } ++ RETURN(RC_OK); ++ } ++ ++ st->size = 0; ++ do { ++ ssize_t raw_len; ++ ssize_t len_bytes; ++ ssize_t len_bits; ++ void *p; ++ int ret; ++ ++ /* Get the PER length */ ++ if (csiz->upper_bound - csiz->lower_bound == 0) ++ // Indefinite length case ++ raw_len = aper_get_length(pd, -1, csiz->effective_bits, &repeat); ++ else ++ raw_len = aper_get_length(pd, csiz->upper_bound - csiz->lower_bound + 1, csiz->effective_bits, &repeat); ++ repeat = 0; ++ if(raw_len < 0) RETURN(RC_WMORE); ++ raw_len += csiz->lower_bound; ++ ++ ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", ++ (long)csiz->effective_bits, (long)raw_len, ++ repeat ? "repeat" : "once", td->name); ++ ++ if (raw_len > 2) { /* X.691 #16 NOTE 1 */ ++ if (aper_get_align(pd) < 0) ++ RETURN(RC_FAIL); ++ } ++ ++ if(bpc) { ++ len_bytes = raw_len * bpc; ++ len_bits = len_bytes * unit_bits; ++ } else { ++ len_bits = raw_len; ++ len_bytes = (len_bits + 7) >> 3; ++ if(len_bits & 0x7) ++ st->bits_unused = 8 - (len_bits & 0x7); ++ /* len_bits be multiple of 16K if repeat is set */ ++ } ++ p = REALLOC(st->buf, st->size + len_bytes + 1); ++ if(!p) RETURN(RC_FAIL); ++ st->buf = (uint8_t *)p; ++ ++ if(bpc) { ++ ret = OCTET_STRING_per_get_characters(pd, ++ &st->buf[st->size], raw_len, bpc, unit_bits, ++ cval->lower_bound, cval->upper_bound, pc); ++ if(ret > 0) RETURN(RC_FAIL); ++ } else { ++ ret = per_get_many_bits(pd, &st->buf[st->size], ++ 0, len_bits); ++ } ++ if(ret < 0) RETURN(RC_WMORE); ++ st->size += len_bytes; ++ } while(repeat); ++ st->buf[st->size] = 0; /* nul-terminate */ ++ ++ return rval; ++} ++ + asn_enc_rval_t + OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, +- asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics +@@ -1566,7 +1756,7 @@ + } + + ASN_DEBUG("Encoding %s into %d units of %d bits" +- " (%ld..%ld, effective %d)%s", ++ " (%lld..%lld, effective %d)%s", + td->name, sizeinunits, unit_bits, + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); +@@ -1598,7 +1788,7 @@ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(csiz->effective_bits >= 0) { +- ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", ++ ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits", + st->size, sizeinunits - csiz->lower_bound, + csiz->effective_bits); + ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, +@@ -1652,6 +1842,173 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ ++ asn_OCTET_STRING_specifics_t *specs = td->specifics ++ ? (asn_OCTET_STRING_specifics_t *)td->specifics ++ : &asn_DEF_OCTET_STRING_specs; ++ asn_per_constraints_t *pc = constraints ? constraints ++ : td->per_constraints; ++ asn_per_constraint_t *cval; ++ asn_per_constraint_t *csiz; ++ const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; ++ asn_enc_rval_t er = { 0, 0, 0 }; ++ int inext = 0; /* Lies not within extension root */ ++ unsigned int unit_bits; ++ unsigned int canonical_unit_bits; ++ unsigned int sizeinunits; ++ const uint8_t *buf; ++ int ret; ++ enum { ++ OS__BPC_BIT = 0, ++ OS__BPC_CHAR = 1, ++ OS__BPC_U16 = 2, ++ OS__BPC_U32 = 4 ++ } bpc; /* Bytes per character */ ++ int ct_extensible; ++ ++ if(!st || (!st->buf && st->size)) ++ _ASN_ENCODE_FAILED; ++ ++ if(pc) { ++ cval = &pc->value; ++ csiz = &pc->size; ++ } else { ++ cval = &asn_DEF_OCTET_STRING_constraints.value; ++ csiz = &asn_DEF_OCTET_STRING_constraints.size; ++ } ++ ct_extensible = csiz->flags & APC_EXTENSIBLE; ++ ++ switch(specs->subvariant) { ++ default: ++// case ASN_OSUBV_ANY: ++// _ASN_ENCODE_FAILED; ++ case ASN_OSUBV_BIT: ++ canonical_unit_bits = unit_bits = 1; ++ bpc = OS__BPC_BIT; ++ sizeinunits = st->size * 8 - (st->bits_unused & 0x07); ++ ASN_DEBUG("BIT STRING of %d bits", ++ sizeinunits); ++ break; ++ case ASN_OSUBV_ANY: ++ case ASN_OSUBV_STR: ++ canonical_unit_bits = unit_bits = 8; ++// if(cval->flags & APC_CONSTRAINED) ++// unit_bits = 8; ++ bpc = OS__BPC_CHAR; ++ sizeinunits = st->size; ++ break; ++ case ASN_OSUBV_U16: ++ canonical_unit_bits = unit_bits = 16; ++ if(cval->flags & APC_CONSTRAINED) ++ unit_bits = cval->range_bits; ++ bpc = OS__BPC_U16; ++ sizeinunits = st->size / 2; ++ break; ++ case ASN_OSUBV_U32: ++ canonical_unit_bits = unit_bits = 32; ++ if(cval->flags & APC_CONSTRAINED) ++ unit_bits = cval->range_bits; ++ bpc = OS__BPC_U32; ++ sizeinunits = st->size / 4; ++ break; ++ } ++ ++ ASN_DEBUG("Encoding %s into %d units of %d bits" ++ " (%lld..%lld, effective %d)%s", ++ td->name, sizeinunits, unit_bits, ++ csiz->lower_bound, csiz->upper_bound, ++ csiz->effective_bits, ct_extensible ? " EXT" : ""); ++ ++ /* Figure out wheter size lies within PER visible constraint */ ++ ++ if(csiz->effective_bits >= 0) { ++ if((int)sizeinunits < csiz->lower_bound ++ || (int)sizeinunits > csiz->upper_bound) { ++ if(ct_extensible) { ++ cval = &asn_DEF_OCTET_STRING_constraints.value; ++ csiz = &asn_DEF_OCTET_STRING_constraints.size; ++ unit_bits = canonical_unit_bits; ++ inext = 1; ++ } else ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ inext = 0; ++ } ++ ++ ++ if(ct_extensible) { ++ /* Declare whether length is [not] within extension root */ ++ if(per_put_few_bits(po, inext, 1)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* X.691, #16.5: zero-length encoding */ ++ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ ++ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ ++ if(csiz->effective_bits >= 0) { ++ ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits", ++ st->size, sizeinunits - csiz->lower_bound, ++ csiz->effective_bits); ++ ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, ++ csiz->effective_bits); ++ if(ret) _ASN_ENCODE_FAILED; ++ if (st->size > 2) { /* X.691 #16 NOTE 1 */ ++ if (aper_put_align(po) < 0) ++ _ASN_ENCODE_FAILED; ++ } ++ if(bpc) { ++ ret = OCTET_STRING_per_put_characters(po, st->buf, ++ sizeinunits, bpc, unit_bits, ++ cval->lower_bound, cval->upper_bound, pc); ++ } else { ++ ret = per_put_many_bits(po, st->buf, ++ sizeinunits * unit_bits); ++ } ++ if(ret) _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ ASN_DEBUG("Encoding %d bytes", st->size); ++ ++ if(sizeinunits == 0) { ++ if(aper_put_length(po, -1, 0)) ++ _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ buf = st->buf; ++ while(sizeinunits) { ++ ssize_t maySave = aper_put_length(po, -1, sizeinunits); ++ ++ if(maySave < 0) _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Encoding %ld of %ld", ++ (long)maySave, (long)sizeinunits); ++ ++ if(bpc) { ++ ret = OCTET_STRING_per_put_characters(po, buf, ++ maySave, bpc, unit_bits, ++ cval->lower_bound, cval->upper_bound, pc); ++ } else { ++ ret = per_put_many_bits(po, buf, maySave * unit_bits); ++ } ++ if(ret) _ASN_ENCODE_FAILED; ++ ++ if(bpc) ++ buf += maySave * bpc; ++ else ++ buf += maySave >> 3; ++ sizeinunits -= maySave; ++ assert(!(maySave & 0x07) || !sizeinunits); ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ + int + OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { +Index: skeletons/IA5String.c +=================================================================== +--- skeletons/IA5String.c (revision 1410) ++++ skeletons/IA5String.c (working copy) +@@ -29,6 +29,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_IA5String_tags, + sizeof(asn_DEF_IA5String_tags) +Index: skeletons/OBJECT_IDENTIFIER.c +=================================================================== +--- skeletons/OBJECT_IDENTIFIER.c (revision 1410) ++++ skeletons/OBJECT_IDENTIFIER.c (working copy) +@@ -26,6 +26,8 @@ + OBJECT_IDENTIFIER_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_OBJECT_IDENTIFIER_tags, + sizeof(asn_DEF_OBJECT_IDENTIFIER_tags) +Index: skeletons/GeneralizedTime.c +=================================================================== +--- skeletons/GeneralizedTime.c (revision 1410) ++++ skeletons/GeneralizedTime.c (working copy) +@@ -167,6 +167,8 @@ + GeneralizedTime_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GeneralizedTime_tags, + sizeof(asn_DEF_GeneralizedTime_tags) +Index: skeletons/OCTET_STRING.h +=================================================================== +--- skeletons/OCTET_STRING.h (revision 1410) ++++ skeletons/OCTET_STRING.h (working copy) +@@ -32,6 +32,8 @@ + xer_type_encoder_f OCTET_STRING_encode_xer_utf8; + per_type_decoder_f OCTET_STRING_decode_uper; + per_type_encoder_f OCTET_STRING_encode_uper; ++per_type_decoder_f OCTET_STRING_decode_aper; ++per_type_encoder_f OCTET_STRING_encode_aper; + + /****************************** + * Handy conversion routines. * +Index: skeletons/constr_TYPE.h +=================================================================== +--- skeletons/constr_TYPE.h (revision 1410) ++++ skeletons/constr_TYPE.h (working copy) +@@ -99,6 +99,8 @@ + xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ + per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ ++ per_type_decoder_f *aper_decoder; /* Aligned PER decoder */ ++ per_type_encoder_f *aper_encoder; /* Aligned PER encoder */ + + /*********************************************************************** + * Internally useful members. Not to be used by applications directly. * +Index: skeletons/constr_CHOICE.c +=================================================================== +--- skeletons/constr_CHOICE.c (revision 1410) ++++ skeletons/constr_CHOICE.c (working copy) +@@ -904,7 +904,88 @@ + elm->name, td->name, rv.code); + return rv; + } +- ++ ++asn_dec_rval_t ++CHOICE_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_dec_rval_t rv; ++ asn_per_constraint_t *ct; ++ asn_TYPE_member_t *elm; /* CHOICE's element */ ++ void *memb_ptr; ++ void **memb_ptr2; ++ void *st = *sptr; ++ int value; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else ct = 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ value = per_get_few_bits(pd, 1); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value) ct = 0; /* Not restricted */ ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ ASN_DEBUG("CHOICE %s got index %d in range %d", ++ td->name, value, ct->range_bits); ++ if(value > ct->upper_bound) ++ _ASN_DECODE_FAILED; ++ } else { ++ if(specs->ext_start == -1) ++ _ASN_DECODE_FAILED; ++ value = uper_get_nsnnwn(pd); ++ if(value < 0) _ASN_DECODE_STARVED; ++ value += specs->ext_start; ++ if(value >= td->elements_count) ++ _ASN_DECODE_FAILED; ++ } ++ ++ /* Adjust if canonical order is different from natural order */ ++ if(specs->canonical_order) ++ value = specs->canonical_order[value]; ++ ++ /* Set presence to be able to free it later */ ++ _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); ++ ++ elm = &td->elements[value]; ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); ++ ++ if(ct && ct->range_bits >= 0) { ++ rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ } else { ++ rv = uper_open_type_get(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ } ++ ++ if(rv.code != RC_OK) ++ ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", ++ elm->name, td->name, rv.code); ++ return rv; ++} ++ + asn_enc_rval_t + CHOICE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { +@@ -916,7 +997,7 @@ + + if(!sptr) _ASN_ENCODE_FAILED; + +- ASN_DEBUG("Encoding %s as CHOICE", td->name); ++ ASN_DEBUG("Encoding %s as CHOICE using UPER", td->name); + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; +@@ -984,8 +1065,88 @@ + _ASN_ENCODED_OK(rval); + } + } +- + ++asn_enc_rval_t ++CHOICE_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm; /* CHOICE's element */ ++ asn_per_constraint_t *ct; ++ void *memb_ptr; ++ int present; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Encoding %s as CHOICE using ALIGNED PER", td->name); ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else ct = 0; ++ ++ present = _fetch_present_idx(sptr, ++ specs->pres_offset, specs->pres_size); ++ ++ /* ++ * If the structure was not initialized properly, it cannot be encoded: ++ * can't deduce what to encode in the choice type. ++ */ ++ if(present <= 0 || present > td->elements_count) ++ _ASN_ENCODE_FAILED; ++ else ++ present--; ++ ++ /* Adjust if canonical order is different from natural order */ ++ if(specs->canonical_order) ++ present = specs->canonical_order[present]; ++ ++ ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); ++ ++ if(ct && ct->range_bits >= 0) { ++ if(present < ct->lower_bound ++ || present > ct->upper_bound) { ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, 1, 1)) ++ _ASN_ENCODE_FAILED; ++ } else { ++ _ASN_ENCODE_FAILED; ++ } ++ ct = 0; ++ } ++ } ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, 0, 1)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ elm = &td->elements[present]; ++ if(elm->flags & ATF_POINTER) { ++ /* Member is a pointer to another structure */ ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) _ASN_ENCODE_FAILED; ++ } else { ++ memb_ptr = (char *)sptr + elm->memb_offset; ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ if(per_put_few_bits(po, present, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ ++ return elm->type->aper_encoder(elm->type, elm->per_constraints, ++ memb_ptr, po); ++ } else { ++ asn_enc_rval_t rval; ++ if(specs->ext_start == -1) ++ _ASN_ENCODE_FAILED; ++ if(aper_put_nsnnwn(po, ct->range_bits, present - specs->ext_start)) ++ _ASN_ENCODE_FAILED; ++ if(aper_open_type_put(elm->type, elm->per_constraints, ++ memb_ptr, po)) ++ _ASN_ENCODE_FAILED; ++ rval.encoded = 0; ++ _ASN_ENCODED_OK(rval); ++ } ++} ++ + int + CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, + asn_app_consume_bytes_f *cb, void *app_key) { +Index: skeletons/REAL.c +=================================================================== +--- skeletons/REAL.c (revision 1410) ++++ skeletons/REAL.c (working copy) +@@ -45,6 +45,8 @@ + REAL_encode_xer, + REAL_decode_uper, + REAL_encode_uper, ++ REAL_decode_aper, ++ REAL_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_REAL_tags, + sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]), +@@ -358,6 +360,21 @@ + return OCTET_STRING_encode_uper(td, 0, sptr, po); + } + ++asn_dec_rval_t ++REAL_decode_aper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **sptr, asn_per_data_t *pd) { ++ (void)constraints; /* No PER visible constraints */ ++ return OCTET_STRING_decode_aper(opt_codec_ctx, td, 0, sptr, pd); ++} ++ ++asn_enc_rval_t ++REAL_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ (void)constraints; /* No PER visible constraints */ ++ return OCTET_STRING_encode_aper(td, 0, sptr, po); ++} ++ + int + asn_REAL2double(const REAL_t *st, double *dbl_value) { + unsigned int octv; +Index: skeletons/constr_SET.c +=================================================================== +--- skeletons/constr_SET.c (revision 1410) ++++ skeletons/constr_SET.c (working copy) +@@ -570,6 +570,181 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++SET_encode_uper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, ++ void *sptr, ++ asn_per_outp_t *po) { ++} ++ ++asn_dec_rval_t ++SET_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++} ++ ++asn_enc_rval_t ++SET_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, ++ void *sptr, ++ asn_per_outp_t *po) { ++ asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ int edx, i; ++ int t2m_build_own = (specs->tag2el_count != td->elements_count); ++ asn_TYPE_tag2member_t *t2m; ++ int t2m_count; ++ ++ (void)constraints; ++ ++ if(!sptr) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ ASN_DEBUG("Encoding %s as SET (APER) map %d", td->name, specs->_mandatory_elements[0]); ++ ++ /* ++ * Use existing, or build our own tags map. ++ */ ++ if(t2m_build_own) { ++ t2m = (asn_TYPE_tag2member_t *)alloca( ++ td->elements_count * sizeof(t2m[0])); ++ if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */ ++ t2m_count = 0; ++ } else { ++ /* ++ * There is no untagged CHOICE in this SET. ++ * Employ existing table. ++ */ ++ t2m = specs->tag2el; ++ t2m_count = specs->tag2el_count; ++ } ++ ++ /* ++ * Gather the length of the underlying members sequence. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ asn_enc_rval_t tmper; ++ void *memb_ptr; ++ ++ /* ++ * Compute the length of the encoding of this member. ++ */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr = *(void **)((char *)sptr + elm->memb_offset); ++ if(!memb_ptr) { ++ if(!elm->optional) ++ /* Mandatory elements missing */ ++ _ASN_ENCODE_FAILED; ++ if(t2m_build_own) { ++ t2m[t2m_count].el_no = edx; ++ t2m[t2m_count].el_tag = 0; ++ t2m_count++; ++ } ++ continue; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ } ++ ++ /* ++ * Remember the outmost tag of this member. ++ */ ++ if(t2m_build_own) { ++ t2m[t2m_count].el_no = edx; ++ t2m[t2m_count].el_tag = asn_TYPE_outmost_tag( ++ elm->type, memb_ptr, elm->tag_mode, elm->tag); ++ t2m_count++; ++ } else { ++ /* ++ * No dynamic sorting is necessary. ++ */ ++ } ++ } ++ ++ /* ++ * Finalize order of the components. ++ */ ++ assert(t2m_count == td->elements_count); ++ if(t2m_build_own) { ++ /* ++ * Sort the underlying members according to their ++ * canonical tags order. DER encoding mandates it. ++ */ ++ qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp); ++ } else { ++ /* ++ * Tags are already sorted by the compiler. ++ */ ++ } ++ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[t2m[edx].el_no]; ++ asn_enc_rval_t tmper; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ int present; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ present = (*memb_ptr2 != 0); ++ } else { ++// memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++// memb_ptr2 = &memb_ptr; ++ present = 1; ++ continue; ++ } ++ ++// /* Eliminate default values */ ++// if(present && elm->default_value ++// && elm->default_value(0, memb_ptr2) == 1) ++// present = 0; ++ ++ ASN_DEBUG("Element %s %s %s->%s is %s", ++ elm->flags & ATF_POINTER ? "ptr" : "inline", ++ elm->default_value ? "def" : "wtv", ++ td->name, elm->name, present ? "present" : "absent"); ++ if(per_put_few_bits(po, present << 7, 8)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* ++ * Encode all members. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ asn_enc_rval_t tmper; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ /* Encode according to the tag order */ ++// elm = &td->elements[t2m[edx].el_no]; ++ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ if(!*memb_ptr2) { ++ ASN_DEBUG("Element %s %d not present", ++ elm->name, edx); ++ if(elm->optional) ++ continue; ++ /* Mandatory element is missing */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ } ++ tmper = elm->type->aper_encoder(elm->type, elm->per_constraints, ++ *memb_ptr2, po); ++ if(tmper.encoded == -1) ++ return tmper; ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ + #undef XER_ADVANCE + #define XER_ADVANCE(num_bytes) do { \ + size_t num = num_bytes; \ +Index: skeletons/constr_SEQUENCE_OF.c +=================================================================== +--- skeletons/constr_SEQUENCE_OF.c (revision 1410) ++++ skeletons/constr_SEQUENCE_OF.c (working copy) +@@ -164,7 +164,7 @@ + if(ct) { + int not_in_root = (list->count < ct->lower_bound + || list->count > ct->upper_bound); +- ASN_DEBUG("lb %ld ub %ld %s", ++ ASN_DEBUG("lb %lld ub %lld %s", + ct->lower_bound, ct->upper_bound, + ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { +@@ -206,3 +206,70 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++SEQUENCE_OF_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_anonymous_sequence_ *list; ++ asn_per_constraint_t *ct; ++ asn_enc_rval_t er; ++ asn_TYPE_member_t *elm = td->elements; ++ int seq; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ list = _A_SEQUENCE_FROM_VOID(sptr); ++ ++ er.encoded = 0; ++ ++ ASN_DEBUG("Encoding %s as SEQUENCE OF size (%d) using ALIGNED PER", td->name, list->count); ++ ++ if(constraints) ct = &constraints->size; ++ else if(td->per_constraints) ct = &td->per_constraints->size; ++ else ct = 0; ++ ++ /* If extensible constraint, check if size is in root */ ++ if(ct) { ++ int not_in_root = (list->count < ct->lower_bound ++ || list->count > ct->upper_bound); ++ ASN_DEBUG("lb %lld ub %lld %s", ++ ct->lower_bound, ct->upper_bound, ++ ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); ++ if(ct->flags & APC_EXTENSIBLE) { ++ /* Declare whether size is in extension root */ ++ if(per_put_few_bits(po, not_in_root, 1)) ++ _ASN_ENCODE_FAILED; ++ if(not_in_root) ct = 0; ++ } else if(not_in_root && ct->effective_bits >= 0) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ if(ct && ct->effective_bits >= 0) { ++ /* X.691, #19.5: No length determinant */ ++// if(per_put_few_bits(po, list->count - ct->lower_bound, ++// ct->effective_bits)) ++// _ASN_ENCODE_FAILED; ++ if (aper_put_length(po, ct->upper_bound - ct->lower_bound + 1, list->count - ct->lower_bound) < 0) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ for(seq = -1; seq < list->count;) { ++ ssize_t mayEncode; ++ if(seq < 0) seq = 0; ++ if(ct && ct->effective_bits >= 0) { ++ mayEncode = list->count; ++ } else { ++ mayEncode = aper_put_length(po, -1, list->count - seq); ++ if(mayEncode < 0) _ASN_ENCODE_FAILED; ++ } ++ ++ while(mayEncode--) { ++ void *memb_ptr = list->array[seq++]; ++ if(!memb_ptr) _ASN_ENCODE_FAILED; ++ er = elm->type->aper_encoder(elm->type, ++ elm->per_constraints, memb_ptr, po); ++ if(er.encoded == -1) ++ _ASN_ENCODE_FAILED; ++ } ++ } ++ ++ _ASN_ENCODED_OK(er); ++} +Index: skeletons/per_encoder.c +=================================================================== +--- skeletons/per_encoder.c (revision 1410) ++++ skeletons/per_encoder.c (working copy) +@@ -4,6 +4,7 @@ + + static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); + ++static asn_enc_rval_t aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); + asn_enc_rval_t + uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + return uper_encode_internal(td, 0, sptr, cb, app_key); +@@ -41,6 +42,18 @@ + return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); + } + ++asn_enc_rval_t ++aper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { ++ enc_to_buf_arg key; ++ ++ key.buffer = buffer; ++ key.left = buffer_size; ++ ++ if(td) ASN_DEBUG("Encoding \"%s\" using ALIGNED PER", td->name); ++ ++ return aper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); ++} ++ + typedef struct enc_dyn_arg { + void *buffer; + size_t length; +@@ -93,6 +106,35 @@ + } + } + ++ssize_t ++aper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) { ++ asn_enc_rval_t er; ++ enc_dyn_arg key; ++ ++ memset(&key, 0, sizeof(key)); ++ ++ er = aper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key); ++ switch(er.encoded) { ++ case -1: ++ FREEMEM(key.buffer); ++ return -1; ++ case 0: ++ FREEMEM(key.buffer); ++ key.buffer = MALLOC(1); ++ if(key.buffer) { ++ *(char *)key.buffer = '\0'; ++ *buffer_r = key.buffer; ++ return 1; ++ } else { ++ return -1; ++ } ++ default: ++ *buffer_r = key.buffer; ++ ASN_DEBUG("Complete encoded in %d bits", er.encoded); ++ return ((er.encoded + 7) >> 3); ++ } ++} ++ + /* + * Internally useful functions. + */ +@@ -115,6 +157,23 @@ + return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); + } + ++static int ++_aper_encode_flush_outp(asn_per_outp_t *po) { ++ uint8_t *buf; ++ ++ if(po->nboff == 0 && po->buffer == po->tmpspace) ++ return 0; ++ ++ buf = po->buffer + (po->nboff >> 3); ++ /* Make sure we account for the last, partially filled */ ++ if(po->nboff & 0x07) { ++ buf[0] &= 0xff << (8 - (po->nboff & 0x07)); ++ buf++; ++ } ++ ++ return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); ++} ++ + static asn_enc_rval_t + uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + asn_per_outp_t po; +@@ -149,3 +208,37 @@ + return er; + } + ++static asn_enc_rval_t ++aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { ++ asn_per_outp_t po; ++ asn_enc_rval_t er; ++ ++ /* ++ * Invoke type-specific encoder. ++ */ ++ if(!td || !td->aper_encoder) ++ _ASN_ENCODE_FAILED; /* PER is not compiled in */ ++ ++ po.buffer = po.tmpspace; ++ po.nboff = 0; ++ po.nbits = 8 * sizeof(po.tmpspace); ++ po.outper = cb; ++ po.op_key = app_key; ++ po.flushed_bytes = 0; ++ ++ er = td->aper_encoder(td, constraints, sptr, &po); ++ if(er.encoded != -1) { ++ size_t bits_to_flush; ++ ++ bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; ++ ++ /* Set number of bits encoded to a firm value */ ++ er.encoded = (po.flushed_bytes << 3) + bits_to_flush; ++ ++ if(_aper_encode_flush_outp(&po)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ return er; ++} ++ +Index: skeletons/constr_CHOICE.h +=================================================================== +--- skeletons/constr_CHOICE.h (revision 1410) ++++ skeletons/constr_CHOICE.h (working copy) +@@ -48,6 +48,8 @@ + xer_type_encoder_f CHOICE_encode_xer; + per_type_decoder_f CHOICE_decode_uper; + per_type_encoder_f CHOICE_encode_uper; ++per_type_decoder_f CHOICE_decode_aper; ++per_type_encoder_f CHOICE_encode_aper; + asn_outmost_tag_f CHOICE_outmost_tag; + + #ifdef __cplusplus +Index: skeletons/constr_SET.h +=================================================================== +--- skeletons/constr_SET.h (revision 1410) ++++ skeletons/constr_SET.h (working copy) +@@ -53,7 +53,9 @@ + xer_type_decoder_f SET_decode_xer; + xer_type_encoder_f SET_encode_xer; + per_type_decoder_f SET_decode_uper; ++per_type_decoder_f SET_decode_aper; + per_type_encoder_f SET_encode_uper; ++per_type_encoder_f SET_encode_aper; + + /*********************** + * Some handy helpers. * +Index: skeletons/REAL.h +=================================================================== +--- skeletons/REAL.h (revision 1410) ++++ skeletons/REAL.h (working copy) +@@ -21,6 +21,8 @@ + xer_type_encoder_f REAL_encode_xer; + per_type_decoder_f REAL_decode_uper; + per_type_encoder_f REAL_encode_uper; ++per_type_decoder_f REAL_decode_aper; ++per_type_encoder_f REAL_encode_aper; + + /*********************************** + * Some handy conversion routines. * +Index: skeletons/ENUMERATED.c +=================================================================== +--- skeletons/ENUMERATED.c (revision 1410) ++++ skeletons/ENUMERATED.c (working copy) +@@ -26,6 +26,8 @@ + INTEGER_encode_xer, + ENUMERATED_decode_uper, /* Unaligned PER decoder */ + ENUMERATED_encode_uper, /* Unaligned PER encoder */ ++ ENUMERATED_decode_aper, /* Aligned PER decoder */ ++ ENUMERATED_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ENUMERATED_tags, + sizeof(asn_DEF_ENUMERATED_tags) / sizeof(asn_DEF_ENUMERATED_tags[0]), +@@ -57,6 +59,27 @@ + return rval; + } + ++asn_dec_rval_t ++ENUMERATED_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rval; ++ ENUMERATED_t *st = (ENUMERATED_t *)*sptr; ++ long value; ++ void *vptr = &value; ++ ++ if(!st) { ++ st = (ENUMERATED_t *)(*sptr = CALLOC(1, sizeof(*st))); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ rval = NativeEnumerated_decode_aper(opt_codec_ctx, td, constraints, ++ (void **)&vptr, pd); ++ if(rval.code == RC_OK) ++ if(asn_long2INTEGER(st, value)) ++ rval.code = RC_FAIL; ++ return rval; ++} ++ + asn_enc_rval_t + ENUMERATED_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { +@@ -69,3 +92,14 @@ + return NativeEnumerated_encode_uper(td, constraints, &value, po); + } + ++asn_enc_rval_t ++ENUMERATED_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ ENUMERATED_t *st = (ENUMERATED_t *)sptr; ++ long value; ++ ++ if(asn_INTEGER2long(st, &value)) ++ _ASN_ENCODE_FAILED; ++ ++ return NativeEnumerated_encode_aper(td, constraints, &value, po); ++} +Index: skeletons/constr_SEQUENCE_OF.h +=================================================================== +--- skeletons/constr_SEQUENCE_OF.h (revision 1410) ++++ skeletons/constr_SEQUENCE_OF.h (working copy) +@@ -22,9 +22,11 @@ + #define SEQUENCE_OF_decode_ber SET_OF_decode_ber + #define SEQUENCE_OF_decode_xer SET_OF_decode_xer + #define SEQUENCE_OF_decode_uper SET_OF_decode_uper ++#define SEQUENCE_OF_decode_aper SET_OF_decode_aper + der_type_encoder_f SEQUENCE_OF_encode_der; + xer_type_encoder_f SEQUENCE_OF_encode_xer; + per_type_encoder_f SEQUENCE_OF_encode_uper; ++per_type_encoder_f SEQUENCE_OF_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/per_encoder.h +=================================================================== +--- skeletons/per_encoder.h (revision 1410) ++++ skeletons/per_encoder.h (working copy) +@@ -38,6 +38,12 @@ + size_t buffer_size /* Initial buffer size (max) */ + ); + ++asn_enc_rval_t aper_encode_to_buffer( ++ struct asn_TYPE_descriptor_s *type_descriptor, ++ void *struct_ptr, /* Structure to be encoded */ ++ void *buffer, /* Pre-allocated buffer */ ++ size_t buffer_size /* Initial buffer size (max) */ ++); + /* + * A variant of uper_encode_to_buffer() which allocates buffer itself. + * Returns the number of bytes in the buffer or -1 in case of failure. +@@ -52,6 +58,11 @@ + void **buffer_r /* Buffer allocated and returned */ + ); + ++ssize_t ++aper_encode_to_new_buffer(struct asn_TYPE_descriptor_s *td, ++ asn_per_constraints_t *constraints, ++ void *sptr, ++ void **buffer_r); + /* + * Type of the generic PER encoder function. + */ +Index: skeletons/ENUMERATED.h +=================================================================== +--- skeletons/ENUMERATED.h (revision 1410) ++++ skeletons/ENUMERATED.h (working copy) +@@ -17,6 +17,8 @@ + + per_type_decoder_f ENUMERATED_decode_uper; + per_type_encoder_f ENUMERATED_encode_uper; ++per_type_decoder_f ENUMERATED_decode_aper; ++per_type_encoder_f ENUMERATED_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/NativeInteger.c +=================================================================== +--- skeletons/NativeInteger.c (revision 1410) ++++ skeletons/NativeInteger.c (working copy) +@@ -31,6 +31,8 @@ + NativeInteger_encode_xer, + NativeInteger_decode_uper, /* Unaligned PER decoder */ + NativeInteger_encode_uper, /* Unaligned PER encoder */ ++ NativeInteger_decode_aper, /* Aligned PER decoder */ ++ NativeInteger_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeInteger_tags, + sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), +@@ -107,7 +109,7 @@ + tmp.size = length; + + if((specs&&specs->field_unsigned) +- ? asn_INTEGER2ulong(&tmp, &l) ++ ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) + : asn_INTEGER2long(&tmp, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; +@@ -187,7 +189,7 @@ + if(rval.code == RC_OK) { + long l; + if((specs&&specs->field_unsigned) +- ? asn_INTEGER2ulong(&st, &l) ++ ? asn_INTEGER2ulong(&st, (unsigned long *)&l) + : asn_INTEGER2long(&st, &l)) { + rval.code = RC_FAIL; + rval.consumed = 0; +@@ -255,7 +257,7 @@ + &tmpintptr, pd); + if(rval.code == RC_OK) { + if((specs&&specs->field_unsigned) +- ? asn_INTEGER2ulong(&tmpint, native) ++ ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) + : asn_INTEGER2long(&tmpint, native)) + rval.code = RC_FAIL; + else +@@ -267,6 +269,42 @@ + return rval; + } + ++asn_dec_rval_t ++NativeInteger_decode_aper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ asn_dec_rval_t rval; ++ long *native = (long *)*sptr; ++ INTEGER_t tmpint; ++ void *tmpintptr = &tmpint; ++ ++ (void)opt_codec_ctx; ++ ASN_DEBUG("Decoding NativeInteger %s (APER)", td->name); ++ ++ if(!native) { ++ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); ++ if(!native) _ASN_DECODE_FAILED; ++ } ++ ++ memset(&tmpint, 0, sizeof tmpint); ++ rval = INTEGER_decode_aper(opt_codec_ctx, td, constraints, ++ &tmpintptr, pd); ++ if(rval.code == RC_OK) { ++ if((specs&&specs->field_unsigned) ++ ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) ++ : asn_INTEGER2long(&tmpint, native)) ++ rval.code = RC_FAIL; ++ else ++ ASN_DEBUG("NativeInteger %s got value %ld", ++ td->name, *native); ++ } ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); ++ ++ return rval; ++} ++ + asn_enc_rval_t + NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { +@@ -291,6 +329,32 @@ + return er; + } + ++asn_enc_rval_t ++NativeInteger_encode_aper( ++ asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ long native; ++ INTEGER_t tmpint; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ ++ native = *(long *)sptr; ++ ++ ASN_DEBUG("Encoding NativeInteger %s %ld (APER)", td->name, native); ++ ++ memset(&tmpint, 0, sizeof(tmpint)); ++ if((specs&&specs->field_unsigned) ++ ? asn_ulong2INTEGER(&tmpint, native) ++ : asn_long2INTEGER(&tmpint, native)) ++ _ASN_ENCODE_FAILED; ++ er = INTEGER_encode_aper(td, constraints, &tmpint, po); ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); ++ return er; ++} ++ + /* + * INTEGER specific human-readable output. + */ +Index: skeletons/PrintableString.c +=================================================================== +--- skeletons/PrintableString.c (revision 1410) ++++ skeletons/PrintableString.c (working copy) +@@ -59,6 +59,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_PrintableString_tags, + sizeof(asn_DEF_PrintableString_tags) +Index: skeletons/NativeInteger.h +=================================================================== +--- skeletons/NativeInteger.h (revision 1410) ++++ skeletons/NativeInteger.h (working copy) +@@ -29,6 +29,8 @@ + xer_type_encoder_f NativeInteger_encode_xer; + per_type_decoder_f NativeInteger_decode_uper; + per_type_encoder_f NativeInteger_encode_uper; ++per_type_decoder_f NativeInteger_decode_aper; ++per_type_encoder_f NativeInteger_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/per_decoder.c +=================================================================== +--- skeletons/per_decoder.c (revision 1410) ++++ skeletons/per_decoder.c (working copy) +@@ -37,6 +37,35 @@ + } + + asn_dec_rval_t ++aper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) { ++ asn_dec_rval_t rval; ++ ++ rval = aper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0); ++ if(rval.consumed) { ++ /* ++ * We've always given 8-aligned data, ++ * so convert bits to integral bytes. ++ */ ++ rval.consumed += 7; ++ rval.consumed >>= 3; ++ } else if(rval.code == RC_OK) { ++ if(size) { ++ if(((uint8_t *)buffer)[0] == 0) { ++ rval.consumed = 1; /* 1 byte */ ++ } else { ++ ASN_DEBUG("Expecting single zeroed byte"); ++ rval.code = RC_FAIL; ++ } ++ } else { ++ /* Must contain at least 8 bits. */ ++ rval.code = RC_WMORE; ++ } ++ } ++ ++ return rval; ++} ++ ++asn_dec_rval_t + uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { + asn_codec_ctx_t s_codec_ctx; + asn_dec_rval_t rval; +@@ -91,3 +120,57 @@ + return rval; + } + ++asn_dec_rval_t ++aper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { ++ asn_codec_ctx_t s_codec_ctx; ++ asn_dec_rval_t rval; ++ asn_per_data_t pd; ++ ++ if(skip_bits < 0 || skip_bits > 7 ++ || unused_bits < 0 || unused_bits > 7 ++ || (unused_bits > 0 && !size)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Stack checker requires that the codec context ++ * must be allocated on the stack. ++ */ ++ if(opt_codec_ctx) { ++ if(opt_codec_ctx->max_stack_size) { ++ s_codec_ctx = *opt_codec_ctx; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ } else { ++ /* If context is not given, be security-conscious anyway */ ++ memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); ++ s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; ++ opt_codec_ctx = &s_codec_ctx; ++ } ++ ++ /* Fill in the position indicator */ ++ memset(&pd, 0, sizeof(pd)); ++ pd.buffer = (const uint8_t *)buffer; ++ pd.nboff = skip_bits; ++ pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from <limits.h> */ ++ if(pd.nboff > pd.nbits) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Invoke type-specific decoder. ++ */ ++ if(!td->aper_decoder) ++ _ASN_DECODE_FAILED; /* PER is not compiled in */ ++ rval = td->aper_decoder(opt_codec_ctx, td, 0, sptr, &pd); ++ if(rval.code == RC_OK) { ++ /* Return the number of consumed bits */ ++ rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) ++ + pd.nboff - skip_bits; ++ ASN_DEBUG("PER decoding consumed %d, counted %d", ++ rval.consumed, pd.moved); ++ assert(rval.consumed == pd.moved); ++ } else { ++ /* PER codec is not a restartable */ ++ rval.consumed = 0; ++ } ++ return rval; ++} +Index: skeletons/VideotexString.c +=================================================================== +--- skeletons/VideotexString.c (revision 1410) ++++ skeletons/VideotexString.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_VideotexString_tags, + sizeof(asn_DEF_VideotexString_tags) +Index: skeletons/per_decoder.h +=================================================================== +--- skeletons/per_decoder.h (revision 1410) ++++ skeletons/per_decoder.h (working copy) +@@ -38,8 +38,30 @@ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); + ++/* ++ * Aligned PER decoder of a "complete encoding" as per X.691#10.1. ++ * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. ++ */ ++asn_dec_rval_t aper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ ++ void **struct_ptr, /* Pointer to a target structure's pointer */ ++ const void *buffer, /* Data to be decoded */ ++ size_t size /* Size of data buffer */ ++ ); + + /* ++ * Aligned PER decoder of any ASN.1 type. May be invoked by the application. ++ * WARNING: This call returns the number of BITS read from the stream. Beware. ++ */ ++asn_dec_rval_t aper_decode(struct asn_codec_ctx_s *opt_codec_ctx, ++ struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ ++ void **struct_ptr, /* Pointer to a target structure's pointer */ ++ const void *buffer, /* Data to be decoded */ ++ size_t size, /* Size of data buffer */ ++ int skip_bits, /* Number of unused leading bits, 0..7 */ ++ int unused_bits /* Number of unused tailing bits, 0..7 */ ++ ); ++/* + * Type of the type-specific PER decoder function. + */ + typedef asn_dec_rval_t (per_type_decoder_f)(asn_codec_ctx_t *opt_codec_ctx, +Index: skeletons/per_support.c +=================================================================== +--- skeletons/per_support.c (revision 1410) ++++ skeletons/per_support.c (working copy) +@@ -31,6 +31,16 @@ + } + } + ++int32_t ++aper_get_align(asn_per_data_t *pd) { ++ ++ if(pd->nboff & 0x7) { ++ ASN_DEBUG("Aligning %d bits", 8 - (pd->nboff & 0x7)); ++ return per_get_few_bits(pd, 8 - (pd->nboff & 0x7)); ++ } ++ return 0; ++} ++ + /* + * Extract a small number of bits (<= 31) from the specified PER data pointer. + */ +@@ -103,7 +113,7 @@ + + accum &= (((uint32_t)1 << nbits) - 1); + +- ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+d[%d..%d]:%02x (%d) => 0x%x]", ++ ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+d[%d..%d]:%02x (%d) => 0x%02x]", + nbits, nleft, + pd->moved, + (((int)pd->buffer) & 0xf), +@@ -122,6 +132,8 @@ + per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { + int32_t value; + ++ ASN_DEBUG("align: %s, nbits %d", alright ? "YES":"NO", nbits); ++ + if(alright && (nbits & 7)) { + /* Perform right alignment of a first few bits */ + value = per_get_few_bits(pd, nbits & 0x07); +@@ -186,6 +198,36 @@ + return (16384 * value); + } + ++ssize_t ++aper_get_length(asn_per_data_t *pd, int range, int ebits, int *repeat) { ++ ssize_t value; ++ ++ *repeat = 0; ++ ++ if (range <= 65536 && range >= 0) ++ return aper_get_nsnnwn(pd, range); ++ ++ if (aper_get_align(pd) < 0) ++ return -1; ++ ++ if(ebits >= 0) return per_get_few_bits(pd, ebits); ++ ++ value = per_get_few_bits(pd, 8); ++ if(value < 0) return -1; ++ if((value & 128) == 0) /* #10.9.3.6 */ ++ return (value & 0x7F); ++ if((value & 64) == 0) { /* #10.9.3.7 */ ++ value = ((value & 63) << 8) | per_get_few_bits(pd, 8); ++ if(value < 0) return -1; ++ return value; ++ } ++ value &= 63; /* this is "m" from X.691, #10.9.3.8 */ ++ if(value < 1 || value > 4) ++ return -1; ++ *repeat = 1; ++ return (16384 * value); ++} ++ + /* + * Get the normally small length "n". + * This procedure used to decode length of extensions bit-maps +@@ -210,6 +252,25 @@ + } + } + ++ssize_t ++aper_get_nslength(asn_per_data_t *pd) { ++ ssize_t length; ++ ++ ASN_DEBUG("Getting normally small length"); ++ ++ if(per_get_few_bits(pd, 1) == 0) { ++ length = per_get_few_bits(pd, 6) + 1; ++ if(length <= 0) return -1; ++ ASN_DEBUG("l=%d", length); ++ return length; ++ } else { ++ int repeat; ++ length = aper_get_length(pd, -1, -1, &repeat); ++ if(length >= 0 && !repeat) return length; ++ return -1; /* Error, or do not support >16K extensions */ ++ } ++} ++ + /* + * Get the normally small non-negative whole number. + * X.691, #10.6 +@@ -236,6 +297,40 @@ + return value; + } + ++ssize_t ++aper_get_nsnnwn(asn_per_data_t *pd, int range) { ++ ssize_t value; ++ int bytes = 0; ++ ++ ASN_DEBUG("getting nsnnwn with range %d", range); ++ ++ if(range <= 255) { ++ if (range < 0) return -1; ++ /* 1 -> 8 bits */ ++ int i; ++ for (i = 1; i <= 8; i++) { ++ int upper = 1 << i; ++ if (upper >= range) ++ break; ++ } ++ value = per_get_few_bits(pd, i); ++ return value; ++ } else if (range == 256){ ++ /* 1 byte */ ++ bytes = 1; ++ return -1; ++ } else if (range <= 65536) { ++ /* 2 bytes */ ++ bytes = 2; ++ } else { ++ return -1; ++ } ++ if (aper_get_align(pd) < 0) ++ return -1; ++ value = per_get_few_bits(pd, 8 * bytes); ++ return value; ++} ++ + /* + * Put the normally small non-negative whole number. + * X.691, #10.6 +@@ -244,6 +339,7 @@ + uper_put_nsnnwn(asn_per_outp_t *po, int n) { + int bytes; + ++ ASN_DEBUG("uper put nsnnwn n %d", n); + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); +@@ -262,7 +358,62 @@ + return per_put_few_bits(po, n, 8 * bytes); + } + ++int ++aper_put_nsnnwn(asn_per_outp_t *po, int range, int number) { ++ int bytes; + ++ ASN_DEBUG("aper put nsnnwn %d with range %d", number, range); ++ /* 10.5.7.1 X.691 */ ++ if(range < 0) { ++ int i; ++ for (i = 1; ; i++) { ++ int bits = 1 << (8 * i); ++ if (number <= bits) ++ break; ++ } ++ bytes = i; ++ assert(i <= 4); ++ } ++ if(range <= 255) { ++ int i; ++ for (i = 1; i <= 8; i++) { ++ int bits = 1 << i; ++ if (range <= bits) ++ break; ++ } ++ return per_put_few_bits(po, number, i); ++ } else if(range == 256) { ++ bytes = 1; ++ } else if(range <= 65536) { ++ bytes = 2; ++ } else { /* Ranges > 64K */ ++ int i; ++ for (i = 1; ; i++) { ++ int bits = 1 << (8 * i); ++ if (range <= bits) ++ break; ++ } ++ assert(i <= 4); ++ bytes = i; ++ } ++ if(aper_put_align(po) < 0) /* Aligning on octet */ ++ return -1; ++// if(per_put_few_bits(po, bytes, 8)) ++// return -1; ++ ++ return per_put_few_bits(po, number, 8 * bytes); ++} ++ ++int aper_put_align(asn_per_outp_t *po) { ++ ++ if(po->nboff & 0x7) { ++ ASN_DEBUG("Aligning %d bits", 8 - (po->nboff & 0x7)); ++ if(per_put_few_bits(po, 0x00, (8 - (po->nboff & 0x7)))) ++ return -1; ++ } ++ return 0; ++} ++ + /* + * Put a small number of bits (<= 31). + */ +@@ -386,6 +537,8 @@ + ssize_t + uper_put_length(asn_per_outp_t *po, size_t length) { + ++ ASN_DEBUG("UPER put length %d", length); ++ + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; +@@ -400,7 +553,34 @@ + ? -1 : (ssize_t)(length << 14); + } + ++ssize_t ++aper_put_length(asn_per_outp_t *po, int range, size_t length) { + ++ ASN_DEBUG("APER put length %d with range %d", length, range); ++ ++ /* 10.9 X.691 Note 2 */ ++ if (range <= 65536 && range >= 0) ++ return aper_put_nsnnwn(po, range, length); ++ ++ if (aper_put_align(po) < 0) ++ return -1; ++ ++ if(length <= 127) /* #10.9.3.6 */{ ++ return per_put_few_bits(po, length, 8) ++ ? -1 : (ssize_t)length; ++ } ++ else if(length < 16384) /* #10.9.3.7 */ ++ return per_put_few_bits(po, length|0x8000, 16) ++ ? -1 : (ssize_t)length; ++ ++ length >>= 14; ++ if(length > 4) length = 4; ++ ++ return per_put_few_bits(po, 0xC0 | length, 8) ++ ? -1 : (ssize_t)(length << 14); ++} ++ ++ + /* + * Put the normally small length "n" into the stream. + * This procedure used to encode length of extensions bit-maps +@@ -423,3 +603,19 @@ + return 0; + } + ++int ++aper_put_nslength(asn_per_outp_t *po, size_t length) { ++ ++ if(length <= 64) { ++ /* #10.9.3.4 */ ++ if(length == 0) return -1; ++ return per_put_few_bits(po, length-1, 7) ? -1 : 0; ++ } else { ++ if(aper_put_length(po, -1, length) != (ssize_t)length) { ++ /* This might happen in case of >16K extensions */ ++ return -1; ++ } ++ } ++ ++ return 0; ++} +Index: skeletons/RELATIVE-OID.c +=================================================================== +--- skeletons/RELATIVE-OID.c (revision 1410) ++++ skeletons/RELATIVE-OID.c (working copy) +@@ -28,6 +28,8 @@ + RELATIVE_OID_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_RELATIVE_OID_tags, + sizeof(asn_DEF_RELATIVE_OID_tags) +Index: skeletons/VisibleString.c +=================================================================== +--- skeletons/VisibleString.c (revision 1410) ++++ skeletons/VisibleString.c (working copy) +@@ -29,6 +29,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_VisibleString_tags, + sizeof(asn_DEF_VisibleString_tags) +Index: skeletons/per_support.h +=================================================================== +--- skeletons/per_support.h (revision 1410) ++++ skeletons/per_support.h (working copy) +@@ -24,8 +24,8 @@ + } flags; + int range_bits; /* Full number of bits in the range */ + int effective_bits; /* Effective bits */ +- long lower_bound; /* "lb" value */ +- long upper_bound; /* "ub" value */ ++ int64_t lower_bound; /* "lb" value */ ++ int64_t upper_bound; /* "ub" value */ + } asn_per_constraint_t; + typedef struct asn_per_constraints_s { + asn_per_constraint_t value; +@@ -39,9 +39,9 @@ + */ + typedef struct asn_per_data_s { + const uint8_t *buffer; /* Pointer to the octet stream */ +- size_t nboff; /* Bit offset to the meaningful bit */ +- size_t nbits; /* Number of bits in the stream */ +- size_t moved; /* Number of bits moved through this bit stream */ ++ size_t nboff; /* Bit offset to the meaningful bit */ ++ size_t nbits; /* Number of bits in the stream */ ++ size_t moved; /* Number of bits moved through this bit stream */ + int (*refill)(struct asn_per_data_s *); + void *refill_key; + } asn_per_data_t; +@@ -71,15 +71,22 @@ + int effective_bound_bits, + int *repeat); + ++ssize_t aper_get_length(asn_per_data_t *pd, ++ int range, ++ int effective_bound_bits, ++ int *repeat); ++ + /* + * Get the normally small length "n". + */ + ssize_t uper_get_nslength(asn_per_data_t *pd); ++ssize_t aper_get_nslength(asn_per_data_t *pd); + + /* + * Get the normally small non-negative whole number. + */ + ssize_t uper_get_nsnnwn(asn_per_data_t *pd); ++ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range); + + /* Non-thread-safe debugging function, don't use it */ + char *per_data_string(asn_per_data_t *pd); +@@ -103,6 +110,10 @@ + /* Output a large number of bits */ + int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + ++/* Align the current bit position to octet bundary */ ++int aper_put_align(asn_per_outp_t *po); ++int32_t aper_get_align(asn_per_data_t *pd); ++ + /* + * Put the length "n" to the Unaligned PER stream. + * This function returns the number of units which may be flushed +@@ -110,17 +121,23 @@ + */ + ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + ++ssize_t aper_put_length(asn_per_outp_t *po, int range, size_t length); ++ + /* + * Put the normally small length "n" to the Unaligned PER stream. + * Returns 0 or -1. + */ + int uper_put_nslength(asn_per_outp_t *po, size_t length); + ++int aper_put_nslength(asn_per_outp_t *po, size_t length); ++ + /* + * Put the normally small non-negative whole number. + */ + int uper_put_nsnnwn(asn_per_outp_t *po, int n); + ++int aper_put_nsnnwn(asn_per_outp_t *po, int range, int number); ++ + #ifdef __cplusplus + } + #endif +Index: skeletons/BIT_STRING.c +=================================================================== +--- skeletons/BIT_STRING.c (revision 1410) ++++ skeletons/BIT_STRING.c (working copy) +@@ -29,6 +29,8 @@ + BIT_STRING_encode_xer, + OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ ++ OCTET_STRING_decode_aper, /* Aligned PER decoder */ ++ OCTET_STRING_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BIT_STRING_tags, + sizeof(asn_DEF_BIT_STRING_tags) +Index: skeletons/GraphicString.c +=================================================================== +--- skeletons/GraphicString.c (revision 1410) ++++ skeletons/GraphicString.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer, /* Can't expect it to be ASCII/UTF8 */ + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_GraphicString_tags, + sizeof(asn_DEF_GraphicString_tags) +Index: skeletons/ObjectDescriptor.c +=================================================================== +--- skeletons/ObjectDescriptor.c (revision 1410) ++++ skeletons/ObjectDescriptor.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ObjectDescriptor_tags, + sizeof(asn_DEF_ObjectDescriptor_tags) +Index: skeletons/NULL.c +=================================================================== +--- skeletons/NULL.c (revision 1410) ++++ skeletons/NULL.c (working copy) +@@ -25,6 +25,8 @@ + NULL_encode_xer, + NULL_decode_uper, /* Unaligned PER decoder */ + NULL_encode_uper, /* Unaligned PER encoder */ ++ NULL_decode_aper, /* Aligned PER decoder */ ++ NULL_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NULL_tags, + sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]), +@@ -132,6 +134,34 @@ + return rv; + } + ++asn_dec_rval_t ++NULL_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rv; ++ ++ (void)opt_codec_ctx; ++ (void)td; ++ (void)constraints; ++ (void)pd; ++ ++ if(!*sptr) { ++ *sptr = MALLOC(sizeof(NULL_t)); ++ if(*sptr) { ++ *(NULL_t *)*sptr = 0; ++ } else { ++ _ASN_DECODE_FAILED; ++ } ++ } ++ ++ /* ++ * NULL type does not have content octets. ++ */ ++ ++ rv.code = RC_OK; ++ rv.consumed = 0; ++ return rv; ++} ++ + asn_enc_rval_t + NULL_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void *sptr, asn_per_outp_t *po) { +@@ -145,3 +175,17 @@ + er.encoded = 0; + _ASN_ENCODED_OK(er); + } ++ ++asn_enc_rval_t ++NULL_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void *sptr, asn_per_outp_t *po) { ++ asn_enc_rval_t er; ++ ++ (void)td; ++ (void)constraints; ++ (void)sptr; ++ (void)po; ++ ++ er.encoded = 0; ++ _ASN_ENCODED_OK(er); ++} +Index: skeletons/BOOLEAN.c +=================================================================== +--- skeletons/BOOLEAN.c (revision 1410) ++++ skeletons/BOOLEAN.c (working copy) +@@ -24,6 +24,8 @@ + BOOLEAN_encode_xer, + BOOLEAN_decode_uper, /* Unaligned PER decoder */ + BOOLEAN_encode_uper, /* Unaligned PER encoder */ ++ BOOLEAN_decode_aper, /* Aligned PER decoder */ ++ BOOLEAN_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BOOLEAN_tags, + sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), +@@ -267,7 +269,36 @@ + return rv; + } + ++asn_dec_rval_t ++BOOLEAN_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rv; ++ BOOLEAN_t *st = (BOOLEAN_t *)*sptr; + ++ (void)opt_codec_ctx; ++ (void)constraints; ++ ++ if(!st) { ++ st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st))); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ /* ++ * Extract a single bit ++ */ ++ switch(per_get_few_bits(pd, 1)) { ++ case 1: *st = 1; break; ++ case 0: *st = 0; break; ++ case -1: default: _ASN_DECODE_STARVED; ++ } ++ ++ ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE"); ++ ++ rv.code = RC_OK; ++ rv.consumed = 1; ++ return rv; ++} ++ + asn_enc_rval_t + BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { +@@ -282,3 +313,18 @@ + + _ASN_ENCODED_OK(er); + } ++ ++asn_enc_rval_t ++BOOLEAN_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; ++ asn_enc_rval_t er; ++ ++ (void)constraints; ++ ++ if(!st) _ASN_ENCODE_FAILED; ++ ++ per_put_few_bits(po, *st ? 1 : 0, 1); ++ ++ _ASN_ENCODED_OK(er); ++} +Index: skeletons/NULL.h +=================================================================== +--- skeletons/NULL.h (revision 1410) ++++ skeletons/NULL.h (working copy) +@@ -25,6 +25,8 @@ + xer_type_encoder_f NULL_encode_xer; + per_type_decoder_f NULL_decode_uper; + per_type_encoder_f NULL_encode_uper; ++per_type_decoder_f NULL_decode_aper; ++per_type_encoder_f NULL_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/BOOLEAN.h +=================================================================== +--- skeletons/BOOLEAN.h (revision 1410) ++++ skeletons/BOOLEAN.h (working copy) +@@ -28,6 +28,8 @@ + xer_type_encoder_f BOOLEAN_encode_xer; + per_type_decoder_f BOOLEAN_decode_uper; + per_type_encoder_f BOOLEAN_encode_uper; ++per_type_decoder_f BOOLEAN_decode_aper; ++per_type_encoder_f BOOLEAN_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/NumericString.c +=================================================================== +--- skeletons/NumericString.c (revision 1410) ++++ skeletons/NumericString.c (working copy) +@@ -49,6 +49,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NumericString_tags, + sizeof(asn_DEF_NumericString_tags) +Index: skeletons/NativeReal.c +=================================================================== +--- skeletons/NativeReal.c (revision 1410) ++++ skeletons/NativeReal.c (working copy) +@@ -32,6 +32,8 @@ + NativeReal_encode_xer, + NativeReal_decode_uper, + NativeReal_encode_uper, ++ NativeReal_decode_aper, ++ NativeReal_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeReal_tags, + sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]), +@@ -199,6 +201,43 @@ + return rval; + } + ++asn_dec_rval_t ++NativeReal_decode_aper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **dbl_ptr, asn_per_data_t *pd) { ++ double *Dbl = (double *)*dbl_ptr; ++ asn_dec_rval_t rval; ++ REAL_t tmp; ++ void *ptmp = &tmp; ++ int ret; ++ ++ (void)constraints; ++ ++ /* ++ * If the structure is not there, allocate it. ++ */ ++ if(Dbl == NULL) { ++ *dbl_ptr = CALLOC(1, sizeof(*Dbl)); ++ Dbl = (double *)*dbl_ptr; ++ if(Dbl == NULL) ++ _ASN_DECODE_FAILED; ++ } ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ rval = OCTET_STRING_decode_aper(opt_codec_ctx, td, NULL, ++ &ptmp, pd); ++ if(rval.code != RC_OK) { ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); ++ return rval; ++ } ++ ++ ret = asn_REAL2double(&tmp, Dbl); ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); ++ if(ret) _ASN_DECODE_FAILED; ++ ++ return rval; ++} ++ + /* + * Encode the NativeReal using the OCTET STRING PER encoder. + */ +@@ -228,6 +267,32 @@ + return erval; + } + ++asn_enc_rval_t ++NativeReal_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ double Dbl = *(const double *)sptr; ++ asn_enc_rval_t erval; ++ REAL_t tmp; ++ ++ (void)constraints; ++ ++ /* Prepare a temporary clean structure */ ++ memset(&tmp, 0, sizeof(tmp)); ++ ++ if(asn_double2REAL(&tmp, Dbl)) ++ _ASN_ENCODE_FAILED; ++ ++ /* Encode a DER REAL */ ++ erval = OCTET_STRING_encode_aper(td, NULL, &tmp, po); ++ if(erval.encoded == -1) ++ erval.structure_ptr = sptr; ++ ++ /* Free possibly allocated members of the temporary structure */ ++ ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); ++ ++ return erval; ++} ++ + /* + * Decode the chunk of XML text encoding REAL. + */ +Index: skeletons/INTEGER.c +=================================================================== +--- skeletons/INTEGER.c (revision 1410) ++++ skeletons/INTEGER.c (working copy) +@@ -26,6 +26,8 @@ + INTEGER_encode_xer, + INTEGER_decode_uper, /* Unaligned PER decoder */ + INTEGER_encode_uper, /* Unaligned PER encoder */ ++ INTEGER_decode_aper, ++ INTEGER_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_INTEGER_tags, + sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), +@@ -395,7 +397,7 @@ + break; + } + +- { ++ { + long new_value = value * 10; + + if(new_value / 10 != value) +@@ -415,7 +417,7 @@ + return XPBD_DECODER_LIMIT; + } + } +- } ++ } + continue; + case 0x3c: /* '<' */ + if(state == ST_SKIPSPACE) { +@@ -424,7 +426,7 @@ + (asn_INTEGER_specifics_t *) + td->specifics, lstart, lstop); + if(el) { +- ASN_DEBUG("Found \"%s\" => %ld", ++ ASN_DEBUG("Found \"%s\" => %lld", + el->enum_name, el->nat_value); + state = ST_DIGITS; + value = el->nat_value; +@@ -611,7 +613,7 @@ + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + } +- ASN_DEBUG("Got value %ld + low %ld", ++ ASN_DEBUG("Got value %ld + low %lld", + value, ct->lower_bound); + value += ct->lower_bound; + if((specs && specs->field_unsigned) +@@ -659,6 +661,158 @@ + return rval; + } + ++asn_dec_rval_t ++INTEGER_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ INTEGER_t *st = (INTEGER_t *)*sptr; ++ asn_per_constraint_t *ct; ++ int repeat; ++ ++ (void)opt_codec_ctx; ++ ++ if(!st) { ++ st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ if(!constraints) constraints = td->per_constraints; ++ ct = constraints ? &constraints->value : 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) _ASN_DECODE_STARVED; ++ if(inext) ct = 0; ++ } ++ ++ FREEMEM(st->buf); ++ st->buf = 0; ++ st->size = 0; ++ if(ct) { ++ if(ct->flags & APC_SEMI_CONSTRAINED) { ++ st->buf = (uint8_t *)CALLOC(1, 2); ++ if(!st->buf) _ASN_DECODE_FAILED; ++ st->size = 1; ++ } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { ++ size_t size = (ct->range_bits + 7) >> 3; ++ st->buf = (uint8_t *)MALLOC(1 + size + 1); ++ if(!st->buf) _ASN_DECODE_FAILED; ++ st->size = size; ++ } ++ } ++ ++ /* X.691, #12.2.2 */ ++ if(ct && ct->flags != APC_UNCONSTRAINED) { ++ /* #10.5.6 */ ++ ASN_DEBUG("Integer with range %d bits", ct->range_bits); ++ if(ct->range_bits >= 0) { ++ if (ct->range_bits > 16) { ++ int max_range_bytes = (ct->range_bits >> 3) + ++ (((ct->range_bits % 8) > 0) ? 1 : 0); ++ int length = 0, i; ++ int64_t value = 0; ++ ++ for (i = 1; ; i++) { ++ int upper = 1 << i; ++ if (upper >= max_range_bytes) ++ break; ++ } ++ ASN_DEBUG("Can encode %d (%d bytes) in %d bits", ct->range_bits, ++ max_range_bytes, i); ++ ++ if ((length = per_get_few_bits(pd, i)) < 0) ++ _ASN_DECODE_FAILED; ++ ++ /* X.691 #12.2.6 length determinant + lb (1) */ ++ length += 1; ++ ASN_DEBUG("Got length %d", length); ++ ++ if (aper_get_align(pd) != 0) ++ _ASN_DECODE_STARVED; ++ ++ while (length--) { ++ int buf = per_get_few_bits(pd, 8); ++ if (buf < 0) ++ _ASN_DECODE_STARVED; ++ value += (((int64_t)buf) << (8 * length)); ++ } ++ ++ value += ct->lower_bound; ++ if((specs && specs->field_unsigned) ++ ? asn_uint642INTEGER(st, value) ++ : asn_int642INTEGER(st, value)) ++ _ASN_DECODE_FAILED; ++ ASN_DEBUG("Got value %lld + low %lld", ++ value, ct->lower_bound); ++ } else { ++ long value = 0; ++ if (ct->range_bits < 8) { ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ } else if (ct->range_bits == 8) { ++ if (aper_get_align(pd) < 0) ++ _ASN_DECODE_FAILED; ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ } else { ++ /* Align */ ++ if (aper_get_align(pd) < 0) ++ _ASN_DECODE_FAILED; ++ value = per_get_few_bits(pd, 16); ++ if(value < 0) _ASN_DECODE_STARVED; ++ } ++ value += ct->lower_bound; ++ if((specs && specs->field_unsigned) ++ ? asn_ulong2INTEGER(st, value) ++ : asn_long2INTEGER(st, value)) ++ _ASN_DECODE_FAILED; ++ ASN_DEBUG("Got value %ld + low %lld", ++ value, ct->lower_bound); ++ } ++ return rval; ++ } else { ++ _ASN_DECODE_FAILED; ++ } ++ } else { ++ ASN_DEBUG("Decoding unconstrained integer %s", td->name); ++ } ++ ++ /* X.691, #12.2.3, #12.2.4 */ ++ do { ++ ssize_t len; ++ void *p; ++ int ret; ++ ++ /* Get the PER length */ ++ len = aper_get_length(pd, -1, -1, &repeat); ++ if(len < 0) _ASN_DECODE_STARVED; ++ ++ p = REALLOC(st->buf, st->size + len + 1); ++ if(!p) _ASN_DECODE_FAILED; ++ st->buf = (uint8_t *)p; ++ ++ ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); ++ if(ret < 0) _ASN_DECODE_STARVED; ++ st->size += len; ++ } while(repeat); ++ st->buf[st->size] = 0; /* JIC */ ++ ++ /* #12.2.3 */ ++ if(ct && ct->lower_bound) { ++ /* ++ * TODO: replace by in-place arithmetics. ++ */ ++ long value; ++ if(asn_INTEGER2long(st, &value)) ++ _ASN_DECODE_FAILED; ++ if(asn_long2INTEGER(st, value + ct->lower_bound)) ++ _ASN_DECODE_FAILED; ++ } ++ ++ return rval; ++} ++ + asn_enc_rval_t + INTEGER_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { +@@ -692,7 +846,7 @@ + || uval > (unsigned long)ct->upper_bound) + inext = 1; + } +- ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s", ++ ASN_DEBUG("Value %lu (%02x/%d) lb %llu ub %llu %s", + uval, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); +@@ -709,7 +863,7 @@ + || value > ct->upper_bound) + inext = 1; + } +- ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", ++ ASN_DEBUG("Value %ld (%02x/%d) lb %lld ub %lld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); +@@ -744,7 +898,7 @@ + } + + if(ct && ct->lower_bound) { +- ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); ++ ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound); + /* TODO: adjust lower bound */ + _ASN_ENCODE_FAILED; + } +@@ -761,6 +915,145 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++INTEGER_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ INTEGER_t *st = (INTEGER_t *)sptr; ++ const uint8_t *buf; ++ const uint8_t *end; ++ asn_per_constraint_t *ct; ++ int64_t value = 0; ++ ++ if(!st || st->size == 0) _ASN_ENCODE_FAILED; ++ ++ if(!constraints) constraints = td->per_constraints; ++ ct = constraints ? &constraints->value : 0; ++ ++ er.encoded = 0; ++ ++ if(ct) { ++ int inext = 0; ++ if(specs && specs->field_unsigned) { ++ uint64_t uval; ++ if(asn_INTEGER2uint64(st, &uval)) ++ _ASN_ENCODE_FAILED; ++ /* Check proper range */ ++ if(ct->flags & APC_SEMI_CONSTRAINED) { ++ if(uval < (unsigned long long)ct->lower_bound) ++ inext = 1; ++ } else if(ct->range_bits >= 0) { ++ if(uval < (unsigned long long)ct->lower_bound ++ || uval > (unsigned long long)ct->upper_bound) ++ inext = 1; ++ } ++ ASN_DEBUG("Value %llu (%02x/%d) lb %llu ub %llu %s", ++ uval, st->buf[0], st->size, ++ ct->lower_bound, ct->upper_bound, ++ inext ? "ext" : "fix"); ++ value = uval; ++ } else { ++ if(asn_INTEGER2int64(st, &value)) _ASN_ENCODE_FAILED; ++ /* Check proper range */ ++ if(ct->flags & APC_SEMI_CONSTRAINED) { ++ if(value < ct->lower_bound) ++ inext = 1; ++ } else if(ct->range_bits >= 0) { ++ if(value < ct->lower_bound ++ || value > ct->upper_bound) ++ inext = 1; ++ } ++ ASN_DEBUG("Value %lld (%02x/%d) lb %lld ub %lld %s", ++ value, st->buf[0], st->size, ++ ct->lower_bound, ct->upper_bound, ++ inext ? "ext" : "fix"); ++ } ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, inext, 1)) ++ _ASN_ENCODE_FAILED; ++ if(inext) ct = 0; ++ } else if(inext) { ++ _ASN_ENCODE_FAILED; ++ } ++ } ++ ++ /* X.691, #12.2.2 */ ++ if(ct && ct->range_bits >= 0) { ++ /* #10.5.6 */ ++ ASN_DEBUG("Encoding integer with range %d bits", ++ ct->range_bits); ++ ++ value -= ct->lower_bound; ++ ++ /* #12 <= 8 -> alignment ? */ ++ if (ct->range_bits < 8) { ++ /* Bit field case -> no alignment*/ ++ if(per_put_few_bits(po, 0x00 | value, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ } else if (ct->range_bits == 8) { ++ if(aper_put_align(po) < 0) ++ _ASN_ENCODE_FAILED; ++ if(per_put_few_bits(po, 0x00 | value, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ } else if (ct->range_bits <= 16) { ++ // Consume the bytes to align on octet ++ if(aper_put_align(po) < 0) ++ _ASN_ENCODE_FAILED; ++ if(per_put_few_bits(po, 0x0000 | value, ++ 16)) ++ _ASN_ENCODE_FAILED; ++ } else { ++ /* TODO: extend to >64 bits */ ++ int64_t v = value; ++ int i, j; ++ int max_range_bytes = (ct->range_bits >> 3) + ++ (((ct->range_bits % 8) > 0) ? 1 : 0); ++ ++ for (i = 1; ; i++) { ++ int upper = 1 << i; ++ if (upper >= max_range_bytes) ++ break; ++ } ++ ++ ASN_DEBUG("Putting n - lb (%lld) with range %d bytes (real size - lb (1)) %d in %d bits", ++ v, max_range_bytes, st->size - 1, i); ++ ++ /* Putting length in the minimum number of bits ex: 5 = 3bits */ ++ if (per_put_few_bits(po, st->size - 1, i)) ++ _ASN_ENCODE_FAILED; ++ ++ // Consume the bits to align on octet ++ if (aper_put_align(po) < 0) ++ _ASN_ENCODE_FAILED; ++ ++ /* Put the value */ ++ for (i = 0; i < st->size; i++) { ++ if(per_put_few_bits(po, (v >> (8 * (st->size - i - 1))) & 0xff, 8)) ++ _ASN_ENCODE_FAILED; ++ } ++ } ++ _ASN_ENCODED_OK(er); ++ } ++ ++ if(ct && ct->lower_bound) { ++ ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound); ++ /* TODO: adjust lower bound */ ++ _ASN_ENCODE_FAILED; ++ } ++ ++ for(buf = st->buf, end = st->buf + st->size; buf < end;) { ++ ssize_t mayEncode = aper_put_length(po, -1, end - buf); ++ if(mayEncode < 0) ++ _ASN_ENCODE_FAILED; ++ if(per_put_many_bits(po, buf, 8 * mayEncode)) ++ _ASN_ENCODE_FAILED; ++ buf += mayEncode; ++ } ++ ++ _ASN_ENCODED_OK(er); ++} ++ + int + asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { + uint8_t *b, *end; +@@ -822,6 +1115,66 @@ + } + + int ++asn_INTEGER2int64(const INTEGER_t *iptr, int64_t *lptr) { ++ uint8_t *b, *end; ++ size_t size; ++ int64_t l; ++ ++ /* Sanity checking */ ++ if(!iptr || !iptr->buf || !lptr) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ /* Cache the begin/end of the buffer */ ++ b = iptr->buf; /* Start of the INTEGER buffer */ ++ size = iptr->size; ++ end = b + size; /* Where to stop */ ++ ++ if(size > sizeof(int64_t)) { ++ uint8_t *end1 = end - 1; ++ /* ++ * Slightly more advanced processing, ++ * able to >sizeof(int64_t) bytes, ++ * when the actual value is small ++ * (0x0000000000abcdef would yield a fine 0x00abcdef) ++ */ ++ /* Skip out the insignificant leading bytes */ ++ for(; b < end1; b++) { ++ switch(*b) { ++ case 0x00: if((b[1] & 0x80) == 0) continue; break; ++ case 0xff: if((b[1] & 0x80) != 0) continue; break; ++ } ++ break; ++ } ++ ++ size = end - b; ++ if(size > sizeof(int64_t)) { ++ /* Still cannot fit the int64_t */ ++ errno = ERANGE; ++ return -1; ++ } ++ } ++ ++ /* Shortcut processing of a corner case */ ++ if(end == b) { ++ *lptr = 0; ++ return 0; ++ } ++ ++ /* Perform the sign initialization */ ++ /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ ++ if((*b >> 7)) l = -1; else l = 0; ++ ++ /* Conversion engine */ ++ for(; b < end; b++) ++ l = (l << 8) | *b; ++ ++ *lptr = l; ++ return 0; ++} ++ ++int + asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { + uint8_t *b, *end; + unsigned long l; +@@ -854,6 +1207,38 @@ + } + + int ++asn_INTEGER2uint64(const INTEGER_t *iptr, uint64_t *lptr) { ++ uint8_t *b, *end; ++ uint64_t l; ++ size_t size; ++ ++ if(!iptr || !iptr->buf || !lptr) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ b = iptr->buf; ++ size = iptr->size; ++ end = b + size; ++ ++ /* If all extra leading bytes are zeroes, ignore them */ ++ for(; size > sizeof(uint64_t); b++, size--) { ++ if(*b) { ++ /* Value won't fit unsigned long */ ++ errno = ERANGE; ++ return -1; ++ } ++ } ++ ++ /* Conversion engine */ ++ for(l = 0; b < end; b++) ++ l = (l << 8) | *b; ++ ++ *lptr = l; ++ return 0; ++} ++ ++int + asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { + uint8_t *buf; + uint8_t *end; +@@ -879,6 +1264,31 @@ + } + + int ++asn_uint642INTEGER(INTEGER_t *st, uint64_t value) { ++ uint8_t *buf; ++ uint8_t *end; ++ uint8_t *b; ++ int shr; ++ ++ if(value <= INT64_MAX) ++ return asn_int642INTEGER(st, value); ++ ++ buf = (uint8_t *)MALLOC(1 + sizeof(value)); ++ if(!buf) return -1; ++ ++ end = buf + (sizeof(value) + 1); ++ buf[0] = 0; ++ for(b = buf + 1, shr = (sizeof(value)-1)*8; b < end; shr -= 8, b++) ++ *b = (uint8_t)(value >> shr); ++ ++ if(st->buf) FREEMEM(st->buf); ++ st->buf = buf; ++ st->size = 1 + sizeof(value); ++ ++ return 0; ++} ++ ++int + asn_long2INTEGER(INTEGER_t *st, long value) { + uint8_t *buf, *bp; + uint8_t *p; +@@ -932,3 +1342,58 @@ + + return 0; + } ++ ++int ++asn_int642INTEGER(INTEGER_t *st, int64_t value) { ++ uint8_t *buf, *bp; ++ uint8_t *p; ++ uint8_t *pstart; ++ uint8_t *pend1; ++ int littleEndian = 1; /* Run-time detection */ ++ int add; ++ ++ if(!st) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ buf = (uint8_t *)MALLOC(sizeof(value)); ++ if(!buf) return -1; ++ ++ if(*(char *)&littleEndian) { ++ pstart = (uint8_t *)&value + sizeof(value) - 1; ++ pend1 = (uint8_t *)&value; ++ add = -1; ++ } else { ++ pstart = (uint8_t *)&value; ++ pend1 = pstart + sizeof(value) - 1; ++ add = 1; ++ } ++ ++ /* ++ * If the contents octet consists of more than one octet, ++ * then bits of the first octet and bit 8 of the second octet: ++ * a) shall not all be ones; and ++ * b) shall not all be zero. ++ */ ++ for(p = pstart; p != pend1; p += add) { ++ switch(*p) { ++ case 0x00: if((*(p+add) & 0x80) == 0) ++ continue; ++ break; ++ case 0xff: if((*(p+add) & 0x80)) ++ continue; ++ break; ++ } ++ break; ++ } ++ /* Copy the integer body */ ++ for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) ++ *bp++ = *p; ++ ++ if(st->buf) FREEMEM(st->buf); ++ st->buf = buf; ++ st->size = bp - buf; ++ ++ return 0; ++} +Index: skeletons/NativeReal.h +=================================================================== +--- skeletons/NativeReal.h (revision 1410) ++++ skeletons/NativeReal.h (working copy) +@@ -27,6 +27,8 @@ + xer_type_encoder_f NativeReal_encode_xer; + per_type_decoder_f NativeReal_decode_uper; + per_type_encoder_f NativeReal_encode_uper; ++per_type_decoder_f NativeReal_decode_aper; ++per_type_encoder_f NativeReal_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/constr_SEQUENCE.c +=================================================================== +--- skeletons/constr_SEQUENCE.c (revision 1410) ++++ skeletons/constr_SEQUENCE.c (working copy) +@@ -740,7 +740,7 @@ + if(edx >= td->elements_count + || + /* Explicit OPTIONAL specs reaches the end */ +- (edx + elements[edx].optional ++ (edx + elements[edx].optional + == td->elements_count) + || + /* All extensions are optional */ +@@ -1158,8 +1158,8 @@ + ASN_DEBUG("Read in extensions bitmap for %s of %d bits (%x..)", + td->name, bmlength, *epres); + +- /* Go over extensions and read them in */ +- for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { ++ /* Go over extensions and read them in */ ++ for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ +@@ -1191,7 +1191,7 @@ + FREEMEM(epres); + return rv; + } +- } ++ } + + /* Skip over overflow extensions which aren't present + * in this system's version of the protocol */ +@@ -1240,6 +1240,219 @@ + return rv; + } + ++asn_dec_rval_t ++SEQUENCE_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; ++ void *st = *sptr; /* Target structure. */ ++ int extpresent; /* Extension additions are present */ ++ uint8_t *opres; /* Presence of optional root members */ ++ asn_per_data_t opmd; ++ asn_dec_rval_t rv; ++ int edx; ++ ++ (void)constraints; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ ++ ASN_DEBUG("Decoding %s as SEQUENCE (APER)", td->name); ++ ++ /* Handle extensions */ ++ if(specs->ext_before >= 0) { ++ extpresent = per_get_few_bits(pd, 1); ++ if(extpresent < 0) _ASN_DECODE_STARVED; ++ } else { ++ extpresent = 0; ++ } ++ ++ /* Prepare a place and read-in the presence bitmap */ ++ memset(&opmd, 0, sizeof(opmd)); ++ if(specs->roms_count) { ++ opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); ++ if(!opres) _ASN_DECODE_FAILED; ++ /* Get the presence map */ ++ if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { ++ FREEMEM(opres); ++ _ASN_DECODE_STARVED; ++ } ++ opmd.buffer = opres; ++ opmd.nbits = specs->roms_count; ++ ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", ++ td->name, specs->roms_count, *opres); ++ } else { ++ opres = 0; ++ } ++ ++ /* ++ * Get the sequence ROOT elements. ++ */ ++ for(edx = 0; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ if(IN_EXTENSION_GROUP(specs, edx)) ++ continue; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ memb_ptr = (char *)st + elm->memb_offset; ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Deal with optionality */ ++ if(elm->optional) { ++ int present = per_get_few_bits(&opmd, 1); ++ ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", ++ td->name, elm->name, present, ++ (int)opmd.nboff, (int)opmd.nbits); ++ if(present == 0) { ++ /* This element is not present */ ++ if(elm->default_value) { ++ /* Fill-in DEFAULT */ ++ if(elm->default_value(1, memb_ptr2)) { ++ FREEMEM(opres); ++ _ASN_DECODE_FAILED; ++ } ++ ASN_DEBUG("Filled-in default"); ++ } ++ /* The member is just not present */ ++ continue; ++ } ++ /* Fall through */ ++ } ++ ++ /* Fetch the member from the stream */ ++ ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); ++ rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ if(rv.code != RC_OK) { ++ ASN_DEBUG("Failed decode %s in %s", ++ elm->name, td->name); ++ FREEMEM(opres); ++ return rv; ++ } ++ } ++ ++ /* Optionality map is not needed anymore */ ++ FREEMEM(opres); ++ ++ /* ++ * Deal with extensions. ++ */ ++ if(extpresent) { ++ ssize_t bmlength; ++ uint8_t *epres; /* Presence of extension members */ ++ asn_per_data_t epmd; ++ ++ bmlength = uper_get_nslength(pd); ++ if(bmlength < 0) _ASN_DECODE_STARVED; ++ ++ ASN_DEBUG("Extensions %d present in %s", bmlength, td->name); ++ ++ epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); ++ if(!epres) _ASN_DECODE_STARVED; ++ ++ /* Get the extensions map */ ++ if(per_get_many_bits(pd, epres, 0, bmlength)) ++ _ASN_DECODE_STARVED; ++ ++ memset(&epmd, 0, sizeof(epmd)); ++ epmd.buffer = epres; ++ epmd.nbits = bmlength; ++ ASN_DEBUG("Read in extensions bitmap for %s of %d bits (%x..)", ++ td->name, bmlength, *epres); ++ ++ /* Go over extensions and read them in */ ++ for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ int present; ++ ++ if(!IN_EXTENSION_GROUP(specs, edx)) { ++ ASN_DEBUG("%d is not extension", edx); ++ continue; ++ } ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)st + elm->memb_offset); ++ } else { ++ memb_ptr = (void *)((char *)st + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ present = per_get_few_bits(&epmd, 1); ++ if(present <= 0) { ++ if(present < 0) break; /* No more extensions */ ++ continue; ++ } ++ ++ ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2); ++ rv = uper_open_type_get(opt_codec_ctx, elm->type, ++ elm->per_constraints, memb_ptr2, pd); ++ if(rv.code != RC_OK) { ++ FREEMEM(epres); ++ return rv; ++ } ++ } ++ ++ /* Skip over overflow extensions which aren't present ++ * in this system's version of the protocol */ ++ for(;;) { ++ ASN_DEBUG("Getting overflow extensions"); ++ switch(per_get_few_bits(&epmd, 1)) { ++ case -1: break; ++ case 0: continue; ++ default: ++ if(uper_open_type_skip(opt_codec_ctx, pd)) { ++ FREEMEM(epres); ++ _ASN_DECODE_STARVED; ++ } ++ } ++ break; ++ } ++ ++ FREEMEM(epres); ++ } ++ ++ /* Fill DEFAULT members in extensions */ ++ for(edx = specs->roms_count; edx < specs->roms_count ++ + specs->aoms_count; edx++) { ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void **memb_ptr2; /* Pointer to member pointer */ ++ ++ if(!elm->default_value) continue; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)st ++ + elm->memb_offset); ++ if(*memb_ptr2) continue; ++ } else { ++ continue; /* Extensions are all optionals */ ++ } ++ ++ /* Set default value */ ++ if(elm->default_value(1, memb_ptr2)) { ++ _ASN_DECODE_FAILED; ++ } ++ } ++ ++ rv.consumed = 0; ++ rv.code = RC_OK; ++ return rv; ++} ++ + static int + SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, + asn_per_outp_t *po1, asn_per_outp_t *po2) { +@@ -1283,7 +1496,7 @@ + if(po1 && per_put_few_bits(po1, present, 1)) + return -1; + /* Encode as open type field */ +- if(po2 && present && uper_open_type_put(elm->type, ++ if(po2 && present && aper_open_type_put(elm->type, + elm->per_constraints, *memb_ptr2, po2)) + return -1; + +@@ -1421,3 +1634,130 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++SEQUENCE_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_SEQUENCE_specifics_t *specs ++ = (asn_SEQUENCE_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ int n_extensions; ++ int edx; ++ int i; ++ ++ (void)constraints; ++ ++ if(!sptr) ++ _ASN_ENCODE_FAILED; ++ ++ er.encoded = 0; ++ ++ ASN_DEBUG("Encoding %s as SEQUENCE (APER)", td->name); ++ ++ /* ++ * X.691#18.1 Whether structure is extensible ++ * and whether to encode extensions ++ */ ++ if(specs->ext_before >= 0) { ++ n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0); ++ per_put_few_bits(po, n_extensions ? 1 : 0, 1); ++ } else { ++ n_extensions = 0; /* There are no extensions to encode */ ++ } ++ ++ /* Encode a presence bitmap */ ++ for(i = 0; i < specs->roms_count; i++) { ++ asn_TYPE_member_t *elm; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ int present; ++ ++ edx = specs->oms[i]; ++ elm = &td->elements[edx]; ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ present = (*memb_ptr2 != 0); ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ present = 1; ++ } ++ ++ /* Eliminate default values */ ++ if(present && elm->default_value ++ && elm->default_value(0, memb_ptr2) == 1) ++ present = 0; ++ ++ ASN_DEBUG("Element %s %s %s->%s is %s", ++ elm->flags & ATF_POINTER ? "ptr" : "inline", ++ elm->default_value ? "def" : "wtv", ++ td->name, elm->name, present ? "present" : "absent"); ++ if(per_put_few_bits(po, present, 1)) ++ _ASN_ENCODE_FAILED; ++ } ++ ++ /* ++ * Encode the sequence ROOT elements. ++ */ ++ ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before); ++ for(edx = 0; edx < ((specs->ext_after < 0) ++ ? td->elements_count : specs->ext_before - 1); edx++) { ++ ++ asn_TYPE_member_t *elm = &td->elements[edx]; ++ void *memb_ptr; /* Pointer to the member */ ++ void **memb_ptr2; /* Pointer to that pointer */ ++ ++ if(IN_EXTENSION_GROUP(specs, edx)) ++ continue; ++ ++ ASN_DEBUG("About to encode %s", elm->type->name); ++ ++ /* Fetch the pointer to this member */ ++ if(elm->flags & ATF_POINTER) { ++ memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); ++ if(!*memb_ptr2) { ++ ASN_DEBUG("Element %s %d not present", ++ elm->name, edx); ++ if(elm->optional) ++ continue; ++ /* Mandatory element is missing */ ++ _ASN_ENCODE_FAILED; ++ } ++ } else { ++ memb_ptr = (void *)((char *)sptr + elm->memb_offset); ++ memb_ptr2 = &memb_ptr; ++ } ++ ++ /* Eliminate default values */ ++ if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) ++ continue; ++ ++ ASN_DEBUG("Encoding %s->%s", td->name, elm->name); ++ er = elm->type->aper_encoder(elm->type, elm->per_constraints, ++ *memb_ptr2, po); ++ if(er.encoded == -1) ++ return er; ++ } ++ ++ /* No extensions to encode */ ++ if(!n_extensions) _ASN_ENCODED_OK(er); ++ ++ ASN_DEBUG("Length of %d bit-map", n_extensions); ++ /* #18.8. Write down the presence bit-map length. */ ++ if(aper_put_nslength(po, n_extensions)) ++ _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Bit-map of %d elements", n_extensions); ++ /* #18.7. Encoding the extensions presence bit-map. */ ++ /* TODO: act upon NOTE in #18.7 for canonical PER */ ++ if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions) ++ _ASN_ENCODE_FAILED; ++ ++ ASN_DEBUG("Writing %d extensions", n_extensions); ++ /* #18.9. Encode extensions as open type fields. */ ++ if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions) ++ _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(er); ++} +Index: skeletons/NativeEnumerated.c +=================================================================== +--- skeletons/NativeEnumerated.c (revision 1410) ++++ skeletons/NativeEnumerated.c (working copy) +@@ -30,6 +30,8 @@ + NativeEnumerated_encode_xer, + NativeEnumerated_decode_uper, + NativeEnumerated_encode_uper, ++ NativeEnumerated_decode_aper, ++ NativeEnumerated_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_NativeEnumerated_tags, + sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), +@@ -42,17 +44,17 @@ + + asn_enc_rval_t + NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, +- int ilevel, enum xer_encoder_flags_e flags, +- asn_app_consume_bytes_f *cb, void *app_key) { ++ int ilevel, enum xer_encoder_flags_e flags, ++ asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; +- asn_enc_rval_t er; +- const long *native = (const long *)sptr; ++ asn_enc_rval_t er; ++ const long *native = (const long *)sptr; + const asn_INTEGER_enum_map_t *el; + +- (void)ilevel; +- (void)flags; ++ (void)ilevel; ++ (void)flags; + +- if(!native) _ASN_ENCODE_FAILED; ++ if(!native) _ASN_ENCODE_FAILED; + + el = INTEGER_map_value2enum(specs, *native); + if(el) { +@@ -125,6 +127,61 @@ + return rval; + } + ++asn_dec_rval_t ++NativeEnumerated_decode_aper(asn_codec_ctx_t *opt_codec_ctx, ++ asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, ++ void **sptr, asn_per_data_t *pd) { ++ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; ++ asn_dec_rval_t rval = { RC_OK, 0 }; ++ long *native = (long *)*sptr; ++ asn_per_constraint_t *ct; ++ long value; ++ ++ (void)opt_codec_ctx; ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else _ASN_DECODE_FAILED; /* Mandatory! */ ++ if(!specs) _ASN_DECODE_FAILED; ++ ++ if(!native) { ++ native = (long *)(*sptr = CALLOC(1, sizeof(*native))); ++ if(!native) _ASN_DECODE_FAILED; ++ } ++ ++ ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); ++ ++ if(ct->flags & APC_EXTENSIBLE) { ++ int inext = per_get_few_bits(pd, 1); ++ if(inext < 0) _ASN_DECODE_STARVED; ++ if(inext) ct = 0; ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ value = per_get_few_bits(pd, ct->range_bits); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value >= (specs->extension ++ ? specs->extension - 1 : specs->map_count)) ++ _ASN_DECODE_FAILED; ++ } else { ++ if(!specs->extension) ++ _ASN_DECODE_FAILED; ++ /* ++ * X.691, #10.6: normally small non-negative whole number; ++ */ ++ value = uper_get_nsnnwn(pd); ++ if(value < 0) _ASN_DECODE_STARVED; ++ value += specs->extension - 1; ++ if(value >= specs->map_count) ++ _ASN_DECODE_FAILED; ++ } ++ ++ *native = specs->value2enum[value].nat_value; ++ ASN_DEBUG("Decoded %s = %ld", td->name, *native); ++ ++ return rval; ++} ++ + static int + NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { + const asn_INTEGER_enum_map_t *a = ap; +@@ -205,3 +262,71 @@ + _ASN_ENCODED_OK(er); + } + ++asn_enc_rval_t ++NativeEnumerated_encode_aper(asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; ++ asn_enc_rval_t er; ++ long native, value; ++ asn_per_constraint_t *ct; ++ int inext = 0; ++ asn_INTEGER_enum_map_t key; ++ asn_INTEGER_enum_map_t *kf; ++ ++ if(!sptr) _ASN_ENCODE_FAILED; ++ if(!specs) _ASN_ENCODE_FAILED; ++ ++ if(constraints) ct = &constraints->value; ++ else if(td->per_constraints) ct = &td->per_constraints->value; ++ else _ASN_ENCODE_FAILED; /* Mandatory! */ ++ ++ ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); ++ ++ er.encoded = 0; ++ ++ native = *(long *)sptr; ++ if(native < 0) _ASN_ENCODE_FAILED; ++ ++ key.nat_value = native; ++ kf = bsearch(&key, specs->value2enum, specs->map_count, ++ sizeof(key), NativeEnumerated__compar_value2enum); ++ if(!kf) { ++ ASN_DEBUG("No element corresponds to %ld", native); ++ _ASN_ENCODE_FAILED; ++ } ++ value = kf - specs->value2enum; ++ ++ if(ct->range_bits >= 0) { ++ int cmpWith = specs->extension ++ ? specs->extension - 1 : specs->map_count; ++ if(value >= cmpWith) ++ inext = 1; ++ } ++ if(ct->flags & APC_EXTENSIBLE) { ++ if(per_put_few_bits(po, inext, 1)) ++ _ASN_ENCODE_FAILED; ++ if(inext) ct = 0; ++ } else if(inext) { ++ _ASN_ENCODE_FAILED; ++ } ++ ++ if(ct && ct->range_bits >= 0) { ++ if(per_put_few_bits(po, value, ct->range_bits)) ++ _ASN_ENCODE_FAILED; ++ _ASN_ENCODED_OK(er); ++ } ++ ++ if(!specs->extension) ++ _ASN_ENCODE_FAILED; ++ ++ /* ++ * X.691, #10.6: normally small non-negative whole number; ++ */ ++ ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld", ++ value, specs->extension, inext, ++ value - (inext ? (specs->extension - 1) : 0)); ++ if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0))) ++ _ASN_ENCODE_FAILED; ++ ++ _ASN_ENCODED_OK(er); ++} +Index: skeletons/TeletexString.c +=================================================================== +--- skeletons/TeletexString.c (revision 1410) ++++ skeletons/TeletexString.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_TeletexString_tags, + sizeof(asn_DEF_TeletexString_tags) +Index: skeletons/T61String.c +=================================================================== +--- skeletons/T61String.c (revision 1410) ++++ skeletons/T61String.c (working copy) +@@ -24,6 +24,8 @@ + OCTET_STRING_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_T61String_tags, + sizeof(asn_DEF_T61String_tags) +Index: skeletons/INTEGER.h +=================================================================== +--- skeletons/INTEGER.h (revision 1410) ++++ skeletons/INTEGER.h (working copy) +@@ -18,7 +18,7 @@ + + /* Map with <tag> to integer value association */ + typedef struct asn_INTEGER_enum_map_s { +- long nat_value; /* associated native integer value */ ++ int64_t nat_value; /* associated native integer value */ + size_t enum_len; /* strlen("tag") */ + const char *enum_name; /* "tag" */ + } asn_INTEGER_enum_map_t; +@@ -41,6 +41,8 @@ + xer_type_encoder_f INTEGER_encode_xer; + per_type_decoder_f INTEGER_decode_uper; + per_type_encoder_f INTEGER_encode_uper; ++per_type_decoder_f INTEGER_decode_aper; ++per_type_encoder_f INTEGER_encode_aper; + + /*********************************** + * Some handy conversion routines. * +@@ -52,8 +54,12 @@ + * -1/ERANGE: Value encoded is out of range for long representation + * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). + */ ++int asn_INTEGER2int64(const INTEGER_t *i, int64_t *l); ++int asn_INTEGER2uint64(const INTEGER_t *i, uint64_t *l); + int asn_INTEGER2long(const INTEGER_t *i, long *l); + int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); ++int asn_int642INTEGER(INTEGER_t *i, int64_t l); ++int asn_uint642INTEGER(INTEGER_t *i, uint64_t l); + int asn_long2INTEGER(INTEGER_t *i, long l); + int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); + +Index: skeletons/constr_SEQUENCE.h +=================================================================== +--- skeletons/constr_SEQUENCE.h (revision 1410) ++++ skeletons/constr_SEQUENCE.h (working copy) +@@ -52,6 +52,8 @@ + xer_type_encoder_f SEQUENCE_encode_xer; + per_type_decoder_f SEQUENCE_decode_uper; + per_type_encoder_f SEQUENCE_encode_uper; ++per_type_decoder_f SEQUENCE_decode_aper; ++per_type_encoder_f SEQUENCE_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/BMPString.c +=================================================================== +--- skeletons/BMPString.c (revision 1410) ++++ skeletons/BMPString.c (working copy) +@@ -35,6 +35,8 @@ + BMPString_encode_xer, /* Convert to UTF-8 */ + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, /* Aligned PER decoder */ ++ OCTET_STRING_encode_aper, /* Aligned PER encoder */ + 0, /* Use generic outmost tag fetcher */ + asn_DEF_BMPString_tags, + sizeof(asn_DEF_BMPString_tags) +Index: skeletons/NativeEnumerated.h +=================================================================== +--- skeletons/NativeEnumerated.h (revision 1410) ++++ skeletons/NativeEnumerated.h (working copy) +@@ -24,6 +24,8 @@ + xer_type_encoder_f NativeEnumerated_encode_xer; + per_type_decoder_f NativeEnumerated_decode_uper; + per_type_encoder_f NativeEnumerated_encode_uper; ++per_type_decoder_f NativeEnumerated_decode_aper; ++per_type_encoder_f NativeEnumerated_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/constr_SET_OF.c +=================================================================== +--- skeletons/constr_SET_OF.c (revision 1410) ++++ skeletons/constr_SET_OF.c (working copy) +@@ -884,7 +884,7 @@ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; +- } ++ } + list = _A_SET_FROM_VOID(st); + + /* Figure out which constraints to use */ +@@ -901,7 +901,7 @@ + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + nelems = per_get_few_bits(pd, ct->effective_bits); +- ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", ++ ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s", + (long)nelems, ct->lower_bound, td->name); + if(nelems < 0) _ASN_DECODE_STARVED; + nelems += ct->lower_bound; +@@ -951,3 +951,91 @@ + return rv; + } + ++asn_dec_rval_t ++SET_OF_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ++ asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { ++ asn_dec_rval_t rv; ++ asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; ++ asn_TYPE_member_t *elm = td->elements; /* Single one */ ++ void *st = *sptr; ++ asn_anonymous_set_ *list; ++ asn_per_constraint_t *ct; ++ int repeat = 0; ++ ssize_t nelems; ++ ++ if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) ++ _ASN_DECODE_FAILED; ++ ++ /* ++ * Create the target structure if it is not present already. ++ */ ++ if(!st) { ++ st = *sptr = CALLOC(1, specs->struct_size); ++ if(!st) _ASN_DECODE_FAILED; ++ } ++ list = _A_SET_FROM_VOID(st); ++ ++ /* Figure out which constraints to use */ ++ if(constraints) ct = &constraints->size; ++ else if(td->per_constraints) ct = &td->per_constraints->size; ++ else ct = 0; ++ ++ if(ct && ct->flags & APC_EXTENSIBLE) { ++ int value = per_get_few_bits(pd, 1); ++ if(value < 0) _ASN_DECODE_STARVED; ++ if(value) ct = 0; /* Not restricted! */ ++ } ++ ++ if(ct && ct->effective_bits >= 0) { ++ /* X.691, #19.5: No length determinant */ ++// nelems = per_get_few_bits(pd, ct->effective_bits); ++ nelems = aper_get_nsnnwn(pd, ct->upper_bound - ct->lower_bound); ++ ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s", ++ (long)nelems, ct->lower_bound, td->name); ++ if(nelems < 0) _ASN_DECODE_STARVED; ++ nelems += ct->lower_bound; ++ } else { ++ nelems = -1; ++ } ++ ++ do { ++ int i; ++ if(nelems < 0) { ++ nelems = aper_get_length(pd, ct ? ct->upper_bound - ct->lower_bound + 1 : -1, ++ ct ? ct->effective_bits : -1, &repeat); ++ ASN_DEBUG("Got to decode %d elements (eff %d)", ++ (int)nelems, (int)ct ? ct->effective_bits : -1); ++ if(nelems < 0) _ASN_DECODE_STARVED; ++ } ++ ++ for(i = 0; i < nelems; i++) { ++ void *ptr = 0; ++ ASN_DEBUG("SET OF %s decoding", elm->type->name); ++ rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, ++ elm->per_constraints, &ptr, pd); ++ ASN_DEBUG("%s SET OF %s decoded %d, %p", ++ td->name, elm->type->name, rv.code, ptr); ++ if(rv.code == RC_OK) { ++ if(ASN_SET_ADD(list, ptr) == 0) ++ continue; ++ ASN_DEBUG("Failed to add element into %s", ++ td->name); ++ /* Fall through */ ++ rv.code = RC_FAIL; ++ } else { ++ ASN_DEBUG("Failed decoding %s of %s (SET OF)", ++ elm->type->name, td->name); ++ } ++ if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); ++ return rv; ++ } ++ ++ nelems = -1; /* Allow uper_get_length() */ ++ } while(repeat); ++ ++ ASN_DEBUG("Decoded %s as SET OF", td->name); ++ ++ rv.code = RC_OK; ++ rv.consumed = 0; ++ return rv; ++} +Index: skeletons/per_opentype.c +=================================================================== +--- skeletons/per_opentype.c (revision 1410) ++++ skeletons/per_opentype.c (working copy) +@@ -53,6 +53,35 @@ + return 0; + } + ++int ++aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { ++ void *buf; ++ void *bptr; ++ ssize_t size; ++ size_t toGo; ++ ++ ASN_DEBUG("Open type put %s ...", td->name); ++ ++ size = aper_encode_to_new_buffer(td, constraints, sptr, &buf); ++ if(size <= 0) return -1; ++ ++ for(bptr = buf, toGo = size; toGo;) { ++ ssize_t maySave = aper_put_length(po, -1, toGo); ++ if(maySave < 0) break; ++ if(per_put_many_bits(po, bptr, maySave * 8)) break; ++ bptr = (char *)bptr + maySave; ++ toGo -= maySave; ++ } ++ ++ FREEMEM(buf); ++ if(toGo) return -1; ++ ++ ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", ++ td->name, size); ++ ++ return 0; ++} ++ + static asn_dec_rval_t + uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { +Index: skeletons/UTCTime.c +=================================================================== +--- skeletons/UTCTime.c (revision 1410) ++++ skeletons/UTCTime.c (working copy) +@@ -40,6 +40,8 @@ + UTCTime_encode_xer, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UTCTime_tags, + sizeof(asn_DEF_UTCTime_tags) +Index: skeletons/constr_SET_OF.h +=================================================================== +--- skeletons/constr_SET_OF.h (revision 1410) ++++ skeletons/constr_SET_OF.h (working copy) +@@ -34,6 +34,8 @@ + xer_type_encoder_f SET_OF_encode_xer; + per_type_decoder_f SET_OF_decode_uper; + per_type_encoder_f SET_OF_encode_uper; ++per_type_decoder_f SET_OF_decode_aper; ++per_type_encoder_f SET_OF_encode_aper; + + #ifdef __cplusplus + } +Index: skeletons/UTF8String.c +=================================================================== +--- skeletons/UTF8String.c (revision 1410) ++++ skeletons/UTF8String.c (working copy) +@@ -25,6 +25,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UTF8String_tags, + sizeof(asn_DEF_UTF8String_tags) +Index: skeletons/per_opentype.h +=================================================================== +--- skeletons/per_opentype.h (revision 1410) ++++ skeletons/per_opentype.h (working copy) +@@ -15,6 +15,8 @@ + + int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); + ++int aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); ++ + #ifdef __cplusplus + } + #endif +Index: skeletons/ISO646String.c +=================================================================== +--- skeletons/ISO646String.c (revision 1410) ++++ skeletons/ISO646String.c (working copy) +@@ -29,6 +29,8 @@ + OCTET_STRING_encode_xer_utf8, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_ISO646String_tags, + sizeof(asn_DEF_ISO646String_tags) +Index: skeletons/asn_internal.h +=================================================================== +--- skeletons/asn_internal.h (revision 1410) ++++ skeletons/asn_internal.h (working copy) +@@ -20,7 +20,7 @@ + #endif + + /* Environment version might be used to avoid running with the old library */ +-#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ ++#define ASN1C_ENVIRONMENT_VERSION 924 /* Compile-time version */ + int get_asn1c_environment_version(void); /* Run-time version */ + + #define CALLOC(nmemb, size) calloc(nmemb, size) +@@ -40,13 +40,17 @@ + #else /* !ASN_THREAD_SAFE */ + int asn_debug_indent; + #endif /* ASN_THREAD_SAFE */ +-#define ASN_DEBUG(fmt, args...) do { \ +- int adi = asn_debug_indent; \ ++extern int asn_debug; ++#define ASN_DEBUG(fmt, args...) \ ++do { \ ++ if(asn_debug) { \ ++ int adi = asn_debug_indent; \ + while(adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ +- __FILE__, __LINE__); \ +- } while(0) ++ __FILE__, __LINE__); \ ++ } \ ++} while(0) + #else /* !__GNUC__ */ + void ASN_DEBUG_f(const char *fmt, ...); + #define ASN_DEBUG ASN_DEBUG_f +Index: skeletons/ANY.c +=================================================================== +--- skeletons/ANY.c (revision 1410) ++++ skeletons/ANY.c (working copy) +@@ -21,7 +21,10 @@ + OCTET_STRING_encode_der, + OCTET_STRING_decode_xer_hex, + ANY_encode_xer, +- 0, 0, ++ OCTET_STRING_decode_uper, ++ OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + 0, 0, 0, 0, + 0, /* No PER visible constraints */ +@@ -87,6 +90,37 @@ + return 0; + } + ++int ++ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr) { ++ uint8_t *buffer = NULL; ++ ssize_t erval; ++ ++ if(!st || !td) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if(!sptr) { ++ if(st->buf) FREEMEM(st->buf); ++ st->size = 0; ++ return 0; ++ } ++ ++ erval = aper_encode_to_new_buffer(td, td->per_constraints, sptr, (void**)&buffer); ++ ++ if(erval == -1) { ++ if(buffer) FREEMEM(buffer); ++ return -1; ++ } ++ assert((size_t)erval > 0); ++ ++ if(st->buf) FREEMEM(st->buf); ++ st->buf = buffer; ++ st->size = erval; ++ ++ return 0; ++} ++ + ANY_t * + ANY_new_fromType(asn_TYPE_descriptor_t *td, void *sptr) { + ANY_t tmp; +@@ -111,6 +145,30 @@ + } + } + ++ANY_t * ++ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr) { ++ ANY_t tmp; ++ ANY_t *st; ++ ++ if(!td || !sptr) { ++ errno = EINVAL; ++ return 0; ++ } ++ ++ memset(&tmp, 0, sizeof(tmp)); ++ ++ if(ANY_fromType_aper(&tmp, td, sptr)) return 0; ++ ++ st = (ANY_t *)CALLOC(1, sizeof(ANY_t)); ++ if(st) { ++ *st = tmp; ++ return st; ++ } else { ++ FREEMEM(tmp.buf); ++ return 0; ++ } ++} ++ + int + ANY_to_type(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) { + asn_dec_rval_t rval; +@@ -138,6 +196,33 @@ + } + } + ++int ++ANY_to_type_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) { ++ asn_dec_rval_t rval; ++ void *newst = 0; ++ ++ if(!st || !td || !struct_ptr) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if(st->buf == 0) { ++ /* Nothing to convert, make it empty. */ ++ *struct_ptr = (void *)0; ++ return 0; ++ } ++ ++ rval = aper_decode(0, td, (void **)&newst, st->buf, st->size, 0, 0); ++ if(rval.code == RC_OK) { ++ *struct_ptr = newst; ++ return 0; ++ } else { ++ /* Remove possibly partially decoded data. */ ++ ASN_STRUCT_FREE(*td, newst); ++ return -1; ++ } ++} ++ + static int ANY__consume_bytes(const void *buffer, size_t size, void *key) { + struct _callback_arg *arg = (struct _callback_arg *)key; + +Index: skeletons/ANY.h +=================================================================== +--- skeletons/ANY.h (revision 1410) ++++ skeletons/ANY.h (working copy) +@@ -32,10 +32,13 @@ + + /* Convert another ASN.1 type into the ANY. This implies DER encoding. */ + int ANY_fromType(ANY_t *, asn_TYPE_descriptor_t *td, void *struct_ptr); ++int ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr); + ANY_t *ANY_new_fromType(asn_TYPE_descriptor_t *td, void *struct_ptr); ++ANY_t *ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr); + + /* Convert the contents of the ANY type into the specified type. */ + int ANY_to_type(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr); ++int ANY_to_type_aper(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr); + + #define ANY_fromBuf(s, buf, size) OCTET_STRING_fromBuf((s), (buf), (size)) + #define ANY_new_fromBuf(buf, size) OCTET_STRING_new_fromBuf( \ +Index: skeletons/UniversalString.c +=================================================================== +--- skeletons/UniversalString.c (revision 1410) ++++ skeletons/UniversalString.c (working copy) +@@ -35,6 +35,8 @@ + UniversalString_encode_xer, /* Convert into UTF-8 */ + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, ++ OCTET_STRING_decode_aper, ++ OCTET_STRING_encode_aper, + 0, /* Use generic outmost tag fetcher */ + asn_DEF_UniversalString_tags, + sizeof(asn_DEF_UniversalString_tags) +Index: libasn1compiler/asn1c_out.h +=================================================================== +--- libasn1compiler/asn1c_out.h (revision 1410) ++++ libasn1compiler/asn1c_out.h (working copy) +@@ -119,15 +119,23 @@ + #define OINT(iv) do { \ + if(iv == (-2147483647L - 1)) \ + OUT("(-2147483647L - 1)"); \ +- else \ +- OUT("%" PRIdASN, iv); \ ++ else if (iv > 4294967296UL) \ ++ OUT("%" PRIdASN "ull", iv); \ ++ else if (iv > 2147483647L) \ ++ OUT("%" PRIdASN "ul", iv); \ ++ else \ ++ OUT("%" PRIdASN "l", iv); \ + } while(0) + + #define OINTS(iv) do { \ + if(iv == (-2147483647L - 1)) \ + OUT("(-2147483647L - 1)"); \ +- else \ +- OUT("% " PRIdASN, iv); \ ++ else if (iv > 4294967296UL) \ ++ OUT("%" PRIdASN "ull", iv); \ ++ else if (iv > 2147483647L) \ ++ OUT("%" PRIdASN "ul", iv); \ ++ else \ ++ OUT("% " PRIdASN "l", iv); \ + } while(0) + + #endif /* _ASN1_COMPILED_OUTPUT_H_ */ +Index: libasn1compiler/asn1c_C.c +=================================================================== +--- libasn1compiler/asn1c_C.c (revision 1410) ++++ libasn1compiler/asn1c_C.c (working copy) +@@ -139,9 +139,8 @@ + OUT("\t"); + out_name_chain(arg, ONC_noflags); + OUT("_%s", MKID(v)); +- OUT("\t= %" PRIdASN "%s\n", +- v->value->value.v_integer, +- (eidx+1 < el_count) ? "," : ""); ++ OUT("\t= %" PRIdASN ",\n", ++ v->value->value.v_integer); + v2e[eidx].name = v->Identifier; + v2e[eidx].value = v->value->value.v_integer; + eidx++; +@@ -157,6 +156,11 @@ + return -1; + } + } ++ /* Max value for comparing */ ++ OUT("\t"); ++ out_name_chain(arg, ONC_noflags); ++ OUT("_max,\n"); ++ + OUT("} e_"); + out_name_chain(arg, ONC_noflags); + OUT(";\n"); +@@ -513,6 +517,7 @@ + ); + mcount++; + } ++ + OUT("} "); out_name_chain(arg, ONC_noflags); OUT("_PR;\n"); + + REDIR(OT_TYPE_DECLS); +@@ -859,23 +864,23 @@ + out_name_chain(arg, ONC_noflags); + OUT("_PR {\n"); + INDENTED( +- int skipComma = 1; + out_name_chain(arg, ONC_noflags); + OUT("_PR_NOTHING,\t/* No components present */\n"); + TQ_FOR(v, &(expr->members), next) { +- if(skipComma) skipComma = 0; +- else OUT(",\n"); + if(v->expr_type == A1TC_EXTENSIBLE) { + OUT("/* Extensions may appear below */\n"); +- skipComma = 1; + continue; + } + out_name_chain(arg, ONC_noflags); + id = MKID(v); +- OUT("_PR_%s", id); ++ OUT("_PR_%s,\n", id); + } + OUT("\n"); + ); ++ INDENTED( ++ out_name_chain(arg, ONC_noflags); ++ OUT("_max,\n"); ++ ); + OUT("} "); out_name_chain(arg, ONC_noflags); OUT("_PR;\n"); + + REDIR(OT_TYPE_DECLS); +@@ -1242,6 +1247,8 @@ + OUT("td->xer_encoder = asn_DEF_%s.xer_encoder;\n", type_name); + OUT("td->uper_decoder = asn_DEF_%s.uper_decoder;\n", type_name); + OUT("td->uper_encoder = asn_DEF_%s.uper_encoder;\n", type_name); ++ OUT("td->aper_decoder = asn_DEF_%s.aper_decoder;\n", type_name); ++ OUT("td->aper_encoder = asn_DEF_%s.aper_encoder;\n", type_name); + if(!terminal && !tags_count) { + OUT("/* The next four lines are here because of -fknown-extern-type */\n"); + OUT("td->tags = asn_DEF_%s.tags;\n", type_name); +@@ -1394,8 +1401,40 @@ + ); + OUT("}\n"); + OUT("\n"); +- } + ++ p = MKID(expr); ++ if(HIDE_INNER_DEFS) OUT("static "); ++ OUT("asn_enc_rval_t\n"); ++ OUT("%s", p); ++ if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index); ++ OUT("_encode_aper(asn_TYPE_descriptor_t *td,\n"); ++ INDENTED( ++ OUT("\tasn_per_constraints_t *constraints,\n"); ++ OUT("\tvoid *structure, asn_per_outp_t *per_out) {\n"); ++ OUT("%s_%d_inherit_TYPE_descriptor(td);\n", ++ p, expr->_type_unique_index); ++ OUT("return td->aper_encoder(td, constraints, structure, per_out);\n"); ++ ); ++ OUT("}\n"); ++ OUT("\n"); ++ ++ p = MKID(expr); ++ ++ if(HIDE_INNER_DEFS) OUT("static "); ++ OUT("asn_dec_rval_t\n"); ++ OUT("%s", p); ++ if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index); ++ OUT("_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,\n"); ++ INDENTED( ++ OUT("\tasn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) {\n"); ++ OUT("%s_%d_inherit_TYPE_descriptor(td);\n", ++ p, expr->_type_unique_index); ++ OUT("return td->aper_decoder(opt_codec_ctx, td, constraints, structure, per_data);\n"); ++ ); ++ OUT("}\n"); ++ OUT("\n"); ++ } ++ + REDIR(OT_FUNC_DECLS); + + p = MKID(expr); +@@ -1415,6 +1454,8 @@ + if(arg->flags & A1C_GEN_PER) { + OUT("per_type_decoder_f %s_decode_uper;\n", p); + OUT("per_type_encoder_f %s_encode_uper;\n", p); ++ OUT("per_type_decoder_f %s_decode_aper;\n", p); ++ OUT("per_type_encoder_f %s_encode_aper;\n", p); + } + } + +@@ -2001,7 +2042,7 @@ + break; + case ASN_STRING_UniversalString: + OUT("{ APC_CONSTRAINED,\t32, 32," +- " 0, 2147483647 }" ++ " 0, 2147483647L }" + " /* special case 1 */\n"); + goto avoid; + default: +@@ -2454,9 +2495,13 @@ + if(arg->flags & A1C_GEN_PER) { + FUNCREF(decode_uper); + FUNCREF(encode_uper); ++ FUNCREF(decode_aper); ++ FUNCREF(encode_aper); + } else { +- OUT("0, 0,\t/* No PER support, " ++ OUT("0, 0,\t/* No UPER support, " + "use \"-gen-PER\" to enable */\n"); ++ OUT("0, 0,\t/* No APER support, " ++ "use \"-gen-PER\" to enable */\n"); + } + + if(!terminal || terminal->expr_type == ASN_CONSTR_CHOICE) { +Index: libasn1compiler/asn1c_misc.c +=================================================================== +--- libasn1compiler/asn1c_misc.c (revision 1410) ++++ libasn1compiler/asn1c_misc.c (working copy) +@@ -370,7 +370,7 @@ + if(left.type == ARE_VALUE + && left.value >= 0 + && right.type == ARE_VALUE +- && right.value > 2147483647 ++ && right.value > 2147483647L + && right.value <= 4294967295UL) + return FL_FITS_UNSIGN; + +Index: asn1c/unber.c +=================================================================== +--- asn1c/unber.c (revision 1410) ++++ asn1c/unber.c (working copy) +@@ -772,4 +772,8 @@ + + asn_enc_rval_t OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; } + ++asn_dec_rval_t OCTET_STRING_decode_aper(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv = { 0, 0 }; (void)ctx; (void)td; (void)cts; (void)sptr; (void)pd; return rv; } ++ ++asn_enc_rval_t OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; } ++ + int xer_is_whitespace(const void *b, size_t s) { (void)b; (void)s; return 0; } diff --git a/openair-cn/S1AP/MESSAGES/ASN1/asn1tostruct.py b/openair-cn/S1AP/MESSAGES/ASN1/asn1tostruct.py new file mode 100644 index 0000000000..479f45e91a --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/ASN1/asn1tostruct.py @@ -0,0 +1,678 @@ +import re, os, sys, string +import datetime +import getopt +import getpass + +version = "1.0.0" + +lines = "" +iesDefs = {} +ieofielist = {} +outdir = './' + +filenames = [] +verbosity = 0 +prefix = "" + +FAIL = '\033[91m' +WARN = '\033[93m' +ENDC = '\033[0m' + +fileprefix = "" + +def printFail(string): + sys.stderr.write(FAIL + string + ENDC + "\n") + +def printWarning(string): + print WARN + string + ENDC + +def printDebug(string): + if verbosity > 0: + print string + +def outputHeaderToFile(f, filename): + now = datetime.datetime.now() + f.write("""/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +""") + f.write("/*******************************************************************************\n") + f.write(" * This file had been created by asn1tostruct.py script v%s\n" % (version)) + f.write(" * Please do not modify this file but regenerate it via script.\n") + f.write(" * Created on: %s by %s\n * from %s\n" % (str(now), getpass.getuser(), filenames)) + f.write(" ******************************************************************************/\n") + +def lowerFirstCamelWord(word): + """ puts the first word in a CamelCase Word in lowercase. + + I.e. CustomerID becomes customerID, XMLInfoTest becomes xmlInfoTest + """ + newstr = '' + swapped = word.swapcase() + idx = 0 + + # if it's all-caps, return an all-lowered version + lowered = word.lower() + + if swapped == lowered: + return lowered + + for c in swapped: + if c in string.lowercase: + newstr += c + idx += 1 + else: + break + if idx < 2: + newstr += word[idx:] + else: + newstr = newstr[:-1]+ word[idx-1:] + + return newstr + +def usage(): + print "Python parser for asn1 v%s" % (version) + print "Usage: python asn1tostruct.py [options]" + print "Available options:" + print "-d Enable script debug" + print "-f [file] Input file to parse" + print "-o [dir] Output files to given directory" + print "-h Print this help and return" + +try: + opts, args = getopt.getopt(sys.argv[1:], "df:ho:", ["debug", "file", "help", "outdir"]) +except getopt.GetoptError as err: + # print help information and exit: + usage() + sys.exit(2) + +for o, a in opts: + if o in ("-f", "--file"): + filenames.append(a) + if o in ("-d", "--debug"): + verbosity = 1 + if o in ("-o", "--outdir"): + outdir = a + if outdir.rfind('/') != len(outdir): + outdir += '/' + if o in ("-h", "--help"): + usage() + sys.exit(2) + +for filename in filenames: + file = open(filename, 'r') + for line in file: + # Removing any comment + if line.find('--') >= 0: + line = line[:line.find('--')] + # Removing any carriage return + lines += re.sub('\r', '', line) + + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+SEQUENCE\s+\(\s*SIZE\s*\(\s*\d+\s*\.\.\s*[0-9a-zA-Z-]+\s*\)\s*\)\s*OF\s+[a-zA-Z-]+\s*\{\s*\{\s*([0-9a-zA-Z-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + for m in re.findall(r'([a-zA-Z0-9-]+)\s*::=\s+E-RAB-IE-ContainerList\s*\{\s*\{\s*([a-zA-Z0-9-]+)\s*\}\s*\}', lines, re.MULTILINE): + ieofielist[m[0]] = m[1] + + for i in re.findall(r'([a-zA-Z0-9-]+)\s+([A-Z0-9-]+)\s*::=\s*\{\s+([\,\|\{\}\t\n\.{3}\ \-a-zA-Z0-9]+)\s+}\n', lines, re.MULTILINE): + ies = [] + maxLength = 0 + # TODO: handle extensions + if i[1].find('EXTENSION') >= 0: + continue + if fileprefix == "": + fileprefix = i[1][:i[1].find('-')].lower() + for j in re.findall(r'\s*\{\s*([a-zA-Z0-9-\ \t]+)\s*\}\s*[\|,]*', i[2], re.MULTILINE): + for k in re.findall(r'ID\s*([a-zA-Z0-9\-]+)\s*CRITICALITY\s*([a-zA-Z0-9\-]+)\s+[A-Z]+\s+([a-zA-Z0-9\-]+)\s*PRESENCE\s*([a-zA-Z0-9\-]+)', j, re.MULTILINE): + printDebug("Got new ie for message " + i[0] + ": " + str(k)) + if len(k[2]) > maxLength: + maxLength = len(k[2]) + ies.append(k) + + if len(ies) > 0: + iesDefs[i[0]] = { "length": maxLength, "ies": ies } + else: + printWarning("Didn't find any information element for message: " + i[0]) + +if len(iesDefs) == 0: + printFail("No Information Element parsed, exiting") + sys.exit(0) + +f = open(outdir + fileprefix + '_ies_defs.h', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n\n" % (fileprefix)) +f.write("#ifndef %s_IES_DEFS_H_\n#define %s_IES_DEFS_H_\n\n" % (fileprefix.upper(), fileprefix.upper())) +f.write("/* Define the version of script used to generate this file */\n") +f.write("#define %s_SCRIPT_VERSION (%s)\n\n" % (fileprefix.upper(), re.sub('\.', '', version))) + +for key in iesDefs: + + if key not in ieofielist.values(): + continue + + for (i, j) in ieofielist.items(): + if j == key: + break + + f.write("typedef struct %sIEs_s {\n" % (re.sub('-', '_', i))) + f.write(" A_SEQUENCE_OF(struct %s_s) %s;\n" % (re.sub('IEs', '', re.sub('-', '_', ieofielist[i])), lowerFirstCamelWord(re.sub('IEs', '', re.sub('-', '_', ieofielist[i]))))) + f.write("} %sIEs_t;\n\n" % (re.sub('-', '_', i))) + +for key in iesDefs: + keyupperunderscore = re.sub('-', '_', key.upper()) + keylowerunderscore = re.sub('-', '_', key.lower()) + shift = 0 + + if len(iesDefs[key]["ies"]) == 0: + continue + + # Presence mask + for ie in iesDefs[key]["ies"]: + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional" or ie[3] == "conditional": + f.write("#define {0:<{pad}} {1}\n".format("%s_%s_PRESENT" % (keyupperunderscore, ieupperunderscore), "(1 << %d)" % shift, + pad=iesDefs[key]["length"] + len(keyupperunderscore) + 9)) + shift += 1 + if (shift > 0): + f.write("\n") + + f.write("typedef struct %s_s {\n" % (re.sub('-', '_', key))) + if (shift > 0): + f.write(" {0:<{pad}} {1};\n".format("uint16_t", "presenceMask", pad=iesDefs[key]["length"] + 2)) + for ie in iesDefs[key]["ies"]: + ieunderscore = re.sub('-', '_', ie[2]) + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + if ie[2] in ieofielist: + f.write(" %sIEs_t %s;" % (re.sub('-', '_', ie[2]), ienameunderscore)) + else: + f.write(" {0:<{pad}} {1};".format("%s_t" % ieunderscore, ienameunderscore, pad=iesDefs[key]["length"] + 2)) + if ie[3] == "optional": + f.write(" ///< Optional field") + elif ie[3] == "conditional": + f.write(" ///< Conditional field") + f.write("\n") + + f.write("} %s_t;\n\n" % (re.sub('-', '_', key))) + +f.write("typedef struct %s_message_s {\n" % (fileprefix)) +f.write(" ProcedureCode_t procedureCode;\n") +f.write(" Criticality_t criticality;\n") +f.write(" uint8_t direction;\n") +f.write(" union {\n") + +messageList = iesDefs.keys() +messageList.sort() +for message in messageList: + if message in ieofielist.values(): + continue + if len(iesDefs[message]["ies"]) == 0: + continue + f.write(" %s_t %s;\n" % (re.sub('-', '_', message), lowerFirstCamelWord(re.sub('-', '_', message)))) +f.write(" } msg;\n") +f.write("} %s_message;\n\n" % (fileprefix)) + +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + keylowerunderscore = re.sub('-', '_', key.lower()) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + if len(iesDefs[key]["ies"]) != 0: + f.write(" * \\param %s Pointer to ASN1 structure in which data will be stored\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" **/\n") + f.write("int %s_decode_%s(\n" % (fileprefix, keylowerunderscore)) + + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p);\n\n") + + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + +for key in iesDefs: + if key not in ieofielist.values(): + continue + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + f.write("/** \\brief Encode function for %s ies.\n" % (key)) + f.write(" * \\param %s Pointer to the ASN1 structure.\n" % (firstlower)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" **/\n") + f.write("int %s_encode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstlower)) + f.write(" %sIEs_t *%sIEs);\n\n" % (asn1cStruct, firstlower)) + f.write("/** \\brief Decode function for %s ies.\n" % (key)) + f.write(" * \\param any_p Pointer to the ANY value to decode.\n") + f.write(" * \\param callback Callback function called when any_p is successfully decoded.\n") + f.write(" **/\n") + f.write("int %s_decode_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" %sIEs_t *%sIEs,\n" % (asn1cStruct, firstlower)) + f.write(" %s_t *%s);\n\n" % (asn1cStruct, lowerFirstCamelWord(asn1cStruct))) + +for key in iesDefs: + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + if key in ieofielist.values(): + f.write("/** \\brief Display %s encapsulated IE using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param %s Pointer to the IES structure.\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('item', 'list', firstlower.lower()))) + f.write(" FILE *file,\n") + f.write(" %sIEs_t *%sIEs);\n\n" % (re.sub('item', 'list', asn1cStruct), firstlower)) + else: + f.write("/** \\brief Display %s message using XER encoding.\n" % (asn1cStruct)) + f.write(" * \\param message_p Pointer to root message.\n") + f.write(" * \\param file File descriptor to write output.\n") + f.write(" **/\n") + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, firstlower.lower())) + f.write(" FILE *file,\n") + f.write(" %s_message *message_p);\n\n" % (fileprefix)) +f.write("#endif /* %s_IES_DEFS_H_ */\n\n" % (fileprefix.upper())) + +#Generate Decode functions +f = open(outdir + fileprefix + '_decoder.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + ielistname = re.sub('UE', 'ue', asn1cStruct) + ielistnamefirstlower = ielistname[:1].lower() + ielistname[1:] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + firstlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstlower) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + if len(iesDefs[key]["ies"]) != 0: + f.write(" %s_t *%s,\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + f.write(" ANY_t *any_p) {\n\n") + + f.write(" %s_t %s;\n %s_t *%s_p = &%s;\n" % (asn1cStruct, asn1cStructfirstlower, asn1cStruct, asn1cStructfirstlower, asn1cStructfirstlower)) + f.write(" int i, decoded = 0;\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" int tempDecoded = 0;\n") + + f.write(" assert(any_p != NULL);\n") + if len(iesDefs[key]["ies"]) != 0: + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" %s_DEBUG(\"Decoding message %s (%%s:%%d)\\n\", __FILE__, __LINE__);\n\n" % (fileprefix.upper(), re.sub('-', '_', keyName))) + f.write(" ANY_to_type_aper(any_p, &asn_DEF_%s, (void**)&%s_p);\n\n" % (asn1cStruct, asn1cStructfirstlower)) + f.write(" for (i = 0; i < %s_p->%slist.count; i++) {\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" IE_t *ie_p;\n") + f.write(" ie_p = %s_p->%slist.array[i];\n" % (asn1cStructfirstlower, iesaccess)) + f.write(" switch(ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + ienameunderscorefirstlower = lowerFirstCamelWord(ienameunderscore) + ietypesubst = re.sub('-', '', ie[2]) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" case ProtocolIE_ID_%s:\n" % (re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[3] != "mandatory": + f.write(" %s->presenceMask |= %s_%s_PRESENT;\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of IE %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore)) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + if ie[2] in ieofielist.keys(): + f.write(" if (%s_decode_%s(&%s->%s, %s_p) < 0) {\n" % (fileprefix, ietypeunderscore.lower(), lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" %s_ERROR(\"Decoding of encapsulated IE %s failed\\n\");\n" % (fileprefix.upper(), lowerFirstCamelWord(ietypesubst))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" }\n") + else: + f.write(" memcpy(&%s->%s, %s_p, sizeof(%s_t));\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienameunderscore, lowerFirstCamelWord(ietypesubst), ietypeunderscore)) + #f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (ietypeunderscore, lowerFirstCamelWord(ietypesubst))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + +for key in iesDefs: + if key not in ieofielist.values(): + continue + + keyname = re.sub('IEs', '', re.sub('Item', 'List', key)) + + f.write("int %s_decode_%s(\n" % (fileprefix, re.sub('-', '_', keyname).lower())) + f.write(" %sIEs_t *%sIEs,\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', keyname), lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" int i, decoded = 0;\n") + f.write(" int tempDecoded = 0;\n\n") + + f.write(" assert(%s != NULL);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))); + + f.write(" for (i = 0; i < %s->list.count; i++) {\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" IE_t *ie_p = %s->list.array[i];\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)))) + f.write(" switch (ie_p->id) {\n") + for ie in iesDefs[key]["ies"]: + iename = re.sub('id-', '', ie[0]) + ienameunderscore = lowerFirstCamelWord(re.sub('-', '_', iename)) + f.write(" case ProtocolIE_ID_%s:\n" % (re.sub('-', '_', ie[0]))) + f.write(" {\n") + f.write(" %s_t *%s_p = NULL;\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" tempDecoded = ANY_to_type_aper(&ie_p->value, &asn_DEF_%s, (void**)&%s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" if (tempDecoded < 0 || %s_p == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" %s_ERROR(\"Decoding of IE %s for message %s failed\\n\");\n" % (fileprefix.upper(), ienameunderscore, re.sub('-', '_', keyname))) + f.write(" if (%s_p)\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + #f.write(" free(%s_p);\n" % (lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_STRUCT_FREE(asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" decoded += tempDecoded;\n") + f.write(" if (asn1_xer_print)\n") + f.write(" xer_fprint(stdout, &asn_DEF_%s, %s_p);\n" % (re.sub('-', '_', ie[2]), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" ASN_SEQUENCE_ADD(&%sIEs->%s, %s_p);\n" % (lowerFirstCamelWord(re.sub('-', '_', keyname)), + re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))), lowerFirstCamelWord(re.sub('-', '', ie[2])))) + f.write(" } break;\n") + f.write(" default:\n") + f.write(" %s_ERROR(\"Unknown protocol IE id (%%d) for message %s\\n\", (int)ie_p->id);\n" % (fileprefix.upper(), re.sub('-', '_', structName.lower()))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" }\n") + f.write(" return decoded;\n") + f.write("}\n\n") + + +#Generate IES Encode functions +f = open(outdir + fileprefix + '_encoder.c', 'w') +outputHeaderToFile(f,filename) +f.write("#include \"%s_common.h\"\n" % (fileprefix)) +f.write("#include \"%s_ies_defs.h\"\n\n" % (fileprefix)) +for key in iesDefs: + if key in ieofielist.values(): + continue + + structName = re.sub('ies', '', key) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', key)) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + if asn1cStruct.rfind('_') == len(asn1cStruct) - 1: + asn1cStruct = asn1cStruct[:-1] + asn1cStructfirstlower = asn1cStruct[:1].lower() + asn1cStruct[1:] + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + iesaccess = "" + if key not in ieofielist.values(): + iesaccess = "%s_ies." % (firstwordlower) + + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + # No IE to encode... + if len(iesDefs[key]["ies"]) == 0: + continue + + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', structName.lower()))) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %s_t *%s) {\n\n" % (re.sub('-', '_', key), lowerFirstCamelWord(re.sub('-', '_', key)))) + + f.write(" IE_t *ie;\n\n") + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%s != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', key)))); + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + ietypeunderscore = re.sub('-', '_', ie[2]) + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), keyupperunderscore, ieupperunderscore)) + #f.write(" == %s_%s_PRESENT) {\n" % (keyupperunderscore, ieupperunderscore)) + f.write(" if ((ie = %s_new_ie(ProtocolIE_ID_%s,\n" % (fileprefix, re.sub('-', '_', ie[0]))) + f.write(" Criticality_%s,\n" % (ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n" % (firstwordlower, iesaccess)) + f.write(" }\n\n") + else: + if ie[2] in ieofielist.keys(): + f.write(" %s_t %s;\n\n" % (ietypeunderscore, ienamefirstwordlower)) + f.write(" memset(&%s, 0, sizeof(%s_t));\n" % (ienamefirstwordlower, ietypeunderscore)) + f.write("\n") + f.write(" if (%s_encode_%s(&%s, &%s->%s) < 0) return -1;\n" % (fileprefix, ietypeunderscore.lower(), ienamefirstwordlower, lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" if ((ie = %s_new_ie(ProtocolIE_ID_%s,\n" % (fileprefix, re.sub('-', '_', ie[0]))) + f.write(" Criticality_%s,\n" % (ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + if ie[2] in ieofielist.keys(): + f.write(" &%s)) == NULL) {\n" % (ienamefirstwordlower)) + else: + f.write(" &%s->%s)) == NULL) {\n" % (lowerFirstCamelWord(re.sub('-', '_', key)), ienamefirstwordlower)) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->%slist, ie);\n\n" % (firstwordlower, iesaccess)) + if ie[2] in ieofielist.keys(): + f.write(" /* Free any dynamic allocation that is no more used */\n") + f.write(" ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_%s, &%s);\n\n" % (ietypeunderscore, ienamefirstwordlower)) + + f.write(" return 0;\n") + f.write("}\n\n") + +for (key, value) in iesDefs.items(): + if key not in ieofielist.values(): + continue + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + asn1cStruct = re.sub('-', '_', re.sub('IEs', '', re.sub('-IEs', '', key))) + asn1cStruct = re.sub('Item', 'List', asn1cStruct) + firstwordlower = re.sub('Item', 'List', re.sub('enb', 'eNB', lowerFirstCamelWord(asn1cStruct))) + + for (i, j) in ieofielist.items(): + if j == key: + break + f.write("int %s_encode_%s(\n" % (fileprefix, re.sub('-', '_', i).lower())) + f.write(" %s_t *%s,\n" % (asn1cStruct, firstwordlower)) + f.write(" %sIEs_t *%sIEs) {\n\n" % (re.sub('-', '_', i), lowerFirstCamelWord(re.sub('-', '_', i)))) + f.write(" int i;\n") + + f.write(" IE_t *ie;\n\n") + + f.write(" assert(%s != NULL);\n" % (firstwordlower)); + f.write(" assert(%sIEs != NULL);\n\n" % (lowerFirstCamelWord(re.sub('-', '_', i)))); + + f.write(" for (i = 0; i < %sIEs->%s.count; i++) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" if ((ie = %s_new_ie(ProtocolIE_ID_%s,\n" % (fileprefix, re.sub('-', '_', ie[0]))) + f.write(" Criticality_%s,\n" % (ie[1])) + f.write(" &asn_DEF_%s,\n" % (ietypeunderscore)) + f.write(" %sIEs->%s.array[i])) == NULL) {\n" % (firstwordlower, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" return -1;\n") + f.write(" }\n") + f.write(" ASN_SEQUENCE_ADD(&%s->list, ie);\n" % (firstwordlower)) + f.write(" }\n") + f.write(" return 0;\n") + f.write("}\n\n") + +#Generate xer print functions +f = open(outdir + fileprefix + '_xer_print.c', 'w') +outputHeaderToFile(f, filename) +f.write("#include <stdlib.h>\n") +f.write("#include <stdio.h>\n\n") +f.write("#include <asn_application.h>\n#include <asn_internal.h>\n\n") +f.write("#include \"%s_common.h\"\n#include \"%s_ies_defs.h\"\n\n" % (fileprefix, fileprefix)) + +f.write("""static int +xer__print2fp(const void *buffer, size_t size, void *app_key) { + FILE *stream = (FILE *)app_key; + + if(fwrite(buffer, 1, size, stream) != size) + return -1; + + return 0; +} + +static asn_enc_rval_t +xer_encode_local(asn_TYPE_descriptor_t *td, void *sptr, + asn_app_consume_bytes_f *cb, void *app_key, int indent) { + asn_enc_rval_t er, tmper; + const char *mname; + size_t mlen; + int xcan = 2; + + if(!td || !sptr) goto cb_failed; + + mname = td->xml_tag; + mlen = strlen(mname); + + _i_ASN_TEXT_INDENT(0, indent); + _ASN_CALLBACK3("<", 1, mname, mlen, ">", 1); + + tmper = td->xer_encoder(td, sptr, indent + 1, XER_F_BASIC, cb, app_key); + if(tmper.encoded == -1) return tmper; + + _ASN_CALLBACK3("</", 2, mname, mlen, ">\\n", xcan); + + er.encoded = 4 + xcan + (2 * mlen) + tmper.encoded; + + _ASN_ENCODED_OK(er); +cb_failed: + _ASN_ENCODE_FAILED; +} +""") + +for (key, value) in iesDefs.items(): + keyName = re.sub('-', '_', key) + keyupperunderscore = keyName.upper() + iesStructName = lowerFirstCamelWord(re.sub('-', '_', key)) + + ie = value["ies"][0] + ietypeunderscore = re.sub('-', '_', ie[2]) + + if key in ieofielist.values(): + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('item', 'list', re.sub('-', '_', key).lower())))) + else: + f.write("asn_enc_rval_t %s_xer_print_%s(\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', key).lower()))) + f.write(" FILE *file,\n") + if key in ieofielist.values(): + iesStructName = lowerFirstCamelWord(re.sub('Item', 'List', re.sub('-', '_', key))) + f.write(" %sIEs_t *%s) {\n\n" % (re.sub('IEs', '', re.sub('Item', 'List', re.sub('-', '_', key))), iesStructName)) + f.write(" int i;\n") + f.write(" asn_enc_rval_t er;\n") + else: + f.write(" %s_message *message_p)\n{\n" % (fileprefix)) + f.write(" %s_t *%s;\n" % (re.sub('-', '_', key), iesStructName)) + f.write(" asn_enc_rval_t er;\n") + f.write(" void *app_key = (void *)file;\n") + f.write(" asn_app_consume_bytes_f *cb = xer__print2fp;\n\n") + + f.write(" %s = &message_p->msg.%s;\n\n" % (iesStructName, iesStructName)) + + if key in ieofielist.values(): + # Increase indentation level + f.write(" for (i = 0; i < %s->%s.count; i++) {\n" % (iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" xer_fprint(file, &asn_DEF_%s, %s->%s.array[i]);\n" % (ietypeunderscore, iesStructName, re.sub('IEs', '', lowerFirstCamelWord(re.sub('-', '_', key))))) + f.write(" }\n") + else: + f.write(" fprintf(file, \"<%s-PDU>\\n\");\n" % (fileprefix.upper())) + f.write(" xer_encode_local(&asn_DEF_Criticality, &message_p->criticality, cb, app_key, 1);\n") + f.write(" xer_encode_local(&asn_DEF_ProcedureCode, &message_p->procedureCode, cb, app_key, 1);\n") + f.write(" fprintf(file, \" <%s>\\n\");\n" % (key)) + + for ie in iesDefs[key]["ies"]: + iename = re.sub('-', '_', re.sub('id-', '', ie[0])) + ienameunderscore = re.sub('-', '_', iename) + ienamefirstwordlower = lowerFirstCamelWord(iename) + ietypeunderscore = re.sub('-', '_', ie[2]) + ieupperunderscore = re.sub('-', '_', re.sub('id-', '', ie[0])).upper() + + if ie[3] != "mandatory": + if ie[3] == "optional": + f.write(" /* Optional field */\n") + elif ie[3] == "conditional": + f.write(" /* Conditional field */\n") + f.write(" if (%s->presenceMask & %s_%s_PRESENT)\n " % (iesStructName, keyupperunderscore, ieupperunderscore)) + + # Is it an encapsulated IE ? + if ie[2] in ieofielist.keys(): + f.write(" %s_xer_print_%s(file, &%s->%s);\n" % (fileprefix, re.sub('ies', '', re.sub('-', '_', ie[2]).lower()), iesStructName, ienamefirstwordlower)) + else: + f.write(" xer_encode_local(&asn_DEF_%s, &%s->%s, cb, app_key, 2);\n" % (ietypeunderscore, iesStructName, ienamefirstwordlower)) + #f.write(" _i_ASN_TEXT_INDENT(1, 1);\n") + f.write(" fprintf(file, \" </%s>\\n\");\n" % (key)) + f.write(" fprintf(file, \"</%s-PDU>\\n\");\n" % (fileprefix.upper())) + + f.write(" _ASN_ENCODED_OK(er);\n") + #if key not in ieofielist.values(): + #f.write("cb_failed:\n") + #f.write(" return er;\n") + f.write("}\n\n") diff --git a/openair-cn/S1AP/MESSAGES/Makefile.am b/openair-cn/S1AP/MESSAGES/Makefile.am new file mode 100644 index 0000000000..ba7eecd1ae --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/Makefile.am @@ -0,0 +1,777 @@ +SUBDIRS= ASN1/ . +ASN_MODULEdir=. +libs1apmessagesdir=. + +ASN_MODULE_SOURCES= \ + Criticality.c \ + Presence.c \ + PrivateIE-ID.c \ + ProcedureCode.c \ + ProtocolExtensionID.c \ + ProtocolIE-ID.c \ + TriggeringMessage.c \ + IE-Extensions.c \ + AllocationAndRetentionPriority.c \ + Bearers-SubjectToStatusTransfer-List.c \ + Bearers-SubjectToStatusTransfer-Item.c \ + BitRate.c \ + BPLMNs.c \ + BroadcastCompletedAreaList.c \ + Cause.c \ + CauseMisc.c \ + CauseProtocol.c \ + CauseRadioNetwork.c \ + CauseTransport.c \ + CauseNas.c \ + CellIdentity.c \ + CellID-Broadcast.c \ + CellID-Broadcast-Item.c \ + Cdma2000PDU.c \ + Cdma2000RATType.c \ + Cdma2000SectorID.c \ + Cdma2000HOStatus.c \ + Cdma2000HORequiredIndication.c \ + Cdma2000OneXSRVCCInfo.c \ + Cdma2000OneXMEID.c \ + Cdma2000OneXMSI.c \ + Cdma2000OneXPilot.c \ + Cdma2000OneXRAND.c \ + Cell-Size.c \ + CellType.c \ + CGI.c \ + CI.c \ + CNDomain.c \ + CSFallbackIndicator.c \ + CSG-Id.c \ + CSG-IdList.c \ + CSG-IdList-Item.c \ + COUNTvalue.c \ + CriticalityDiagnostics.c \ + CriticalityDiagnostics-IE-List.c \ + CriticalityDiagnostics-IE-Item.c \ + DataCodingScheme.c \ + DL-Forwarding.c \ + Direct-Forwarding-Path-Availability.c \ + E-RABToBeModifiedListBearerModReq.c \ + E-RABToBeModifiedItemBearerModReq.c \ + E-RABReleaseListBearerRelComp.c \ + E-RABReleaseItemBearerRelComp.c \ + E-RABDataForwardingList.c \ + E-RABDataForwardingItem.c \ + E-RABToBeSetupListCtxtSUReq.c \ + E-RABToBeSetupItemCtxtSUReq.c \ + E-RABSetupListBearerSURes.c \ + E-RABSetupItemBearerSURes.c \ + E-RABFailedToSetupListHOReqAck.c \ + E-RABFailedToSetupItemHOReqAck.c \ + E-RABToBeSetupListBearerSUReq.c \ + E-RABToBeSetupItemBearerSUReq.c \ + E-RABAdmittedList.c \ + E-RABAdmittedItem.c \ + E-RABToBeSwitchedDLList.c \ + E-RABToBeSwitchedDLItem.c \ + E-RABToBeSwitchedULList.c \ + E-RABToBeSwitchedULItem.c \ + E-RABModifyListBearerModRes.c \ + E-RABModifyItemBearerModRes.c \ + E-RABSetupListCtxtSURes.c \ + E-RABSetupItemCtxtSURes.c \ + E-RABToBeSetupListHOReq.c \ + E-RABToBeSetupItemHOReq.c \ + ECGIList.c \ + EmergencyAreaIDList.c \ + EmergencyAreaID.c \ + EmergencyAreaID-Broadcast.c \ + EmergencyAreaID-Broadcast-Item.c \ + CompletedCellinEAI.c \ + CompletedCellinEAI-Item.c \ + ENB-ID.c \ + GERAN-Cell-ID.c \ + Global-ENB-ID.c \ + ENB-StatusTransfer-TransparentContainer.c \ + ENB-UE-S1AP-ID.c \ + ENBname.c \ + ENBX2TLAs.c \ + EncryptionAlgorithms.c \ + EPLMNs.c \ + EventType.c \ + E-RAB-ID.c \ + E-RABInformationList.c \ + E-RABInformationListItem.c \ + E-RABList.c \ + E-RABItem.c \ + E-RABLevelQoSParameters.c \ + EUTRAN-CGI.c \ + ExtendedRNC-ID.c \ + ForbiddenInterRATs.c \ + ForbiddenTAs.c \ + ForbiddenTAs-Item.c \ + ForbiddenTACs.c \ + ForbiddenLAs.c \ + ForbiddenLAs-Item.c \ + ForbiddenLACs.c \ + GBR-QosInformation.c \ + GTP-TEID.c \ + GUMMEI.c \ + HandoverRestrictionList.c \ + HandoverType.c \ + HFN.c \ + HandoverNotify.c \ + Inter-SystemInformationTransferType.c \ + IMSI.c \ + IntegrityProtectionAlgorithms.c \ + InterfacesToTrace.c \ + LAC.c \ + LAI.c \ + LastVisitedCell-Item.c \ + LastVisitedEUTRANCellInformation.c \ + LastVisitedUTRANCellInformation.c \ + LastVisitedGERANCellInformation.c \ + L3-Information.c \ + MessageIdentifier.c \ + MMEname.c \ + MME-Group-ID.c \ + MME-Code.c \ + MME-UE-S1AP-ID.c \ + M-TMSI.c \ + MSClassmark2.c \ + MSClassmark3.c \ + NAS-PDU.c \ + NASSecurityParametersfromE-UTRAN.c \ + NASSecurityParameterstoE-UTRAN.c \ + NumberofBroadcastRequest.c \ + NumberOfBroadcasts.c \ + OldBSS-ToNewBSS-Information.c \ + OverloadAction.c \ + OverloadResponse.c \ + PagingDRX.c \ + PDCP-SN.c \ + PLMNidentity.c \ + Pre-emptionCapability.c \ + Pre-emptionVulnerability.c \ + PriorityLevel.c \ + QCI.c \ + ReceiveStatusofULPDCPSDUs.c \ + RelativeMMECapacity.c \ + RAC.c \ + RequestType.c \ + ResetType.c \ + ResetAll.c \ + RIMTransfer.c \ + RIMInformation.c \ + RIMRoutingAddress.c \ + ReportArea.c \ + RepetitionPeriod.c \ + RNC-ID.c \ + RRC-Container.c \ + RRC-Establishment-Cause.c \ + SecurityKey.c \ + SecurityContext.c \ + SerialNumber.c \ + SONInformation.c \ + SONInformationRequest.c \ + SONInformationReply.c \ + SONConfigurationTransfer.c \ + Source-ToTarget-TransparentContainer.c \ + SourceBSS-ToTargetBSS-TransparentContainer.c \ + SourceeNB-ID.c \ + SRVCCOperationPossible.c \ + SRVCCHOIndication.c \ + SourceeNB-ToTargeteNB-TransparentContainer.c \ + SourceRNC-ToTargetRNC-TransparentContainer.c \ + ServedGUMMEIs.c \ + ServedGUMMEIsItem.c \ + ServedGroupIDs.c \ + ServedMMECs.c \ + ServedPLMNs.c \ + SubscriberProfileIDforRFP.c \ + SupportedTAs.c \ + SupportedTAs-Item.c \ + S-TMSI.c \ + TAC.c \ + TAIListforWarning.c \ + TAIList.c \ + TAIItem.c \ + TAI.c \ + TAI-Broadcast.c \ + TAI-Broadcast-Item.c \ + CompletedCellinTAI.c \ + CompletedCellinTAI-Item.c \ + TBCD-STRING.c \ + TargetID.c \ + TargeteNB-ID.c \ + TargetRNC-ID.c \ + TargeteNB-ToSourceeNB-TransparentContainer.c \ + Target-ToSource-TransparentContainer.c \ + TargetRNC-ToSourceRNC-TransparentContainer.c \ + TargetBSS-ToSourceBSS-TransparentContainer.c \ + TimeToWait.c \ + Time-UE-StayedInCell.c \ + TransportLayerAddress.c \ + TraceActivation.c \ + TraceDepth.c \ + E-UTRAN-Trace-ID.c \ + TypeOfError.c \ + UEAggregateMaximumBitrate.c \ + UE-S1AP-IDs.c \ + UE-S1AP-ID-pair.c \ + UE-associatedLogicalS1-ConnectionListRes.c \ + UE-associatedLogicalS1-ConnectionListResAck.c \ + UE-associatedLogicalS1-ConnectionItem.c \ + UEIdentityIndexValue.c \ + UE-HistoryInformation.c \ + UEPagingID.c \ + UERadioCapability.c \ + UESecurityCapabilities.c \ + WarningAreaList.c \ + WarningType.c \ + WarningSecurityInfo.c \ + WarningMessageContents.c \ + X2TNLConfigurationInfo.c \ + S1AP-PDU.c \ + InitiatingMessage.c \ + SuccessfulOutcome.c \ + UnsuccessfulOutcome.c \ + HandoverRequired.c \ + HandoverCommand.c \ + HandoverPreparationFailure.c \ + HandoverRequest.c \ + HandoverRequestAcknowledge.c \ + HandoverFailure.c \ + HandoverNotify.c \ + PathSwitchRequest.c \ + PathSwitchRequestAcknowledge.c \ + PathSwitchRequestFailure.c \ + E-RABSetupRequest.c \ + E-RABSetupResponse.c \ + E-RABModifyRequest.c \ + E-RABModifyResponse.c \ + E-RABReleaseIndication.c \ + E-RABReleaseCommand.c \ + E-RABReleaseResponse.c \ + InitialContextSetupRequest.c \ + InitialContextSetupResponse.c \ + InitialContextSetupFailure.c \ + UEContextReleaseRequest.c \ + Paging.c \ + DownlinkNASTransport.c \ + InitialUEMessage.c \ + UplinkNASTransport.c \ + NASNonDeliveryIndication.c \ + HandoverCancel.c \ + HandoverCancelAcknowledge.c \ + Reset.c \ + ResetAcknowledge.c \ + S1SetupResponse.c \ + S1SetupRequest.c \ + S1SetupFailure.c \ + ErrorIndication.c \ + ENBConfigurationUpdate.c \ + ENBConfigurationUpdateAcknowledge.c \ + ENBConfigurationUpdateFailure.c \ + MMEConfigurationUpdate.c \ + MMEConfigurationUpdateAcknowledge.c \ + MMEConfigurationUpdateFailure.c \ + DownlinkS1cdma2000tunneling.c \ + UplinkS1cdma2000tunneling.c \ + UEContextModificationRequest.c \ + UEContextModificationResponse.c \ + UEContextModificationFailure.c \ + UECapabilityInfoIndication.c \ + UEContextReleaseCommand.c \ + UEContextReleaseComplete.c \ + ENBStatusTransfer.c \ + MMEStatusTransfer.c \ + DeactivateTrace.c \ + TraceStart.c \ + TraceFailureIndication.c \ + CellTrafficTrace.c \ + LocationReportingControl.c \ + LocationReportingFailureIndication.c \ + LocationReport.c \ + OverloadStart.c \ + OverloadStop.c \ + WriteReplaceWarningRequest.c \ + WriteReplaceWarningResponse.c \ + ENBDirectInformationTransfer.c \ + MMEDirectInformationTransfer.c \ + ENBConfigurationTransfer.c \ + MMEConfigurationTransfer.c \ + PrivateMessage.c \ + IE.c \ + IE-Extensions.c + +ASN_MODULE_HEADERS= \ + Criticality.h \ + Presence.h \ + PrivateIE-ID.h \ + ProcedureCode.h \ + ProtocolExtensionID.h \ + ProtocolIE-ID.h \ + TriggeringMessage.h \ + AllocationAndRetentionPriority.h \ + Bearers-SubjectToStatusTransfer-List.h \ + Bearers-SubjectToStatusTransfer-Item.h \ + BitRate.h \ + BPLMNs.h \ + BroadcastCompletedAreaList.h \ + Cause.h \ + CauseMisc.h \ + CauseProtocol.h \ + CauseRadioNetwork.h \ + CauseTransport.h \ + CauseNas.h \ + CellIdentity.h \ + CellID-Broadcast.h \ + CellID-Broadcast-Item.h \ + Cdma2000PDU.h \ + Cdma2000RATType.h \ + Cdma2000SectorID.h \ + Cdma2000HOStatus.h \ + Cdma2000HORequiredIndication.h \ + Cdma2000OneXSRVCCInfo.h \ + Cdma2000OneXMEID.h \ + Cdma2000OneXMSI.h \ + Cdma2000OneXPilot.h \ + Cdma2000OneXRAND.h \ + Cell-Size.h \ + CellType.h \ + CGI.h \ + CI.h \ + CNDomain.h \ + CSFallbackIndicator.h \ + CSG-Id.h \ + CSG-IdList.h \ + CSG-IdList-Item.h \ + COUNTvalue.h \ + CriticalityDiagnostics.h \ + CriticalityDiagnostics-IE-List.h \ + CriticalityDiagnostics-IE-Item.h \ + DataCodingScheme.h \ + DL-Forwarding.h \ + Direct-Forwarding-Path-Availability.h \ + E-RABToBeModifiedListBearerModReq.h \ + E-RABToBeModifiedItemBearerModReq.h \ + E-RABReleaseListBearerRelComp.h \ + E-RABReleaseItemBearerRelComp.h \ + E-RABDataForwardingList.h \ + E-RABDataForwardingItem.h \ + E-RABToBeSetupListCtxtSUReq.h \ + E-RABToBeSetupItemCtxtSUReq.h \ + E-RABSetupListBearerSURes.h \ + E-RABSetupItemBearerSURes.h \ + E-RABFailedToSetupListHOReqAck.h \ + E-RABFailedToSetupItemHOReqAck.h \ + E-RABToBeSetupListBearerSUReq.h \ + E-RABToBeSetupItemBearerSUReq.h \ + E-RABAdmittedList.h \ + E-RABAdmittedItem.h \ + E-RABToBeSwitchedDLList.h \ + E-RABToBeSwitchedDLItem.h \ + E-RABToBeSwitchedULList.h \ + E-RABToBeSwitchedULItem.h \ + E-RABModifyListBearerModRes.h \ + E-RABModifyItemBearerModRes.h \ + E-RABSetupListCtxtSURes.h \ + E-RABSetupItemCtxtSURes.h \ + E-RABToBeSetupListHOReq.h \ + E-RABToBeSetupItemHOReq.h \ + ECGIList.h \ + EmergencyAreaIDList.h \ + EmergencyAreaID.h \ + EmergencyAreaID-Broadcast.h \ + EmergencyAreaID-Broadcast-Item.h \ + CompletedCellinEAI.h \ + CompletedCellinEAI-Item.h \ + ENB-ID.h \ + GERAN-Cell-ID.h \ + Global-ENB-ID.h \ + ENB-StatusTransfer-TransparentContainer.h \ + ENB-UE-S1AP-ID.h \ + ENBname.h \ + ENBX2TLAs.h \ + EncryptionAlgorithms.h \ + EPLMNs.h \ + EventType.h \ + E-RAB-ID.h \ + E-RABInformationList.h \ + E-RABInformationListItem.h \ + E-RABList.h \ + E-RABItem.h \ + E-RABLevelQoSParameters.h \ + EUTRAN-CGI.h \ + ExtendedRNC-ID.h \ + ForbiddenInterRATs.h \ + ForbiddenTAs.h \ + ForbiddenTAs-Item.h \ + ForbiddenTACs.h \ + ForbiddenLAs.h \ + ForbiddenLAs-Item.h \ + ForbiddenLACs.h \ + GBR-QosInformation.h \ + GTP-TEID.h \ + GUMMEI.h \ + HandoverRestrictionList.h \ + HandoverType.h \ + HFN.h \ + HandoverNotify.h \ + Inter-SystemInformationTransferType.h \ + IMSI.h \ + IntegrityProtectionAlgorithms.h \ + InterfacesToTrace.h \ + LAC.h \ + LAI.h \ + LastVisitedCell-Item.h \ + LastVisitedEUTRANCellInformation.h \ + LastVisitedUTRANCellInformation.h \ + LastVisitedGERANCellInformation.h \ + L3-Information.h \ + MessageIdentifier.h \ + MMEname.h \ + MME-Group-ID.h \ + MME-Code.h \ + MME-UE-S1AP-ID.h \ + M-TMSI.h \ + MSClassmark2.h \ + MSClassmark3.h \ + NAS-PDU.h \ + NASSecurityParametersfromE-UTRAN.h \ + NASSecurityParameterstoE-UTRAN.h \ + NumberofBroadcastRequest.h \ + NumberOfBroadcasts.h \ + OldBSS-ToNewBSS-Information.h \ + OverloadAction.h \ + OverloadResponse.h \ + PagingDRX.h \ + PDCP-SN.h \ + PLMNidentity.h \ + Pre-emptionCapability.h \ + Pre-emptionVulnerability.h \ + PriorityLevel.h \ + QCI.h \ + ReceiveStatusofULPDCPSDUs.h \ + RelativeMMECapacity.h \ + RAC.h \ + RequestType.h \ + ResetType.h \ + ResetAll.h \ + RIMTransfer.h \ + RIMInformation.h \ + RIMRoutingAddress.h \ + ReportArea.h \ + RepetitionPeriod.h \ + RNC-ID.h \ + RRC-Container.h \ + RRC-Establishment-Cause.h \ + SecurityKey.h \ + SecurityContext.h \ + SerialNumber.h \ + SONInformation.h \ + SONInformationRequest.h \ + SONInformationReply.h \ + SONConfigurationTransfer.h \ + Source-ToTarget-TransparentContainer.h \ + SourceBSS-ToTargetBSS-TransparentContainer.h \ + SourceeNB-ID.h \ + SRVCCOperationPossible.h \ + SRVCCHOIndication.h \ + SourceeNB-ToTargeteNB-TransparentContainer.h \ + SourceRNC-ToTargetRNC-TransparentContainer.h \ + ServedGUMMEIs.h \ + ServedGUMMEIsItem.h \ + ServedGroupIDs.h \ + ServedMMECs.h \ + ServedPLMNs.h \ + SubscriberProfileIDforRFP.h \ + SupportedTAs.h \ + SupportedTAs-Item.h \ + S-TMSI.h \ + TAC.h \ + TAIListforWarning.h \ + TAIList.h \ + TAIItem.h \ + TAI.h \ + TAI-Broadcast.h \ + TAI-Broadcast-Item.h \ + CompletedCellinTAI.h \ + CompletedCellinTAI-Item.h \ + TBCD-STRING.h \ + TargetID.h \ + TargeteNB-ID.h \ + TargetRNC-ID.h \ + TargeteNB-ToSourceeNB-TransparentContainer.h \ + Target-ToSource-TransparentContainer.h \ + TargetRNC-ToSourceRNC-TransparentContainer.h \ + TargetBSS-ToSourceBSS-TransparentContainer.h \ + TimeToWait.h \ + Time-UE-StayedInCell.h \ + TransportLayerAddress.h \ + TraceActivation.h \ + TraceDepth.h \ + E-UTRAN-Trace-ID.h \ + TypeOfError.h \ + UEAggregateMaximumBitrate.h \ + UE-S1AP-IDs.h \ + UE-S1AP-ID-pair.h \ + UE-associatedLogicalS1-ConnectionListRes.h \ + UE-associatedLogicalS1-ConnectionListResAck.h \ + UE-associatedLogicalS1-ConnectionItem.h \ + UEIdentityIndexValue.h \ + UE-HistoryInformation.h \ + UEPagingID.h \ + UERadioCapability.h \ + UESecurityCapabilities.h \ + WarningAreaList.h \ + WarningType.h \ + WarningSecurityInfo.h \ + WarningMessageContents.h \ + X2TNLConfigurationInfo.h \ + S1AP-PDU.h \ + InitiatingMessage.h \ + SuccessfulOutcome.h \ + UnsuccessfulOutcome.h \ + HandoverRequired.h \ + HandoverCommand.h \ + HandoverPreparationFailure.h \ + HandoverRequest.h \ + HandoverRequestAcknowledge.h \ + HandoverFailure.h \ + PathSwitchRequest.h \ + PathSwitchRequestAcknowledge.h \ + PathSwitchRequestFailure.h \ + E-RABSetupRequest.h \ + E-RABSetupResponse.h \ + E-RABModifyRequest.h \ + E-RABModifyResponse.h \ + E-RABReleaseIndication.h \ + E-RABReleaseCommand.h \ + E-RABReleaseResponse.h \ + InitialContextSetupRequest.h \ + InitialContextSetupResponse.h \ + InitialContextSetupFailure.h \ + UEContextReleaseRequest.h \ + Paging.h \ + DownlinkNASTransport.h \ + InitialUEMessage.h \ + UplinkNASTransport.h \ + NASNonDeliveryIndication.h \ + HandoverCancel.h \ + HandoverCancelAcknowledge.h \ + Reset.h \ + ResetAcknowledge.h \ + S1SetupResponse.h \ + S1SetupRequest.h \ + S1SetupFailure.h \ + ErrorIndication.h \ + ENBConfigurationUpdate.h \ + ENBConfigurationUpdateAcknowledge.h \ + ENBConfigurationUpdateFailure.h \ + MMEConfigurationUpdate.h \ + MMEConfigurationUpdateAcknowledge.h \ + MMEConfigurationUpdateFailure.h \ + DownlinkS1cdma2000tunneling.h \ + UplinkS1cdma2000tunneling.h \ + UEContextModificationRequest.h \ + UEContextModificationResponse.h \ + UEContextModificationFailure.h \ + UECapabilityInfoIndication.h \ + UEContextReleaseCommand.h \ + UEContextReleaseComplete.h \ + ENBStatusTransfer.h \ + MMEStatusTransfer.h \ + DeactivateTrace.h \ + TraceStart.h \ + TraceFailureIndication.h \ + CellTrafficTrace.h \ + LocationReportingControl.h \ + LocationReportingFailureIndication.h \ + LocationReport.h \ + OverloadStart.h \ + OverloadStop.h \ + WriteReplaceWarningRequest.h \ + WriteReplaceWarningResponse.h \ + ENBDirectInformationTransfer.h \ + MMEDirectInformationTransfer.h \ + ENBConfigurationTransfer.h \ + MMEConfigurationTransfer.h \ + PrivateMessage.h \ + IE.h \ + IE-Extensions.h + +ASN_MODULE_HEADERS+=ANY.h +ASN_MODULE_SOURCES+=ANY.c +ASN_MODULE_HEADERS+=BOOLEAN.h +ASN_MODULE_SOURCES+=BOOLEAN.c +ASN_MODULE_HEADERS+=INTEGER.h +ASN_MODULE_HEADERS+=NativeEnumerated.h +ASN_MODULE_SOURCES+=INTEGER.c +ASN_MODULE_HEADERS+=NULL.h +ASN_MODULE_SOURCES+=NULL.c +ASN_MODULE_SOURCES+=NativeEnumerated.c +ASN_MODULE_HEADERS+=NativeInteger.h +ASN_MODULE_SOURCES+=NativeInteger.c +ASN_MODULE_HEADERS+=OBJECT_IDENTIFIER.h +ASN_MODULE_SOURCES+=OBJECT_IDENTIFIER.c +ASN_MODULE_HEADERS+=PrintableString.h +ASN_MODULE_SOURCES+=PrintableString.c +ASN_MODULE_HEADERS+=asn_SEQUENCE_OF.h +ASN_MODULE_SOURCES+=asn_SEQUENCE_OF.c +ASN_MODULE_HEADERS+=asn_SET_OF.h +ASN_MODULE_SOURCES+=asn_SET_OF.c +ASN_MODULE_HEADERS+=constr_CHOICE.h +ASN_MODULE_SOURCES+=constr_CHOICE.c +ASN_MODULE_HEADERS+=constr_SEQUENCE.h +ASN_MODULE_SOURCES+=constr_SEQUENCE.c +ASN_MODULE_HEADERS+=constr_SEQUENCE_OF.h +ASN_MODULE_SOURCES+=constr_SEQUENCE_OF.c +ASN_MODULE_HEADERS+=constr_SET_OF.h +ASN_MODULE_SOURCES+=constr_SET_OF.c +ASN_MODULE_HEADERS+=asn_application.h +ASN_MODULE_HEADERS+=asn_system.h +ASN_MODULE_HEADERS+=asn_codecs.h +ASN_MODULE_HEADERS+=asn_internal.h +ASN_MODULE_HEADERS+=OCTET_STRING.h +ASN_MODULE_SOURCES+=OCTET_STRING.c +ASN_MODULE_HEADERS+=BIT_STRING.h +ASN_MODULE_SOURCES+=BIT_STRING.c +ASN_MODULE_SOURCES+=asn_codecs_prim.c +ASN_MODULE_HEADERS+=asn_codecs_prim.h +ASN_MODULE_HEADERS+=ber_tlv_length.h +ASN_MODULE_SOURCES+=ber_tlv_length.c +ASN_MODULE_HEADERS+=ber_tlv_tag.h +ASN_MODULE_SOURCES+=ber_tlv_tag.c +ASN_MODULE_HEADERS+=ber_decoder.h +ASN_MODULE_SOURCES+=ber_decoder.c +ASN_MODULE_HEADERS+=der_encoder.h +ASN_MODULE_SOURCES+=der_encoder.c +ASN_MODULE_HEADERS+=constr_TYPE.h +ASN_MODULE_SOURCES+=constr_TYPE.c +ASN_MODULE_HEADERS+=constraints.h +ASN_MODULE_SOURCES+=constraints.c +ASN_MODULE_HEADERS+=xer_support.h +ASN_MODULE_SOURCES+=xer_support.c +ASN_MODULE_HEADERS+=xer_decoder.h +ASN_MODULE_SOURCES+=xer_decoder.c +ASN_MODULE_HEADERS+=xer_encoder.h +ASN_MODULE_SOURCES+=xer_encoder.c +ASN_MODULE_HEADERS+=per_support.h +ASN_MODULE_SOURCES+=per_support.c +ASN_MODULE_HEADERS+=per_decoder.h +ASN_MODULE_SOURCES+=per_decoder.c +ASN_MODULE_HEADERS+=per_encoder.h +ASN_MODULE_SOURCES+=per_encoder.c +ASN_MODULE_HEADERS+=per_opentype.h +ASN_MODULE_SOURCES+=per_opentype.c + +if UPDATE_RELEASE_9 +ASN_MODULE_SOURCES += \ + KillResponse.c \ + KillRequest.c \ + Data-Forwarding-Not-Possible.c \ + DownlinkUEAssociatedLPPaTransport.c \ + UplinkUEAssociatedLPPaTransport.c \ + DownlinkNonUEAssociatedLPPaTransport.c \ + UplinkNonUEAssociatedLPPaTransport.c \ + TAI-Cancelled.c \ + TAI-Cancelled-Item.c \ + StratumLevel.c \ + SynchronizationStatus.c \ + TimeSynchronizationInfo.c \ + Routing-ID.c \ + PS-ServiceNotAvailable.c \ + LPPa-PDU.c \ + ExtendedRepetitionPeriod.c \ + EUTRANRoundTripDelayEstimationInfo.c \ + EmergencyAreaID-Cancelled.c \ + EmergencyAreaID-Cancelled-Item.c \ + CSGMembershipStatus.c \ + ConcurrentWarningMessageIndicator.c \ + CellID-Cancelled.c \ + CellID-Cancelled-Item.c \ + CellAccessMode.c \ + CancelledCellinEAI.c \ + CancelledCellinEAI-Item.c \ + CancelledCellinTAI.c \ + CancelledCellinTAI-Item.c \ + BroadcastCancelledAreaList.c + +ASN_MODULE_HEADERS += \ + BroadcastCancelledAreaList.h \ + CancelledCellinEAI.h \ + CancelledCellinEAI-Item.h \ + CancelledCellinTAI.h \ + CancelledCellinTAI-Item.h \ + CellAccessMode.h \ + CellID-Cancelled.h \ + CellID-Cancelled-Item.h \ + ConcurrentWarningMessageIndicator.h \ + CSGMembershipStatus.h \ + Data-Forwarding-Not-Possible.h \ + EmergencyAreaID-Cancelled.h \ + EmergencyAreaID-Cancelled-Item.h \ + E-RABList.h \ + EUTRANRoundTripDelayEstimationInfo.h \ + ExtendedRepetitionPeriod.h \ + LPPa-PDU.h \ + PS-ServiceNotAvailable.h \ + Routing-ID.h \ + StratumLevel.h \ + SynchronizationStatus.h \ + TimeSynchronizationInfo.h \ + TAI-Cancelled.h \ + TAI-Cancelled-Item.h \ + KillResponse.h \ + KillRequest.h \ + DownlinkUEAssociatedLPPaTransport.h \ + UplinkUEAssociatedLPPaTransport.h \ + DownlinkNonUEAssociatedLPPaTransport.h \ + UplinkNonUEAssociatedLPPaTransport.h +endif + +if UPDATE_RELEASE_10 +ASN_MODULE_SOURCES += \ + PagingPriority.c \ + RelayNode-Indicator.c \ + GWContextReleaseIndication.c \ + MMERelaySupportIndicator.c \ + ManagementBasedMDTAllowed.c \ + PrivacyIndicator.c \ + TrafficLoadReductionIndication.c \ + GUMMEIList.c + +ASN_MODULE_HEADERS += \ + PagingPriority.h \ + RelayNode-Indicator.h \ + GWContextReleaseIndication.h \ + MMERelaySupportIndicator.h \ + ManagementBasedMDTAllowed.h \ + PrivacyIndicator.h \ + TrafficLoadReductionIndication.h \ + GUMMEIList.h +endif + +noinst_LTLIBRARIES = libs1apmessages.la +libs1apmessages_la_LDFLAGS = -all-static + +BUILT_SOURCES = asn1regen.stamp + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -DEMIT_ASN_DEBUG_EXTERN + +libs1apmessages_la_SOURCES=$(ASN_MODULE_SOURCES) $(ASN_MODULE_HEADERS) + +asn1regen.stamp: ASN1/$(ASN1DIR)/S1AP-CommonDataTypes.asn ASN1/$(ASN1DIR)/S1AP-Constants.asn ASN1/$(ASN1DIR)/S1AP-IEs.asn ASN1/$(ASN1DIR)/S1AP-PDU.asn + asn1c -gen-PER -fhave_native64 $^ + echo Timestamp > $@ + +clean-messages: + rm -f *.lo + +clean-local: + rm -f asn1regen.stamp + rm -f Makefile.am.sample + rm -f converter-sample.c + rm -f $(ASN_MODULE_SOURCES) + rm -f $(ASN_MODULE_HEADERS) + rm -f $(ASN_MODULE_HEADERS_IES) diff --git a/openair-cn/S1AP/MESSAGES/Makefile.inc b/openair-cn/S1AP/MESSAGES/Makefile.inc new file mode 100644 index 0000000000..626660d634 --- /dev/null +++ b/openair-cn/S1AP/MESSAGES/Makefile.inc @@ -0,0 +1,760 @@ +S1AP_ASN_MODULE_SOURCES= \ + Criticality.o \ + Presence.o \ + PrivateIE-ID.o \ + ProcedureCode.o \ + ProtocolExtensionID.o \ + ProtocolIE-ID.o \ + TriggeringMessage.o \ + IE-Extensions.o \ + AllocationAndRetentionPriority.o \ + Bearers-SubjectToStatusTransfer-List.o \ + Bearers-SubjectToStatusTransfer-Item.o \ + BitRate.o \ + BPLMNs.o \ + BroadcastCompletedAreaList.o \ + Cause.o \ + CauseMisc.o \ + CauseProtocol.o \ + CauseRadioNetwork.o \ + CauseTransport.o \ + CauseNas.o \ + CellIdentity.o \ + CellID-Broadcast.o \ + CellID-Broadcast-Item.o \ + Cdma2000PDU.o \ + Cdma2000RATType.o \ + Cdma2000SectorID.o \ + Cdma2000HOStatus.o \ + Cdma2000HORequiredIndication.o \ + Cdma2000OneXSRVCCInfo.o \ + Cdma2000OneXMEID.o \ + Cdma2000OneXMSI.o \ + Cdma2000OneXPilot.o \ + Cdma2000OneXRAND.o \ + Cell-Size.o \ + CellType.o \ + CGI.o \ + CI.o \ + CNDomain.o \ + CSFallbackIndicator.o \ + CSG-Id.o \ + CSG-IdList.o \ + CSG-IdList-Item.o \ + COUNTvalue.o \ + CriticalityDiagnostics.o \ + CriticalityDiagnostics-IE-List.o \ + CriticalityDiagnostics-IE-Item.o \ + DataCodingScheme.o \ + DL-Forwarding.o \ + Direct-Forwarding-Path-Availability.o \ + E-RABToBeModifiedListBearerModReq.o \ + E-RABToBeModifiedItemBearerModReq.o \ + E-RABReleaseListBearerRelComp.o \ + E-RABReleaseItemBearerRelComp.o \ + E-RABDataForwardingList.o \ + E-RABDataForwardingItem.o \ + E-RABToBeSetupListCtxtSUReq.o \ + E-RABToBeSetupItemCtxtSUReq.o \ + E-RABSetupListBearerSURes.o \ + E-RABSetupItemBearerSURes.o \ + E-RABFailedToSetupListHOReqAck.o \ + E-RABFailedToSetupItemHOReqAck.o \ + E-RABToBeSetupListBearerSUReq.o \ + E-RABToBeSetupItemBearerSUReq.o \ + E-RABAdmittedList.o \ + E-RABAdmittedItem.o \ + E-RABToBeSwitchedDLList.o \ + E-RABToBeSwitchedDLItem.o \ + E-RABToBeSwitchedULList.o \ + E-RABToBeSwitchedULItem.o \ + E-RABModifyListBearerModRes.o \ + E-RABModifyItemBearerModRes.o \ + E-RABSetupListCtxtSURes.o \ + E-RABSetupItemCtxtSURes.o \ + E-RABToBeSetupListHOReq.o \ + E-RABToBeSetupItemHOReq.o \ + ECGIList.o \ + EmergencyAreaIDList.o \ + EmergencyAreaID.o \ + EmergencyAreaID-Broadcast.o \ + EmergencyAreaID-Broadcast-Item.o \ + CompletedCellinEAI.o \ + CompletedCellinEAI-Item.o \ + ENB-ID.o \ + GERAN-Cell-ID.o \ + Global-ENB-ID.o \ + ENB-StatusTransfer-TransparentContainer.o \ + ENB-UE-S1AP-ID.o \ + ENBname.o \ + ENBX2TLAs.o \ + EncryptionAlgorithms.o \ + EPLMNs.o \ + EventType.o \ + E-RAB-ID.o \ + E-RABInformationList.o \ + E-RABInformationListItem.o \ + E-RABList.o \ + E-RABItem.o \ + E-RABLevelQoSParameters.o \ + EUTRAN-CGI.o \ + ExtendedRNC-ID.o \ + ForbiddenInterRATs.o \ + ForbiddenTAs.o \ + ForbiddenTAs-Item.o \ + ForbiddenTACs.o \ + ForbiddenLAs.o \ + ForbiddenLAs-Item.o \ + ForbiddenLACs.o \ + GBR-QosInformation.o \ + GTP-TEID.o \ + GUMMEI.o \ + HandoverRestrictionList.o \ + HandoverType.o \ + HFN.o \ + Inter-SystemInformationTransferType.o \ + IMSI.o \ + IntegrityProtectionAlgorithms.o \ + InterfacesToTrace.o \ + LAC.o \ + LAI.o \ + LastVisitedCell-Item.o \ + LastVisitedEUTRANCellInformation.o \ + LastVisitedUTRANCellInformation.o \ + LastVisitedGERANCellInformation.o \ + L3-Information.o \ + MessageIdentifier.o \ + MMEname.o \ + MME-Group-ID.o \ + MME-Code.o \ + MME-UE-S1AP-ID.o \ + M-TMSI.o \ + MSClassmark2.o \ + MSClassmark3.o \ + NAS-PDU.o \ + NASSecurityParametersfromE-UTRAN.o \ + NASSecurityParameterstoE-UTRAN.o \ + NumberofBroadcastRequest.o \ + NumberOfBroadcasts.o \ + OldBSS-ToNewBSS-Information.o \ + OverloadAction.o \ + OverloadResponse.o \ + PagingDRX.o \ + PDCP-SN.o \ + PLMNidentity.o \ + Pre-emptionCapability.o \ + Pre-emptionVulnerability.o \ + PriorityLevel.o \ + QCI.o \ + ReceiveStatusofULPDCPSDUs.o \ + RelativeMMECapacity.o \ + RAC.o \ + RequestType.o \ + ResetType.o \ + ResetAll.o \ + RIMTransfer.o \ + RIMInformation.o \ + RIMRoutingAddress.o \ + ReportArea.o \ + RepetitionPeriod.o \ + RNC-ID.o \ + RRC-Container.o \ + RRC-Establishment-Cause.o \ + SecurityKey.o \ + SecurityContext.o \ + SerialNumber.o \ + SONInformation.o \ + SONInformationRequest.o \ + SONInformationReply.o \ + SONConfigurationTransfer.o \ + Source-ToTarget-TransparentContainer.o \ + SourceBSS-ToTargetBSS-TransparentContainer.o \ + SourceeNB-ID.o \ + SRVCCOperationPossible.o \ + SRVCCHOIndication.o \ + SourceeNB-ToTargeteNB-TransparentContainer.o \ + SourceRNC-ToTargetRNC-TransparentContainer.o \ + ServedGUMMEIs.o \ + ServedGUMMEIsItem.o \ + ServedGroupIDs.o \ + ServedMMECs.o \ + ServedPLMNs.o \ + SubscriberProfileIDforRFP.o \ + SupportedTAs.o \ + SupportedTAs-Item.o \ + S-TMSI.o \ + TAC.o \ + TAIListforWarning.o \ + TAIList.o \ + TAIItem.o \ + TAI.o \ + TAI-Broadcast.o \ + TAI-Broadcast-Item.o \ + CompletedCellinTAI.o \ + CompletedCellinTAI-Item.o \ + TBCD-STRING.o \ + TargetID.o \ + TargeteNB-ID.o \ + TargetRNC-ID.o \ + TargeteNB-ToSourceeNB-TransparentContainer.o \ + Target-ToSource-TransparentContainer.o \ + TargetRNC-ToSourceRNC-TransparentContainer.o \ + TargetBSS-ToSourceBSS-TransparentContainer.o \ + TimeToWait.o \ + Time-UE-StayedInCell.o \ + TransportLayerAddress.o \ + TraceActivation.o \ + TraceDepth.o \ + E-UTRAN-Trace-ID.o \ + TypeOfError.o \ + UEAggregateMaximumBitrate.o \ + UE-S1AP-IDs.o \ + UE-S1AP-ID-pair.o \ + UE-associatedLogicalS1-ConnectionListRes.o \ + UE-associatedLogicalS1-ConnectionListResAck.o \ + UE-associatedLogicalS1-ConnectionItem.o \ + UEIdentityIndexValue.o \ + UE-HistoryInformation.o \ + UEPagingID.o \ + UERadioCapability.o \ + UESecurityCapabilities.o \ + WarningAreaList.o \ + WarningType.o \ + WarningSecurityInfo.o \ + WarningMessageContents.o \ + X2TNLConfigurationInfo.o \ + S1AP-PDU.o \ + InitiatingMessage.o \ + SuccessfulOutcome.o \ + UnsuccessfulOutcome.o \ + HandoverRequired.o \ + HandoverCommand.o \ + HandoverPreparationFailure.o \ + HandoverRequest.o \ + HandoverRequestAcknowledge.o \ + HandoverFailure.o \ + HandoverNotify.o \ + PathSwitchRequest.o \ + PathSwitchRequestAcknowledge.o \ + PathSwitchRequestFailure.o \ + E-RABSetupRequest.o \ + E-RABSetupResponse.o \ + E-RABModifyRequest.o \ + E-RABModifyResponse.o \ + E-RABReleaseIndication.o \ + E-RABReleaseCommand.o \ + E-RABReleaseResponse.o \ + InitialContextSetupRequest.o \ + InitialContextSetupResponse.o \ + InitialContextSetupFailure.o \ + UEContextReleaseRequest.o \ + Paging.o \ + DownlinkNASTransport.o \ + InitialUEMessage.o \ + UplinkNASTransport.o \ + NASNonDeliveryIndication.o \ + HandoverCancel.o \ + HandoverCancelAcknowledge.o \ + Reset.o \ + ResetAcknowledge.o \ + S1SetupResponse.o \ + S1SetupRequest.o \ + S1SetupFailure.o \ + ErrorIndication.o \ + ENBConfigurationUpdate.o \ + ENBConfigurationUpdateAcknowledge.o \ + ENBConfigurationUpdateFailure.o \ + MMEConfigurationUpdate.o \ + MMEConfigurationUpdateAcknowledge.o \ + MMEConfigurationUpdateFailure.o \ + DownlinkS1cdma2000tunneling.o \ + UplinkS1cdma2000tunneling.o \ + UEContextModificationRequest.o \ + UEContextModificationResponse.o \ + UEContextModificationFailure.o \ + UECapabilityInfoIndication.o \ + UEContextReleaseCommand.o \ + UEContextReleaseComplete.o \ + ENBStatusTransfer.o \ + MMEStatusTransfer.o \ + DeactivateTrace.o \ + TraceStart.o \ + TraceFailureIndication.o \ + CellTrafficTrace.o \ + LocationReportingControl.o \ + LocationReportingFailureIndication.o \ + LocationReport.o \ + OverloadStart.o \ + OverloadStop.o \ + WriteReplaceWarningRequest.o \ + WriteReplaceWarningResponse.o \ + ENBDirectInformationTransfer.o \ + MMEDirectInformationTransfer.o \ + ENBConfigurationTransfer.o \ + MMEConfigurationTransfer.o \ + PrivateMessage.o \ + IE.o + +S1AP_ASN_MODULE_HEADERS= \ + Criticality.h \ + Presence.h \ + PrivateIE-ID.h \ + ProcedureCode.h \ + ProtocolExtensionID.h \ + ProtocolIE-ID.h \ + TriggeringMessage.h \ + IE-Extensions.h \ + AllocationAndRetentionPriority.h \ + Bearers-SubjectToStatusTransfer-List.h \ + Bearers-SubjectToStatusTransfer-Item.h \ + BitRate.h \ + BPLMNs.h \ + BroadcastCompletedAreaList.h \ + Cause.h \ + CauseMisc.h \ + CauseProtocol.h \ + CauseRadioNetwork.h \ + CauseTransport.h \ + CauseNas.h \ + CellIdentity.h \ + CellID-Broadcast.h \ + CellID-Broadcast-Item.h \ + Cdma2000PDU.h \ + Cdma2000RATType.h \ + Cdma2000SectorID.h \ + Cdma2000HOStatus.h \ + Cdma2000HORequiredIndication.h \ + Cdma2000OneXSRVCCInfo.h \ + Cdma2000OneXMEID.h \ + Cdma2000OneXMSI.h \ + Cdma2000OneXPilot.h \ + Cdma2000OneXRAND.h \ + Cell-Size.h \ + CellType.h \ + CGI.h \ + CI.h \ + CNDomain.h \ + CSFallbackIndicator.h \ + CSG-Id.h \ + CSG-IdList.h \ + CSG-IdList-Item.h \ + COUNTvalue.h \ + CriticalityDiagnostics.h \ + CriticalityDiagnostics-IE-List.h \ + CriticalityDiagnostics-IE-Item.h \ + DataCodingScheme.h \ + DL-Forwarding.h \ + Direct-Forwarding-Path-Availability.h \ + E-RABToBeModifiedListBearerModReq.h \ + E-RABToBeModifiedItemBearerModReqIEs.h \ + E-RABToBeModifiedItemBearerModReq.h \ + E-RABReleaseListBearerRelComp.h \ + E-RABReleaseItemBearerRelCompIEs.h \ + E-RABReleaseItemBearerRelComp.h \ + E-RABSubjecttoDataForwardingList.h \ + E-RABDataForwardingList.h \ + E-RABDataForwardingItemIEs.h \ + E-RABDataForwardingItem.h \ + E-RABToBeSetupListCtxtSUReq.h \ + E-RABToBeSetupItemCtxtSUReqIEs.h \ + E-RABToBeSetupItemCtxtSUReq.h \ + E-RABSetupListBearerSURes.h \ + E-RABSetupItemBearerSUResIEs.h \ + E-RABSetupItemBearerSURes.h \ + E-RABFailedToSetupListHOReqAck.h \ + E-RABFailedToSetupItemHOReqAckIEs.h \ + E-RABFailedToSetupItemHOReqAck.h \ + E-RABToBeSetupListBearerSUReq.h \ + E-RABToBeSetupItemBearerSUReqIEs.h \ + E-RABToBeSetupItemBearerSUReq.h \ + E-RABAdmittedList.h \ + E-RABAdmittedItemIEs.h \ + E-RABAdmittedItem.h \ + E-RABToBeSwitchedDLList.h \ + E-RABToBeSwitchedDLListIEs.h \ + E-RABToBeSwitchedDLItem.h \ + E-RABToBeSwitchedULList.h \ + E-RABToBeSwitchedULItemIEs.h \ + E-RABToBeSwitchedULItem.h \ + E-RABModifyListBearerModRes.h \ + E-RABModifyItemBearerModResIEs.h \ + E-RABModifyItemBearerModRes.h \ + E-RABSetupListCtxtSURes.h \ + E-RABSetupListCtxtSUResIEs.h \ + E-RABSetupItemCtxtSURes.h \ + E-RABToBeSetupListHOReq.h \ + E-RABToBeSetupListHOReqIEs.h \ + E-RABToBeSetupItemHOReq.h \ + ECGIList.h \ + EmergencyAreaIDList.h \ + EmergencyAreaID.h \ + EmergencyAreaID-Broadcast.h \ + EmergencyAreaID-Broadcast-Item.h \ + CompletedCellinEAI.h \ + CompletedCellinEAI-Item.h \ + ENB-ID.h \ + GERAN-Cell-ID.h \ + Global-ENB-ID.h \ + ENB-StatusTransfer-TransparentContainer.h \ + ENB-UE-S1AP-ID.h \ + ENBname.h \ + ENBX2TLAs.h \ + EncryptionAlgorithms.h \ + EPLMNs.h \ + EventType.h \ + E-RAB-ID.h \ + E-RABInformationList.h \ + E-RABInformationListItem.h \ + E-RABList.h \ + E-RABItem.h \ + E-RABLevelQoSParameters.h \ + EUTRAN-CGI.h \ + ExtendedRNC-ID.h \ + ForbiddenInterRATs.h \ + ForbiddenTAs.h \ + ForbiddenTAs-Item.h \ + ForbiddenTACs.h \ + ForbiddenLAs.h \ + ForbiddenLAs-Item.h \ + ForbiddenLACs.h \ + GBR-QosInformation.h \ + GTP-TEID.h \ + GUMMEI.h \ + HandoverRestrictionList.h \ + HandoverType.h \ + HFN.h \ + HandoverNotify.h \ + Inter-SystemInformationTransferType.h \ + IMSI.h \ + IntegrityProtectionAlgorithms.h \ + InterfacesToTrace.h \ + LAC.h \ + LAI.h \ + LastVisitedCell-Item.h \ + LastVisitedEUTRANCellInformation.h \ + LastVisitedUTRANCellInformation.h \ + LastVisitedGERANCellInformation.h \ + L3-Information.h \ + MessageIdentifier.h \ + MMEname.h \ + MME-Group-ID.h \ + MME-Code.h \ + MME-UE-S1AP-ID.h \ + M-TMSI.h \ + MSClassmark2.h \ + MSClassmark3.h \ + NAS-PDU.h \ + NASSecurityParametersfromE-UTRAN.h \ + NASSecurityParameterstoE-UTRAN.h \ + NumberofBroadcastRequest.h \ + NumberOfBroadcasts.h \ + OldBSS-ToNewBSS-Information.h \ + OverloadAction.h \ + OverloadResponse.h \ + PagingDRX.h \ + PDCP-SN.h \ + PLMNidentity.h \ + Pre-emptionCapability.h \ + Pre-emptionVulnerability.h \ + PriorityLevel.h \ + QCI.h \ + ReceiveStatusofULPDCPSDUs.h \ + RelativeMMECapacity.h \ + RAC.h \ + RequestType.h \ + ResetType.h \ + ResetAll.h \ + RIMTransfer.h \ + RIMInformation.h \ + RIMRoutingAddress.h \ + ReportArea.h \ + RepetitionPeriod.h \ + RNC-ID.h \ + RRC-Container.h \ + RRC-Establishment-Cause.h \ + SecurityKey.h \ + SecurityContext.h \ + SerialNumber.h \ + SONInformation.h \ + SONInformationRequest.h \ + SONInformationReply.h \ + SONConfigurationTransfer.h \ + Source-ToTarget-TransparentContainer.h \ + SourceBSS-ToTargetBSS-TransparentContainer.h \ + SourceeNB-ID.h \ + SRVCCOperationPossible.h \ + SRVCCHOIndication.h \ + SourceeNB-ToTargeteNB-TransparentContainer.h \ + SourceRNC-ToTargetRNC-TransparentContainer.h \ + ServedGUMMEIs.h \ + ServedGUMMEIsItem.h \ + ServedGroupIDs.h \ + ServedMMECs.h \ + ServedPLMNs.h \ + SubscriberProfileIDforRFP.h \ + SupportedTAs.h \ + SupportedTAs-Item.h \ + S-TMSI.h \ + TAC.h \ + TAIListforWarning.h \ + TAIList.h \ + TAIItem.h \ + TAI.h \ + TAI-Broadcast.h \ + TAI-Broadcast-Item.h \ + CompletedCellinTAI.h \ + CompletedCellinTAI-Item.h \ + TBCD-STRING.h \ + TargetID.h \ + TargeteNB-ID.h \ + TargetRNC-ID.h \ + TargeteNB-ToSourceeNB-TransparentContainer.h \ + Target-ToSource-TransparentContainer.h \ + TargetRNC-ToSourceRNC-TransparentContainer.h \ + TargetBSS-ToSourceBSS-TransparentContainer.h \ + TimeToWait.h \ + Time-UE-StayedInCell.h \ + TransportLayerAddress.h \ + TraceActivation.h \ + TraceDepth.h \ + E-UTRAN-Trace-ID.h \ + TypeOfError.h \ + UEAggregateMaximumBitrate.h \ + UE-S1AP-IDs.h \ + UE-S1AP-ID-pair.h \ + UE-associatedLogicalS1-ConnectionListRes.h \ + UE-associatedLogicalS1-ConnectionListResAck.h \ + UE-associatedLogicalS1-ConnectionItem.h \ + UEIdentityIndexValue.h \ + UE-HistoryInformation.h \ + UEPagingID.h \ + UERadioCapability.h \ + UESecurityCapabilities.h \ + WarningAreaList.h \ + WarningType.h \ + WarningSecurityInfo.h \ + WarningMessageContents.h \ + X2TNLConfigurationInfo.h \ + S1AP-PDU.h \ + InitiatingMessage.h \ + SuccessfulOutcome.h \ + UnsuccessfulOutcome.h \ + HandoverRequired.h \ + HandoverCommand.h \ + HandoverPreparationFailure.h \ + HandoverRequest.h \ + HandoverRequestAcknowledge.h \ + HandoverFailure.h \ + HandoverNotify.h \ + PathSwitchRequest.h \ + PathSwitchRequestAcknowledge.h \ + PathSwitchRequestFailure.h \ + E-RABSetupRequest.h \ + E-RABSetupResponse.h \ + E-RABModifyRequest.h \ + E-RABModifyResponse.h \ + E-RABReleaseIndication.h \ + E-RABReleaseCommand.h \ + E-RABReleaseResponse.h \ + InitialContextSetupRequest.h \ + InitialContextSetupResponse.h \ + InitialContextSetupFailure.h \ + UEContextReleaseRequest.h \ + Paging.h \ + DownlinkNASTransport.h \ + InitialUEMessage.h \ + UplinkNASTransport.h \ + NASNonDeliveryIndication.h \ + HandoverCancel.h \ + HandoverCancelAcknowledge.h \ + Reset.h \ + ResetAcknowledge.h \ + S1SetupResponse.h \ + S1SetupRequest.h \ + S1SetupFailure.h \ + ErrorIndication.h \ + ENBConfigurationUpdate.h \ + ENBConfigurationUpdateAcknowledge.h \ + ENBConfigurationUpdateFailure.h \ + MMEConfigurationUpdate.h \ + MMEConfigurationUpdateAcknowledge.h \ + MMEConfigurationUpdateFailure.h \ + DownlinkS1cdma2000tunneling.h \ + UplinkS1cdma2000tunneling.h \ + UEContextModificationRequest.h \ + UEContextModificationResponse.h \ + UEContextModificationFailure.h \ + UECapabilityInfoIndication.h \ + UEContextReleaseCommand.h \ + UEContextReleaseComplete.h \ + ENBStatusTransfer.h \ + MMEStatusTransfer.h \ + DeactivateTrace.h \ + TraceStart.h \ + TraceFailureIndication.h \ + CellTrafficTrace.h \ + LocationReportingControl.h \ + LocationReportingFailureIndication.h \ + LocationReport.h \ + OverloadStart.h \ + OverloadStop.h \ + WriteReplaceWarningRequest.h \ + WriteReplaceWarningResponse.h \ + ENBDirectInformationTransfer.h \ + MMEDirectInformationTransfer.h \ + ENBConfigurationTransfer.h \ + MMEConfigurationTransfer.h \ + PrivateMessage.h \ + IE.h + +ifdef UPDATE_RELEASE_9 +S1AP_ASN_MODULE_SOURCES += \ + KillResponse.o \ + KillRequest.o \ + Data-Forwarding-Not-Possible.o \ + DownlinkUEAssociatedLPPaTransport.o \ + UplinkUEAssociatedLPPaTransport.o \ + DownlinkNonUEAssociatedLPPaTransport.o \ + UplinkNonUEAssociatedLPPaTransport.o \ + TAI-Cancelled.o \ + TAI-Cancelled-Item.o \ + StratumLevel.o \ + SynchronizationStatus.o \ + TimeSynchronizationInfo.o \ + Routing-ID.o \ + PS-ServiceNotAvailable.o \ + LPPa-PDU.o \ + ExtendedRepetitionPeriod.o \ + EUTRANRoundTripDelayEstimationInfo.o \ + EmergencyAreaID-Cancelled.o \ + EmergencyAreaID-Cancelled-Item.o \ + CSGMembershipStatus.o \ + ConcurrentWarningMessageIndicator.o \ + CellID-Cancelled.o \ + CellID-Cancelled-Item.o \ + CellAccessMode.o \ + CancelledCellinEAI.o \ + CancelledCellinEAI-Item.o \ + CancelledCellinTAI.o \ + CancelledCellinTAI-Item.o \ + BroadcastCancelledAreaList.o + +S1AP_ASN_MODULE_HEADERS += \ + BroadcastCancelledAreaList.h \ + CancelledCellinEAI.h \ + CancelledCellinEAI-Item.h \ + CancelledCellinTAI.h \ + CancelledCellinTAI-Item.h \ + CellAccessMode.h \ + CellID-Cancelled.h \ + CellID-Cancelled-Item.h \ + ConcurrentWarningMessageIndicator.h \ + CSGMembershipStatus.h \ + Data-Forwarding-Not-Possible.h \ + EmergencyAreaID-Cancelled.h \ + EmergencyAreaID-Cancelled-Item.h \ + E-RABList.h \ + EUTRANRoundTripDelayEstimationInfo.h \ + ExtendedRepetitionPeriod.h \ + LPPa-PDU.h \ + PS-ServiceNotAvailable.h \ + Routing-ID.h \ + StratumLevel.h \ + SynchronizationStatus.h \ + TimeSynchronizationInfo.h \ + TAI-Cancelled.h \ + TAI-Cancelled-Item.h \ + KillResponse.h \ + KillRequest.h \ + DownlinkUEAssociatedLPPaTransport.h \ + UplinkUEAssociatedLPPaTransport.h \ + DownlinkNonUEAssociatedLPPaTransport.h \ + UplinkNonUEAssociatedLPPaTransport.h +endif + +ifdef UPDATE_RELEASE_10 +S1AP_ASN_MODULE_SOURCES += \ + PagingPriority.o \ + RelayNode-Indicator.o \ + GWContextReleaseIndication.o \ + MMERelaySupportIndicator.o \ + ManagementBasedMDTAllowed.o \ + PrivacyIndicator.o \ + TrafficLoadReductionIndication.o \ + GUMMEIList.o + +S1AP_ASN_MODULE_HEADERS += \ + PagingPriority.h \ + RelayNode-Indicator.h \ + GWContextReleaseIndication.h \ + MMERelaySupportIndicator.h \ + ManagementBasedMDTAllowed.h \ + PrivacyIndicator.h \ + TrafficLoadReductionIndication.h \ + GUMMEIList.h +endif + +S1AP_ASN_MODULE_HEADERS+=ANY.h +S1AP_ASN_MODULE_SOURCES+=ANY.o +S1AP_ASN_MODULE_HEADERS+=BOOLEAN.h +S1AP_ASN_MODULE_SOURCES+=BOOLEAN.o +S1AP_ASN_MODULE_HEADERS+=INTEGER.h +S1AP_ASN_MODULE_HEADERS+=NativeEnumerated.h +S1AP_ASN_MODULE_SOURCES+=INTEGER.o +S1AP_ASN_MODULE_HEADERS+=NULL.h +S1AP_ASN_MODULE_SOURCES+=NULL.o +S1AP_ASN_MODULE_SOURCES+=NativeEnumerated.o +S1AP_ASN_MODULE_HEADERS+=NativeInteger.h +S1AP_ASN_MODULE_SOURCES+=NativeInteger.o +S1AP_ASN_MODULE_HEADERS+=OBJECT_IDENTIFIER.h +S1AP_ASN_MODULE_SOURCES+=OBJECT_IDENTIFIER.o +S1AP_ASN_MODULE_HEADERS+=PrintableString.h +S1AP_ASN_MODULE_SOURCES+=PrintableString.o +S1AP_ASN_MODULE_HEADERS+=asn_SEQUENCE_OF.h +S1AP_ASN_MODULE_SOURCES+=asn_SEQUENCE_OF.o +S1AP_ASN_MODULE_HEADERS+=asn_SET_OF.h +S1AP_ASN_MODULE_SOURCES+=asn_SET_OF.o +S1AP_ASN_MODULE_HEADERS+=constr_CHOICE.h +S1AP_ASN_MODULE_SOURCES+=constr_CHOICE.o +S1AP_ASN_MODULE_HEADERS+=constr_SEQUENCE.h +S1AP_ASN_MODULE_SOURCES+=constr_SEQUENCE.o +S1AP_ASN_MODULE_HEADERS+=constr_SEQUENCE_OF.h +S1AP_ASN_MODULE_SOURCES+=constr_SEQUENCE_OF.o +S1AP_ASN_MODULE_HEADERS+=constr_SET_OF.h +S1AP_ASN_MODULE_SOURCES+=constr_SET_OF.o +S1AP_ASN_MODULE_HEADERS+=asn_application.h +S1AP_ASN_MODULE_HEADERS+=asn_system.h +S1AP_ASN_MODULE_HEADERS+=asn_codecs.h +S1AP_ASN_MODULE_HEADERS+=asn_internal.h +S1AP_ASN_MODULE_HEADERS+=OCTET_STRING.h +S1AP_ASN_MODULE_SOURCES+=OCTET_STRING.o +S1AP_ASN_MODULE_HEADERS+=BIT_STRING.h +S1AP_ASN_MODULE_SOURCES+=BIT_STRING.o +S1AP_ASN_MODULE_SOURCES+=asn_codecs_prim.o +S1AP_ASN_MODULE_HEADERS+=asn_codecs_prim.h +S1AP_ASN_MODULE_HEADERS+=ber_tlv_length.h +S1AP_ASN_MODULE_SOURCES+=ber_tlv_length.o +S1AP_ASN_MODULE_HEADERS+=ber_tlv_tag.h +S1AP_ASN_MODULE_SOURCES+=ber_tlv_tag.o +S1AP_ASN_MODULE_HEADERS+=ber_decoder.h +S1AP_ASN_MODULE_SOURCES+=ber_decoder.o +S1AP_ASN_MODULE_HEADERS+=der_encoder.h +S1AP_ASN_MODULE_SOURCES+=der_encoder.o +S1AP_ASN_MODULE_HEADERS+=constr_TYPE.h +S1AP_ASN_MODULE_SOURCES+=constr_TYPE.o +S1AP_ASN_MODULE_HEADERS+=constraints.h +S1AP_ASN_MODULE_SOURCES+=constraints.o +S1AP_ASN_MODULE_HEADERS+=xer_support.h +S1AP_ASN_MODULE_SOURCES+=xer_support.o +S1AP_ASN_MODULE_HEADERS+=xer_decoder.h +S1AP_ASN_MODULE_SOURCES+=xer_decoder.o +S1AP_ASN_MODULE_HEADERS+=xer_encoder.h +S1AP_ASN_MODULE_SOURCES+=xer_encoder.o +S1AP_ASN_MODULE_HEADERS+=per_support.h +S1AP_ASN_MODULE_SOURCES+=per_support.o +S1AP_ASN_MODULE_HEADERS+=per_decoder.h +S1AP_ASN_MODULE_SOURCES+=per_decoder.o +S1AP_ASN_MODULE_HEADERS+=per_encoder.h +S1AP_ASN_MODULE_SOURCES+=per_encoder.o +S1AP_ASN_MODULE_HEADERS+=per_opentype.h +S1AP_ASN_MODULE_SOURCES+=per_opentype.o \ No newline at end of file diff --git a/openair-cn/S1AP/Makefile.am b/openair-cn/S1AP/Makefile.am new file mode 100644 index 0000000000..d6e9fac9ed --- /dev/null +++ b/openair-cn/S1AP/Makefile.am @@ -0,0 +1,36 @@ +SUBDIRS = ./MESSAGES/ . + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_builddir)/S1AP \ + -I$(top_builddir)/S1AP/MESSAGES \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/SCTP \ + -I$(top_srcdir)/UTILS \ + -DEMIT_ASN_DEBUG_EXTERN + +noinst_LTLIBRARIES = libs1ap.la +libs1ap_la_LDFLAGS = -all-static +libs1ap_la_LIBADD = ./MESSAGES/libs1apmessages.la + +libs1ap_la_SOURCES = \ + s1ap_common.h s1ap_common.c \ + s1ap_mme_encoder.h s1ap_mme_encoder.c \ + s1ap_mme_decoder.h s1ap_mme_decoder.c \ + s1ap_mme_handlers.h s1ap_mme_handlers.c \ + s1ap_mme_nas_procedures.c s1ap_mme_nas_procedures.h \ + s1ap_mme.h s1ap_mme.c \ + s1ap_mme_itti_messaging.c s1ap_mme_itti_messaging.h \ + s1ap_mme_retransmission.c s1ap_mme_retransmission.h \ + s1ap_mme_ta.c s1ap_mme_ta.h \ + $(top_builddir)/S1AP/s1ap_decoder.c \ + $(top_builddir)/S1AP/s1ap_encoder.c \ + $(top_builddir)/S1AP/s1ap_xer_print.c \ + $(top_builddir)/S1AP/s1ap_ies_defs.h + +clean-local: + rm -f $(top_builddir)/S1AP/s1ap_ies_defs.h + rm -f $(top_builddir)/S1AP/s1ap_decoder.c + rm -f $(top_builddir)/S1AP/s1ap_encoder.c + rm -f $(top_builddir)/S1AP/s1ap_xer_print.c diff --git a/openair-cn/S1AP/Makefile.eNB b/openair-cn/S1AP/Makefile.eNB new file mode 100644 index 0000000000..c9faf35cb8 --- /dev/null +++ b/openair-cn/S1AP/Makefile.eNB @@ -0,0 +1,96 @@ +S1AP_DIR = $(OPENAIR3_DIR)/OPENAIRMME/S1AP +S1AP_OBJDIR = $(OPENAIR3_DIR)/OPENAIRMME/S1AP/enb_objs + +ASN1MESSAGESDIR=$(S1AP_DIR)/MESSAGES +ASN1DIR=$(ASN1MESSAGESDIR)/ASN1 + +ifeq ($(USE_MME), R10) + ASN1RELDIR=R10.5 + UPDATE_RELEASE_9=1 + UPDATE_RELEASE_10=1 + ADD_CFLAGS=-DUPDATE_RELEASE_9 -DUPDATE_RELEASE_10 +else + ifeq ($(USE_MME), R9) + UPDATE_RELEASE_9=1 + ASN1RELDIR=R9.8 + ADD_CFLAGS=-DUPDATE_RELEASE_9 + else + ASN1RELDIR=R8.10 + endif +endif + +include $(ASN1MESSAGESDIR)/Makefile.inc + +libs1ap_OBJECTS = \ + s1ap_eNB.o s1ap_common.o \ + $(S1AP_OBJDIR)/s1ap_encoder.o \ + $(S1AP_OBJDIR)/s1ap_decoder.o \ + $(S1AP_OBJDIR)/s1ap_xer_print.o \ + s1ap_eNB_decoder.o s1ap_eNB_encoder.o \ + s1ap_eNB_handlers.o \ + s1ap_eNB_nnsf.o s1ap_eNB_ue_context.o \ + s1ap_eNB_trace.o s1ap_eNB_overload.o \ + s1ap_eNB_nas_procedures.o \ + s1ap_eNB_management_procedures.o \ + $(addprefix MESSAGES/, $(S1AP_ASN_MODULE_SOURCES)) + +# pull in dependency info for *existing* .o files +-include .*.d +# -include .*.d + +CFLAGS = \ + -I./MESSAGES \ + -I$(S1AP_OBJDIR) \ + -I../GTPV1-U \ + -I../GTPV1-U/nw-gtpv1u/shared \ + -I../GTPV1-U/nw-gtpv1u/include \ + -I../SCTP \ + -I../UDP \ + -I../UTILS \ + -I../UTILS/HASHTABLE \ + -I$(OPENAIR2_DIR)/COMMON \ + -I$(S1AP_DIR) \ + -I$(OPENAIR2_DIR) \ + -I$(OPENAIR2_DIR)/UTIL \ + $(ADD_CFLAGS) \ + -DENB_MODE \ + -DENABLE_USE_MME \ + -DEMIT_ASN_DEBUG_EXTERN \ + -DUSER_MODE \ + -g \ + -O2 \ + -Wall \ + -Werror=implicit-function-declaration + +$(libs1ap_OBJECTS): %.o : %.c + @echo "Compiling $<" + @$(CC) -c $(CFLAGS) -o $@ $< + @$(CC) -MM $(CFLAGS) $*.c > .$(notdir $*).d + @mv -f .$(notdir $*).d .$(notdir $*).d.tmp + @sed -e 's|.*:|$*.o:|' < .$(notdir $*).d.tmp > .$(notdir $*).d + @sed -e 's/.*://' -e 's/\\$$//' < .$(notdir $*).d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .$(notdir $*).d + @rm -f .$(notdir $*).tmp + +$(S1AP_OBJDIR)/s1ap_ieregen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU-Contents.asn $(ASN1DIR)/asn1tostruct.py + mkdir -p $(S1AP_OBJDIR) + python $(ASN1DIR)/asn1tostruct.py -f$< -o$(S1AP_OBJDIR) + echo Timestamp > $@ + +$(S1AP_OBJDIR)/s1ap_asn1regen.stamp: $(ASN1DIR)/$(ASN1RELDIR)/S1AP-CommonDataTypes.asn \ + $(ASN1DIR)/$(ASN1RELDIR)/S1AP-Constants.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-IEs.asn $(ASN1DIR)/$(ASN1RELDIR)/S1AP-PDU.asn + (cd $(ASN1MESSAGESDIR) && asn1c -fhave_native64 -gen-PER $^) + echo Timestamp > $@ + +libs1ap.a: $(S1AP_OBJDIR)/s1ap_ieregen.stamp $(S1AP_OBJDIR)/s1ap_asn1regen.stamp $(libs1ap_OBJECTS) + @echo Creating S1AP archive + @$(AR) rcs $@ $(libs1ap_OBJECTS) + +clean: + rm -f $(libs1ap_OBJECTS) + rm -f $(libs1ap_OBJECTS:.o=.d) + rm -f libs1ap.a + rm -f $(S1AP_OBJDIR)/s1ap_asn1regen.stamp + rm -f $(S1AP_OBJDIR)/s1ap_ieregen.stamp + rm -f $(S1AP_OBJDIR)/s1ap_decoder.c $(S1AP_OBJDIR)/s1ap_encoder.c + rm -f $(S1AP_OBJDIR)/s1ap_xer_print.c $(S1AP_OBJDIR)/s1ap_ies_defs.h \ No newline at end of file diff --git a/openair-cn/S1AP/Makefile.inc b/openair-cn/S1AP/Makefile.inc new file mode 100644 index 0000000000..437068d106 --- /dev/null +++ b/openair-cn/S1AP/Makefile.inc @@ -0,0 +1,9 @@ +S1AP_OBJS = $(OPENAIR2_DIR)/S1AP/s1ap_eNB.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_common.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_encoder.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_decoder.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_eNB_decoder.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_eNB_encoder.o +S1AP_OBJS += $(OPENAIR2_DIR)/S1AP/s1ap_eNB_handlers.o + +S1AP_Incl = -I$(OPENAIR2_DIR)/S1AP -I$(OPENAIR2_DIR)/S1AP/MESSAGES diff --git a/openair-cn/S1AP/s1ap_common.c b/openair-cn/S1AP/s1ap_common.c new file mode 100644 index 0000000000..655b4c9d71 --- /dev/null +++ b/openair-cn/S1AP/s1ap_common.c @@ -0,0 +1,199 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_common.c + * \brief s1ap procedures for both eNB and MME + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include <stdint.h> + +#include "s1ap_common.h" +#include "S1AP-PDU.h" + +int asn_debug = 0; +int asn1_xer_print = 0; + +inline void ASN_DEBUG(const char *fmt, ...) +{ + if (asn_debug) { + int adi = asn_debug_indent; + va_list ap; + va_start(ap, fmt); + fprintf(stderr, "[ASN1]"); + while(adi--) fprintf(stderr, " "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + } +} + +ssize_t s1ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + S1AP_PDU_t pdu; + ssize_t encoded; + + memset(&pdu, 0, sizeof(S1AP_PDU_t)); + + pdu.present = S1AP_PDU_PR_initiatingMessage; + pdu.choice.initiatingMessage.procedureCode = procedureCode; + pdu.choice.initiatingMessage.criticality = criticality; + ANY_fromType_aper(&pdu.choice.initiatingMessage.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_S1AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_S1AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + return encoded; +} + +ssize_t s1ap_generate_successfull_outcome( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + S1AP_PDU_t pdu; + ssize_t encoded; + + memset(&pdu, 0, sizeof(S1AP_PDU_t)); + + pdu.present = S1AP_PDU_PR_successfulOutcome; + pdu.choice.successfulOutcome.procedureCode = procedureCode; + pdu.choice.successfulOutcome.criticality = criticality; + ANY_fromType_aper(&pdu.choice.successfulOutcome.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_S1AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_S1AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + + return encoded; +} + +ssize_t s1ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr) +{ + S1AP_PDU_t pdu; + ssize_t encoded; + + memset(&pdu, 0, sizeof(S1AP_PDU_t)); + + pdu.present = S1AP_PDU_PR_unsuccessfulOutcome; + pdu.choice.successfulOutcome.procedureCode = procedureCode; + pdu.choice.successfulOutcome.criticality = criticality; + ANY_fromType_aper(&pdu.choice.successfulOutcome.value, td, sptr); + + if (asn1_xer_print) { + xer_fprint(stdout, &asn_DEF_S1AP_PDU, (void *)&pdu); + } + + /* We can safely free list of IE from sptr */ + ASN_STRUCT_FREE_CONTENTS_ONLY(*td, sptr); + + if ((encoded = aper_encode_to_new_buffer(&asn_DEF_S1AP_PDU, 0, &pdu, + (void **)buffer)) < 0) { + return -1; + } + + *length = encoded; + + return encoded; +} + +IE_t *s1ap_new_ie( + ProtocolIE_ID_t id, + Criticality_t criticality, + asn_TYPE_descriptor_t *type, + void *sptr) +{ + IE_t *buff; + + if ((buff = malloc(sizeof(IE_t))) == NULL) { + // Possible error on malloc + return NULL; + } + memset((void *)buff, 0, sizeof(IE_t)); + + buff->id = id; + buff->criticality = criticality; + + if (ANY_fromType_aper(&buff->value, type, sptr) < 0) { + fprintf(stderr, "Encoding of %s failed\n", type->name); + free(buff); + return NULL; + } + + if (asn1_xer_print) + if (xer_fprint(stdout, &asn_DEF_IE, buff) < 0) { + free(buff); + return NULL; + } + + return buff; +} + +void s1ap_handle_criticality(e_Criticality criticality) +{ + +} diff --git a/openair-cn/S1AP/s1ap_common.h b/openair-cn/S1AP/s1ap_common.h new file mode 100644 index 0000000000..bd0d9e5c81 --- /dev/null +++ b/openair-cn/S1AP/s1ap_common.h @@ -0,0 +1,505 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/** @defgroup _s1ap_impl_ S1AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#if HAVE_CONFIG_H_ +# include "config.h" +#endif + +#ifndef S1AP_COMMON_H_ +#define S1AP_COMMON_H_ + +/* Defined in asn_internal.h */ +// extern int asn_debug_indent; +extern int asn_debug; + +inline void ASN_DEBUG(const char *fmt, ...); + +#include "Criticality.h" +#include "Presence.h" +#include "PrivateIE-ID.h" +#include "ProcedureCode.h" +#include "ProtocolExtensionID.h" +#include "ProtocolIE-ID.h" +#include "TriggeringMessage.h" +#include "AllocationAndRetentionPriority.h" +#include "Bearers-SubjectToStatusTransfer-List.h" +#include "Bearers-SubjectToStatusTransfer-Item.h" +#include "BitRate.h" +#include "BPLMNs.h" +#include "BroadcastCompletedAreaList.h" +#include "Cause.h" +#include "CauseMisc.h" +#include "CauseProtocol.h" +#include "CauseRadioNetwork.h" +#include "CauseTransport.h" +#include "CauseNas.h" +#include "CellIdentity.h" +#include "CellID-Broadcast.h" +#include "CellID-Broadcast-Item.h" +#include "Cdma2000PDU.h" +#include "Cdma2000RATType.h" +#include "Cdma2000SectorID.h" +#include "Cdma2000HOStatus.h" +#include "Cdma2000HORequiredIndication.h" +#include "Cdma2000OneXSRVCCInfo.h" +#include "Cdma2000OneXMEID.h" +#include "Cdma2000OneXMSI.h" +#include "Cdma2000OneXPilot.h" +#include "Cdma2000OneXRAND.h" +#include "Cell-Size.h" +#include "CellType.h" +#include "CGI.h" +#include "CI.h" +#include "CNDomain.h" +#include "CSFallbackIndicator.h" +#include "CSG-Id.h" +#include "CSG-IdList.h" +#include "CSG-IdList-Item.h" +#include "COUNTvalue.h" +#include "CriticalityDiagnostics.h" +#include "CriticalityDiagnostics-IE-List.h" +#include "CriticalityDiagnostics-IE-Item.h" +#include "DataCodingScheme.h" +#include "DL-Forwarding.h" +#include "Direct-Forwarding-Path-Availability.h" +#include "ECGIList.h" +#include "EmergencyAreaIDList.h" +#include "EmergencyAreaID.h" +#include "EmergencyAreaID-Broadcast.h" +#include "EmergencyAreaID-Broadcast-Item.h" +#include "CompletedCellinEAI.h" +#include "CompletedCellinEAI-Item.h" +#include "ENB-ID.h" +#include "GERAN-Cell-ID.h" +#include "Global-ENB-ID.h" +#include "ENB-StatusTransfer-TransparentContainer.h" +#include "ENB-UE-S1AP-ID.h" +#include "ENBname.h" +#include "ENBX2TLAs.h" +#include "EncryptionAlgorithms.h" +#include "EPLMNs.h" +#include "EventType.h" +#include "E-RAB-ID.h" +#include "E-RABInformationList.h" +#include "E-RABInformationListItem.h" +#include "E-RABList.h" +#include "E-RABItem.h" +#include "E-RABLevelQoSParameters.h" +#include "EUTRAN-CGI.h" +#include "ExtendedRNC-ID.h" +#include "ForbiddenInterRATs.h" +#include "ForbiddenTAs.h" +#include "ForbiddenTAs-Item.h" +#include "ForbiddenTACs.h" +#include "ForbiddenLAs.h" +#include "ForbiddenLAs-Item.h" +#include "ForbiddenLACs.h" +#include "GBR-QosInformation.h" +#include "GTP-TEID.h" +#include "GUMMEI.h" +#include "HandoverRestrictionList.h" +#include "HandoverType.h" +#include "HFN.h" +#include "IMSI.h" +#include "IntegrityProtectionAlgorithms.h" +#include "InterfacesToTrace.h" +#include "LAC.h" +#include "LAI.h" +#include "LastVisitedCell-Item.h" +#include "LastVisitedEUTRANCellInformation.h" +#include "LastVisitedUTRANCellInformation.h" +#include "LastVisitedGERANCellInformation.h" +#include "L3-Information.h" +#include "MessageIdentifier.h" +#include "MMEname.h" +#include "MME-Group-ID.h" +#include "MME-Code.h" +#include "MME-UE-S1AP-ID.h" +#include "M-TMSI.h" +#include "MSClassmark2.h" +#include "MSClassmark3.h" +#include "NAS-PDU.h" +#include "NASSecurityParametersfromE-UTRAN.h" +#include "NASSecurityParameterstoE-UTRAN.h" +#include "NumberofBroadcastRequest.h" +#include "NumberOfBroadcasts.h" +#include "OldBSS-ToNewBSS-Information.h" +#include "OverloadAction.h" +#include "OverloadResponse.h" +#include "PagingDRX.h" +#include "PDCP-SN.h" +#include "PLMNidentity.h" +#include "Pre-emptionCapability.h" +#include "Pre-emptionVulnerability.h" +#include "PriorityLevel.h" +#include "QCI.h" +#include "ReceiveStatusofULPDCPSDUs.h" +#include "RelativeMMECapacity.h" +#include "RAC.h" +#include "RequestType.h" +#include "RIMTransfer.h" +#include "RIMInformation.h" +#include "RIMRoutingAddress.h" +#include "ReportArea.h" +#include "RepetitionPeriod.h" +#include "RNC-ID.h" +#include "RRC-Container.h" +#include "RRC-Establishment-Cause.h" +#include "SecurityKey.h" +#include "SecurityContext.h" +#include "SerialNumber.h" +#include "SONInformation.h" +#include "SONInformationRequest.h" +#include "SONInformationReply.h" +#include "SONConfigurationTransfer.h" +#include "Source-ToTarget-TransparentContainer.h" +#include "SourceBSS-ToTargetBSS-TransparentContainer.h" +#include "SourceeNB-ID.h" +#include "SRVCCOperationPossible.h" +#include "SRVCCHOIndication.h" +#include "SourceeNB-ToTargeteNB-TransparentContainer.h" +#include "SourceRNC-ToTargetRNC-TransparentContainer.h" +#include "ServedGUMMEIs.h" +#include "ServedGUMMEIsItem.h" +#include "ServedGroupIDs.h" +#include "ServedMMECs.h" +#include "ServedPLMNs.h" +#include "SubscriberProfileIDforRFP.h" +#include "SupportedTAs.h" +#include "SupportedTAs-Item.h" +#include "S-TMSI.h" +#include "TAC.h" +#include "TAIItem.h" +#include "TAIList.h" +#include "TAIListforWarning.h" +#include "TAI.h" +#include "TAI-Broadcast.h" +#include "TAI-Broadcast-Item.h" +#include "CompletedCellinTAI.h" +#include "CompletedCellinTAI-Item.h" +#include "TBCD-STRING.h" +#include "TargetID.h" +#include "TargeteNB-ID.h" +#include "TargetRNC-ID.h" +#include "TargeteNB-ToSourceeNB-TransparentContainer.h" +#include "Target-ToSource-TransparentContainer.h" +#include "TargetRNC-ToSourceRNC-TransparentContainer.h" +#include "TargetBSS-ToSourceBSS-TransparentContainer.h" +#include "TimeToWait.h" +#include "Time-UE-StayedInCell.h" +#include "TransportLayerAddress.h" +#include "TraceActivation.h" +#include "TraceDepth.h" +#include "E-UTRAN-Trace-ID.h" +#include "TypeOfError.h" +#include "UEAggregateMaximumBitrate.h" +#include "UE-S1AP-IDs.h" +#include "UE-S1AP-ID-pair.h" +#include "UE-associatedLogicalS1-ConnectionItem.h" +#include "UEIdentityIndexValue.h" +#include "UE-HistoryInformation.h" +#include "UEPagingID.h" +#include "UERadioCapability.h" +#include "UESecurityCapabilities.h" +#include "WarningAreaList.h" +#include "WarningType.h" +#include "WarningSecurityInfo.h" +#include "WarningMessageContents.h" +#include "X2TNLConfigurationInfo.h" +#include "S1AP-PDU.h" +#include "InitiatingMessage.h" +#include "SuccessfulOutcome.h" +#include "UnsuccessfulOutcome.h" +#include "HandoverRequired.h" +#include "HandoverCommand.h" +#include "HandoverNotify.h" +#include "HandoverPreparationFailure.h" +#include "HandoverRequest.h" +#include "HandoverRequestAcknowledge.h" +#include "HandoverFailure.h" +#include "PathSwitchRequest.h" +#include "PathSwitchRequestAcknowledge.h" +#include "PathSwitchRequestFailure.h" +#include "E-RABSetupRequest.h" +#include "E-RABSetupResponse.h" +#include "E-RABModifyRequest.h" +#include "E-RABModifyResponse.h" +#include "E-RABReleaseIndication.h" +#include "E-RABReleaseCommand.h" +#include "E-RABReleaseResponse.h" +#include "InitialContextSetupRequest.h" +#include "InitialContextSetupResponse.h" +#include "InitialContextSetupFailure.h" +#include "UEContextReleaseRequest.h" +#include "Paging.h" +#include "DownlinkNASTransport.h" +#include "InitialUEMessage.h" +#include "UplinkNASTransport.h" +#include "NASNonDeliveryIndication.h" +#include "HandoverCancel.h" +#include "HandoverCancelAcknowledge.h" +#include "Reset.h" +#include "ResetType.h" +#include "ResetAcknowledge.h" +#include "S1SetupResponse.h" +#include "S1SetupRequest.h" +#include "S1SetupFailure.h" +#include "ErrorIndication.h" +#include "ENBConfigurationUpdate.h" +#include "ENBConfigurationUpdateAcknowledge.h" +#include "ENBConfigurationUpdateFailure.h" +#include "MMEConfigurationUpdate.h" +#include "MMEConfigurationUpdateAcknowledge.h" +#include "MMEConfigurationUpdateFailure.h" +#include "DownlinkS1cdma2000tunneling.h" +#include "UplinkS1cdma2000tunneling.h" +#include "UEContextModificationRequest.h" +#include "UEContextModificationResponse.h" +#include "UEContextModificationFailure.h" +#include "UECapabilityInfoIndication.h" +#include "UEContextReleaseCommand.h" +#include "UEContextReleaseComplete.h" +#include "ENBStatusTransfer.h" +#include "MMEStatusTransfer.h" +#include "DeactivateTrace.h" +#include "TraceStart.h" +#include "TraceFailureIndication.h" +#include "CellTrafficTrace.h" +#include "LocationReportingControl.h" +#include "LocationReportingFailureIndication.h" +#include "LocationReport.h" +#include "OverloadStart.h" +#include "OverloadStop.h" +#include "WriteReplaceWarningRequest.h" +#include "WriteReplaceWarningResponse.h" +#include "ENBDirectInformationTransfer.h" +#include "MMEDirectInformationTransfer.h" +#include "ENBConfigurationTransfer.h" +#include "MMEConfigurationTransfer.h" +#include "PrivateMessage.h" +#include "Inter-SystemInformationTransferType.h" +#include "E-RABReleaseItemBearerRelComp.h" +#include "E-RABToBeSwitchedDLList.h" +#include "E-RABToBeSwitchedDLItem.h" +#include "E-RABToBeSwitchedULList.h" +#include "E-RABToBeSwitchedULItem.h" +#include "E-RABToBeSetupListBearerSUReq.h" +#include "E-RABToBeSetupItemBearerSUReq.h" +#include "E-RABDataForwardingList.h" +#include "E-RABDataForwardingItem.h" +#include "E-RABToBeSetupListHOReq.h" +#include "E-RABToBeSetupItemHOReq.h" +#include "E-RABAdmittedList.h" +#include "E-RABAdmittedItem.h" +#include "E-RABFailedToSetupListHOReqAck.h" +#include "E-RABToBeSetupItemCtxtSUReq.h" +#include "E-RABToBeSetupListCtxtSUReq.h" +#include "E-RABSetupItemBearerSURes.h" +#include "E-RABSetupListBearerSURes.h" +#include "E-RABSetupItemCtxtSURes.h" +#include "E-RABSetupListCtxtSURes.h" +#include "E-RABReleaseListBearerRelComp.h" +#include "E-RABModifyItemBearerModRes.h" +#include "E-RABModifyListBearerModRes.h" +#include "E-RABFailedToSetupItemHOReqAck.h" +#include "E-RABFailedToSetupListHOReqAck.h" +#include "E-RABToBeModifiedItemBearerModReq.h" +#include "E-RABToBeModifiedListBearerModReq.h" +#include "UE-associatedLogicalS1-ConnectionListResAck.h" +#include "IE.h" + +#if defined (UPDATE_RELEASE_9) +# include "BroadcastCancelledAreaList.h" +# include "CancelledCellinEAI.h" +# include "CancelledCellinEAI-Item.h" +# include "CancelledCellinTAI.h" +# include "CancelledCellinTAI-Item.h" +# include "CellAccessMode.h" +# include "CellID-Cancelled.h" +# include "CellID-Cancelled-Item.h" +# include "ConcurrentWarningMessageIndicator.h" +# include "CSGMembershipStatus.h" +# include "Data-Forwarding-Not-Possible.h" +# include "EmergencyAreaID-Cancelled.h" +# include "EmergencyAreaID-Cancelled-Item.h" +# include "E-RABList.h" +# include "EUTRANRoundTripDelayEstimationInfo.h" +# include "ExtendedRepetitionPeriod.h" +# include "LPPa-PDU.h" +# include "PS-ServiceNotAvailable.h" +# include "Routing-ID.h" +# include "StratumLevel.h" +# include "SynchronizationStatus.h" +# include "TimeSynchronizationInfo.h" +# include "TAI-Cancelled.h" +# include "TAI-Cancelled-Item.h" +# include "KillRequest.h" +# include "KillResponse.h" +# include "DownlinkUEAssociatedLPPaTransport.h" +# include "UplinkUEAssociatedLPPaTransport.h" +# include "DownlinkNonUEAssociatedLPPaTransport.h" +# include "UplinkNonUEAssociatedLPPaTransport.h" +#endif /* (UPDATE_RELEASE_9) */ + +#if defined(UPDATE_RELEASE_10) +# include "PagingPriority.h" +# include "RelayNode-Indicator.h" +# include "GWContextReleaseIndication.h" +# include "MMERelaySupportIndicator.h" +# include "ManagementBasedMDTAllowed.h" +# include "PrivacyIndicator.h" +# include "TrafficLoadReductionIndication.h" +# include "GUMMEIList.h" +#endif /* (UPDATE_RELEASE_10) */ + +/* Checking version of ASN1C compiler */ +#if (ASN1C_ENVIRONMENT_VERSION < ASN1C_MINIMUM_VERSION) +# error "You are compiling s1ap with the wrong version of ASN1C" +#endif + +#ifndef FALSE +# define FALSE (0) +#endif +#ifndef TRUE +# define TRUE (!FALSE) +#endif + +extern int asn_debug; +extern int asn1_xer_print; + +#if defined(ENB_MODE) +# include "mme_sim.h" +# include "UTIL/LOG/log.h" +# include "eNB_default_values.h" +# define S1AP_ERROR(x, args...) LOG_E(S1AP, x, ##args) +# define S1AP_WARN(x, args...) LOG_W(S1AP, x, ##args) +# define S1AP_TRAF(x, args...) LOG_T(S1AP, x, ##args) +# define S1AP_DEBUG(x, args...) LOG_D(S1AP, x, ##args) +#else +# include "mme_default_values.h" +# define S1AP_ERROR(x, args...) do { fprintf(stdout, "[S1AP][E]"x, ##args); } while(0) +# define S1AP_WARN(x, args...) do { fprintf(stdout, "[S1AP][W]"x, ##args); } while(0) +# define S1AP_TRAF(x, args...) do { fprintf(stdout, "[S1AP][T]"x, ##args); } while(0) +# define S1AP_DEBUG(x, args...) do { fprintf(stdout, "[S1AP][D]"x, ##args); } while(0) +#endif + +//Forward declaration +struct s1ap_message_s; + +/** \brief Function callback prototype. + **/ +#if defined(ENB_MODE) +typedef int (*s1ap_message_decoded_callback)( + eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p +); +#else +typedef int (*s1ap_message_decoded_callback)( + uint32_t assocId, + uint32_t stream, + struct s1ap_message_s *message_p +); +#endif +/** \brief Encode a successfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t s1ap_generate_successfull_outcome( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an initiating message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t s1ap_generate_initiating_message( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Encode an unsuccessfull outcome message + \param buffer pointer to buffer in which data will be encoded + \param length pointer to the length of buffer + \param procedureCode Procedure code for the message + \param criticality Criticality of the message + \param td ASN1C type descriptor of the sptr + \param sptr Deferenced pointer to the structure to encode + @returns size in bytes encded on success or 0 on failure + **/ +ssize_t s1ap_generate_unsuccessfull_outcome( + uint8_t **buffer, + uint32_t *length, + e_ProcedureCode procedureCode, + Criticality_t criticality, + asn_TYPE_descriptor_t *td, + void *sptr); + +/** \brief Generate a new IE + \param id Protocol ie id of the IE + \param criticality Criticality of the IE + \param type ASN1 type descriptor of the IE value + \param sptr Structure to be encoded in the value field + @returns a pointer to the newly created IE structure or NULL in case of failure + **/ +IE_t *s1ap_new_ie(ProtocolIE_ID_t id, + Criticality_t criticality, + asn_TYPE_descriptor_t *type, + void *sptr); + +/** \brief Handle criticality + \param criticality Criticality of the IE + @returns void + **/ +void s1ap_handle_criticality(e_Criticality criticality); + +#endif /* S1AP_COMMON_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB.c b/openair-cn/S1AP/s1ap_eNB.c new file mode 100644 index 0000000000..68598cf3e0 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB.c @@ -0,0 +1,412 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "tree.h" +#include "queue.h" + +#include "mme_sim.h" +#include "eNB_default_values.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" + +#include "s1ap_eNB_defs.h" +#include "s1ap_eNB.h" +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_handlers.h" +#include "s1ap_eNB_nnsf.h" + +#include "s1ap_eNB_nas_procedures.h" +#include "s1ap_eNB_management_procedures.h" + +#include "sctp_primitives_client.h" + +#include "assertions.h" +#include "conversions.h" + +static int s1ap_eNB_generate_s1_setup_request(eNB_mme_desc_t *eNB_desc_p, + s1ap_eNB_mme_data_t *mme_assoc_p); + +RB_GENERATE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry, s1ap_eNB_compare_assoc_id); + +inline int s1ap_eNB_compare_assoc_id( + struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2) +{ + if (p1->sctp_data.assoc_id < p2->sctp_data.assoc_id) { + return -1; + } + if (p1->sctp_data.assoc_id > p2->sctp_data.assoc_id) { + return 1; + } + return 0; +} + +inline struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(eNB_mme_desc_t *eNB_desc_p, + uint32_t assoc_id) +{ + struct s1ap_eNB_mme_data_s temp; + + memset(&temp, 0, sizeof(struct s1ap_eNB_mme_data_s)); + + temp.sctp_data.assoc_id = assoc_id; + + return RB_FIND(s1ap_mme_map, &eNB_desc_p->s1ap_mme_head, &temp); +} + +int s1ap_run(eNB_mme_desc_t *eNB_desc_p) +{ + int ret = 0; + struct s1ap_eNB_mme_data_s *mme_p; + + DevAssert(eNB_desc_p != NULL); + + RB_FOREACH(mme_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) { + struct sctp_queue_item_s *item_p; + + /* Run the SCTP part for each MME */ + sctp_run(&mme_p->sctp_data); + + S1AP_DEBUG("Entering s1ap_run for eNB %d: %d packet(s) to handle\n", + eNB_desc_p->eNB_id, mme_p->sctp_data.queue_length); + + /* Handle every message in the queue */ + TAILQ_FOREACH(item_p, &mme_p->sctp_data.sctp_queue, entry) { + /* Handle the message in S1AP */ + s1ap_eNB_handle_message(eNB_desc_p, item_p); + /* Remove the packet from the list and update data */ + TAILQ_REMOVE(&mme_p->sctp_data.sctp_queue, item_p, entry); + ret += item_p->length; + mme_p->sctp_data.queue_size -= item_p->length; + mme_p->sctp_data.queue_length--; + /* Deallocate memory as the message has been handled */ + free(item_p->buffer); + free(item_p); + } + } + return ret; +} + +int s1ap_eNB_init(eNB_mme_desc_t *eNB_desc_p, + char **local_ip_addr, int nb_local_ip, + char **remote_ip_addr, int nb_remote_ip) +{ + int i; + sctp_data_t sctp_data; + char hostname[30]; + + DevAssert(eNB_desc_p != NULL); + + if (eNB_desc_p->eNB_id >= (1 << 20)) + S1AP_WARN("eNB_id exceed limit of 20 bits...\n"); + + if (gethostname(hostname, sizeof(hostname)) == -1) { + hostname[0] = '\0'; + } + + /* Set the eNB name */ + snprintf(eNB_desc_p->eNB_name, S1AP_ENB_NAME_LENGTH_MAX, + ENB_NAME " %s %u", hostname, eNB_desc_p->eNB_id & 0xFFFFF); + + S1AP_DEBUG("Initializing S1AP layer for eNB %u\n", + eNB_desc_p->eNB_id); + + /* TODO: RRM configuration... */ + eNB_desc_p->tac = ENB_TAC; + eNB_desc_p->mcc = ENB_MCC; + eNB_desc_p->mnc = ENB_MNC; + + RB_INIT(&eNB_desc_p->s1ap_mme_head); + RB_INIT(&eNB_desc_p->s1ap_ue_head); + + memset(&sctp_data, 0, sizeof(sctp_data_t)); + + for (i = 0; i < nb_remote_ip; i++) + { + /* Connecting eNB to provided MME IP address and port */ + if (sctp_connect_to_remote_host(local_ip_addr, nb_local_ip, + remote_ip_addr[i], S1AP_PORT_NUMBER, + SOCK_STREAM, &sctp_data) <= 0) + { + S1AP_ERROR("Failed to connect to %s:%d\n", + remote_ip_addr[i], S1AP_PORT_NUMBER); + return -1; + } else { + struct s1ap_eNB_mme_data_s *mme_assoc_p; + struct s1ap_eNB_mme_data_s *collision_p; + + mme_assoc_p = calloc(1, sizeof(struct s1ap_eNB_mme_data_s)); + mme_assoc_p->nextstream = 1; + + memcpy(&mme_assoc_p->sctp_data, &sctp_data, sizeof(sctp_data_t)); + + TAILQ_INIT(&mme_assoc_p->sctp_data.sctp_queue); + + if ((collision_p = RB_INSERT(s1ap_mme_map, &eNB_desc_p->s1ap_mme_head, + mme_assoc_p)) != NULL) { + S1AP_WARN("Failed to add MME to the tree of associated MME\n"); + free(mme_assoc_p); + return -1; + } + + S1AP_DEBUG("[%d] Successfully added MME to the list of known host\n", + sctp_data.assoc_id); + S1AP_DEBUG("[%d] Now tries to send S1 setup request\n", + sctp_data.assoc_id); + + STAILQ_INIT(&mme_assoc_p->served_gummei); + if (s1ap_eNB_generate_s1_setup_request(eNB_desc_p, mme_assoc_p) == -1) + { + exit(EXIT_FAILURE); + } + } + } + + S1AP_DEBUG("Initializing S1AP layer for eNB %d: DONE\n", eNB_desc_p->eNB_id); + return 0; +} + +static int s1ap_eNB_generate_s1_setup_request( + eNB_mme_desc_t *eNB_desc_p, + s1ap_eNB_mme_data_t *mme_assoc_p) +{ + s1ap_message message; + S1SetupRequestIEs_t *s1SetupRequest_p; + PLMNidentity_t plmnIdentity; + SupportedTAs_Item_t ta; + uint8_t *buffer; + uint32_t len; + int ret; + + DevAssert(eNB_desc_p != NULL); + DevAssert(mme_assoc_p != NULL); + + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_initiatingMessage; + message.procedureCode = ProcedureCode_id_S1Setup; + + s1SetupRequest_p = &message.msg.s1SetupRequestIEs; + memset((void *)&plmnIdentity, 0, sizeof(PLMNidentity_t)); + + memset((void *)&ta, 0, sizeof(SupportedTAs_Item_t)); + + mme_assoc_p->state = S1AP_ENB_STATE_WAITING; + + s1SetupRequest_p->global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID; + MACRO_ENB_ID_TO_BIT_STRING(eNB_desc_p->eNB_id, + &s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID); + MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc, + &s1SetupRequest_p->global_ENB_ID.pLMNidentity); + + INT16_TO_OCTET_STRING(eNB_desc_p->tac, &ta.tAC); + MCC_MNC_TO_TBCD(eNB_desc_p->mcc, eNB_desc_p->mnc, &plmnIdentity); + + ASN_SEQUENCE_ADD(&ta.broadcastPLMNs.list, &plmnIdentity); + ASN_SEQUENCE_ADD(&s1SetupRequest_p->supportedTAs.list, &ta); + + s1SetupRequest_p->defaultPagingDRX = PagingDRX_v64; + + if (eNB_desc_p->eNB_name != NULL) { + s1SetupRequest_p->presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT; + OCTET_STRING_fromBuf(&s1SetupRequest_p->eNBname, eNB_desc_p->eNB_name, + strlen(eNB_desc_p->eNB_name)); + } + + if (s1ap_eNB_encode_pdu(&message, &buffer, &len) < 0) { + S1AP_ERROR("Failed to encode S1 setup request\n"); + return -1; + } + + if ((ret = sctp_send_msg(&mme_assoc_p->sctp_data, S1AP_SCTP_PPID, 0, buffer, + len)) < 0) { + S1AP_ERROR("Failed to send S1 setup request\n"); + } + free(buffer); + return ret; +} + +int s1ap_eNB_generate_initial_UE_message(eNB_mme_desc_t *eNB_desc_p, + s1ap_nas_first_req_t nas_req_p) +{ + s1ap_message message; + struct s1ap_eNB_mme_data_s *mme_desc_p; + struct s1ap_eNB_ue_context_s *ue_desc_p; + InitialUEMessageIEs_t *initial_ue_message_p; + + uint8_t *buffer; + uint32_t length; + + DevAssert(eNB_desc_p != NULL); + + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_initiatingMessage; + message.procedureCode = ProcedureCode_id_initialUEMessage; + + initial_ue_message_p = &message.msg.initialUEMessageIEs; + + /* Select the MME corresponding to the provided GUMMEI. + * If no MME corresponds to the GUMMEI, the function selects the MME with the + * highest capacity. + * In case eNB has no MME associated, the eNB should inform RRC and discard + * this request. + */ + if (nas_req_p.ue_identity.present == GUMMEI_PROVIDED) { + mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei( + eNB_desc_p, + nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.gummei); + } else { + mme_desc_p = s1ap_eNB_nnsf_select_mme_by_mme_code( + eNB_desc_p, + nas_req_p.establishment_cause, nas_req_p.ue_identity.identity.s_tmsi.mme_code); + } + if (mme_desc_p == NULL) { + S1AP_WARN("No MME is associated to the eNB\n"); + // TODO: Inform RRC + return -1; + } + + /* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value + * will be used for the duration of the connectivity. + */ + if ((ue_desc_p = s1ap_eNB_allocate_new_UE_context()) == NULL) { + return -1; + } + + /* Keep a reference to the selected MME */ + ue_desc_p->mme_ref = mme_desc_p; + ue_desc_p->rnti = nas_req_p.rnti; + + do { + struct s1ap_eNB_ue_context_s *collision_p; + + /* Peek a random value for the eNB_ue_s1ap_id */ + ue_desc_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff; + if ((collision_p = RB_INSERT(s1ap_ue_map, &eNB_desc_p->s1ap_ue_head, ue_desc_p)) + == NULL) { + /* Break the loop as the id is not already used by another UE */ + break; + } + } while(1); + + initial_ue_message_p->eNB_UE_S1AP_ID = ue_desc_p->eNB_ue_s1ap_id; + /* Prepare the NAS PDU */ + initial_ue_message_p->nas_pdu.buf = nas_req_p.nas_pdu.buffer; + initial_ue_message_p->nas_pdu.size = nas_req_p.nas_pdu.length; + + /* Set the establishment cause according to those provided by RRC */ + DevCheck(nas_req_p.establishment_cause <= RRC_CAUSE_MAX, + nas_req_p.establishment_cause, 0, 0); + initial_ue_message_p->rrC_Establishment_Cause = nas_req_p.establishment_cause; + + if (nas_req_p.ue_identity.present == S_TMSI_PROVIDED) { + initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_S_TMSI_PRESENT; + + MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.mme_code, + &initial_ue_message_p->s_tmsi.mMEC); + M_TMSI_TO_OCTET_STRING(nas_req_p.ue_identity.identity.s_tmsi.m_tmsi, + &initial_ue_message_p->s_tmsi.m_TMSI); + } else { + initial_ue_message_p->presenceMask |= INITIALUEMESSAGEIES_GUMMEI_ID_PRESENT; + + MCC_MNC_TO_PLMNID(nas_req_p.ue_identity.identity.gummei.mcc, + nas_req_p.ue_identity.identity.gummei.mnc, + &initial_ue_message_p->gummei_id.pLMN_Identity); + MME_GID_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_group_id, + &initial_ue_message_p->gummei_id.mME_Group_ID); + MME_CODE_TO_OCTET_STRING(nas_req_p.ue_identity.identity.gummei.mme_code, + &initial_ue_message_p->gummei_id.mME_Code); + } + + /* Assuming TAI is the TAI from the cell */ + INT16_TO_OCTET_STRING(eNB_desc_p->tac, &initial_ue_message_p->tai.tAC); + MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc, + &initial_ue_message_p->tai.pLMNidentity); + + /* Set the EUTRAN CGI + * The cell identity is defined on 28 bits but as we use macro enb id, + * we have to pad. + */ + MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id, + &initial_ue_message_p->eutran_cgi.cell_ID); + MCC_MNC_TO_TBCD(eNB_desc_p->mcc, eNB_desc_p->mnc, + &initial_ue_message_p->eutran_cgi.pLMNidentity); + + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + /* Failed to encode message */ + return -1; + } + + /* Update the current S1AP UE state */ + ue_desc_p->ue_state = S1AP_UE_WAITING_CSR; + + /* Send encoded message over sctp */ + return sctp_send_msg(&mme_desc_p->sctp_data, S1AP_SCTP_PPID, 1, buffer, length); +} + +int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p, + s1ap_rrc_api_req_t *api_req_p) +{ + int ret = -1; + + DevAssert(eNB_desc_p != NULL); + DevAssert(api_req_p != NULL); + + switch(api_req_p->api_req) { + case S1AP_API_NAS_FIRST_REQ: + return s1ap_eNB_generate_initial_UE_message(eNB_desc_p, + api_req_p->msg.first_nas_req); + case S1AP_API_NAS_UPLINK: + return s1ap_eNB_nas_uplink(eNB_desc_p, &api_req_p->msg.nas_uplink); + case S1AP_API_UE_CAP_INFO_IND: + return s1ap_eNB_ue_capabilities(eNB_desc_p, &api_req_p->msg.ue_cap_info_ind); + case S1AP_API_INITIAL_CONTEXT_SETUP_RESP: + return s1ap_eNB_initial_ctxt_resp(eNB_desc_p, &api_req_p->msg.initial_ctxt_resp); + case S1AP_API_NAS_NON_DELIVERY_IND: + case S1AP_API_PATH_SWITCH_REQ: + case S1AP_API_INITIAL_CONTEXT_SETUP_FAIL: + case S1AP_API_E_RAB_SETUP_RESP: + case S1AP_API_E_RAB_MODIFY_RESP: + case S1AP_API_E_RAB_RELEASE_RESP: + case S1AP_API_RESET: + case S1AP_API_RESET_ACK: + S1AP_ERROR("This API type (%02x) is not implemented yet\n", + api_req_p->api_req); + break; + default: + S1AP_ERROR("Unknown API type %02x\n", api_req_p->api_req); + break; + } + return ret; +} diff --git a/openair-cn/S1AP/s1ap_eNB.h b/openair-cn/S1AP/s1ap_eNB.h new file mode 100644 index 0000000000..b46b2bf22b --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB.h @@ -0,0 +1,131 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdint.h> + +#include "tree.h" +#include "queue.h" + +#include "mme_sim.h" +#include "s1ap_eNB_defs.h" + +#ifndef S1AP_ENB_H_ +#define S1AP_ENB_H_ + +/* Served PLMN identity element */ +struct plmn_identity_s { + uint16_t mcc; + uint16_t mnc; + STAILQ_ENTRY(plmn_identity_s) next; +}; + +/* Served group id element */ +struct served_group_id_s { + uint16_t mme_group_id; + STAILQ_ENTRY(served_group_id_s) next; +}; + +/* Served mme code for a particular MME */ +struct mme_code_s { + uint8_t mme_code; + STAILQ_ENTRY(mme_code_s) next; +}; + +/* Served gummei element */ +struct served_gummei_s { + /* Number of MME served PLMNs */ + uint8_t nb_served_plmns; + /* List of served PLMNs by MME */ + STAILQ_HEAD(served_plmns_s, plmn_identity_s) served_plmns; + + /* Number of group id in list */ + uint8_t nb_group_id; + /* Served group id list */ + STAILQ_HEAD(served_group_ids_s, served_group_id_s) served_group_ids; + + /* Number of MME code */ + uint8_t nb_mme_code; + /* MME Code to uniquely identify an MME within an MME pool area */ + STAILQ_HEAD(mme_codes_s, mme_code_s) mme_codes; + + /* Next GUMMEI element */ + STAILQ_ENTRY(served_gummei_s) next; +}; + +/* This structure describes association of a eNB to a MME */ +typedef struct s1ap_eNB_mme_data_s { + /* This is the optional name provided by the MME */ + char *mme_name; + + /* Remote MME IP addr */ + char *ip_addr; + + /* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max + * number of 8 RATs but in our case only one is used. The LTE related pool + * configuration is included on the first place in the list. + */ + STAILQ_HEAD(served_gummeis_s, served_gummei_s) served_gummei; + + /* Relative processing capacity of an MME with respect to the other MMEs + * in the pool in order to load-balance MMEs within a pool as defined + * in TS 23.401. + */ + uint8_t relative_mme_capacity; + + /* Current MME overload information (if any). */ + s1ap_overload_state_t overload_state; + /* Current eNB->MME S1AP association state */ + s1ap_eNB_state_t state; + + /* SCTP related data for this MME */ + sctp_data_t sctp_data; + /* Next usable stream for UE signalling */ + int32_t nextstream; + + /* MME descriptors tree, ordered by sctp assoc id */ + RB_ENTRY(s1ap_eNB_mme_data_s) entry; +} s1ap_eNB_mme_data_t; + +inline int s1ap_eNB_compare_assoc_id( + struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2); + +/* Generate the tree management functions */ +RB_PROTOTYPE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry, + s1ap_eNB_compare_assoc_id); + +struct s1ap_eNB_mme_data_s *s1ap_eNB_get_MME(eNB_mme_desc_t *eNB_desc_p, + uint32_t assocId); + +int s1ap_eNB_init(eNB_mme_desc_t *eNB_desc_p, + char *local_ip_addr[], int nb_local_ip, + char *remote_ip_addr[], int nb_remote_ip); + +#endif /* S1AP_ENB_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_decoder.c b/openair-cn/S1AP/s1ap_eNB_decoder.c new file mode 100644 index 0000000000..072a98febf --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_decoder.c @@ -0,0 +1,149 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_decoder.c + * \brief s1ap pdu decode procedures for eNB + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +#include <stdio.h> + +#include "assertions.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_decoder.h" + +static int s1ap_eNB_decode_initiating_message(s1ap_message *message, + InitiatingMessage_t *initiating_p) +{ + DevAssert(initiating_p != NULL); + + message->procedureCode = initiating_p->procedureCode; + message->criticality = initiating_p->criticality; + + switch(initiating_p->procedureCode) { + case ProcedureCode_id_downlinkNASTransport: + return s1ap_decode_downlinknastransporties(&message->msg.downlinkNASTransportIEs, + &initiating_p->value); + case ProcedureCode_id_InitialContextSetup: + return s1ap_decode_initialcontextsetuprequesties( + &message->msg.initialContextSetupRequestIEs, &initiating_p->value); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for initiating message\n", + (int)initiating_p->procedureCode); + break; + } + return -1; +} + +static int s1ap_eNB_decode_successful_outcome(s1ap_message *message, + SuccessfulOutcome_t *successfullOutcome_p) +{ + DevAssert(successfullOutcome_p != NULL); + + message->procedureCode = successfullOutcome_p->procedureCode; + message->criticality = successfullOutcome_p->criticality; + + switch(successfullOutcome_p->procedureCode) { + case ProcedureCode_id_S1Setup: + return s1ap_decode_s1setupresponseies(&message->msg.s1SetupResponseIEs, + &successfullOutcome_p->value); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for successfull outcome message\n", + (int)successfullOutcome_p->procedureCode); + break; + } + return -1; +} + +static int s1ap_eNB_decode_unsuccessful_outcome(s1ap_message *message, + UnsuccessfulOutcome_t *unSuccessfullOutcome_p) +{ + DevAssert(unSuccessfullOutcome_p != NULL); + + message->procedureCode = unSuccessfullOutcome_p->procedureCode; + message->criticality = unSuccessfullOutcome_p->criticality; + + switch(unSuccessfullOutcome_p->procedureCode) { + case ProcedureCode_id_S1Setup: + return s1ap_decode_s1setupfailureies(&message->msg.s1SetupFailureIEs, + &unSuccessfullOutcome_p->value); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)unSuccessfullOutcome_p->procedureCode); + break; + } + return -1; +} + +int s1ap_eNB_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t length) +{ + S1AP_PDU_t pdu; + S1AP_PDU_t *pdu_p = &pdu; + asn_dec_rval_t dec_ret; + + DevAssert(buffer != NULL); + + memset((void *)pdu_p, 0, sizeof(S1AP_PDU_t)); + + dec_ret = aper_decode(NULL, + &asn_DEF_S1AP_PDU, + (void **)&pdu_p, + buffer, + length, + 0, + 0); + + if (dec_ret.code != RC_OK) { + S1AP_ERROR("Failed to decode pdu\n"); + return -1; + } + + message->direction = pdu_p->present; + + switch(pdu_p->present) { + case S1AP_PDU_PR_initiatingMessage: + return s1ap_eNB_decode_initiating_message(message, + &pdu_p->choice.initiatingMessage); + case S1AP_PDU_PR_successfulOutcome: + return s1ap_eNB_decode_successful_outcome(message, + &pdu_p->choice.successfulOutcome); + case S1AP_PDU_PR_unsuccessfulOutcome: + return s1ap_eNB_decode_unsuccessful_outcome(message, + &pdu_p->choice.unsuccessfulOutcome); + default: + S1AP_DEBUG("Unknown presence (%d) or not implemented\n", (int)pdu_p->present); + break; + } + return -1; +} diff --git a/openair-cn/S1AP/s1ap_eNB_decoder.h b/openair-cn/S1AP/s1ap_eNB_decoder.h new file mode 100644 index 0000000000..37745f79ab --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_decoder.h @@ -0,0 +1,40 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> +#include "s1ap_ies_defs.h" + +#ifndef S1AP_ENB_DECODER_H_ +#define S1AP_ENB_DECODER_H_ + +int s1ap_eNB_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t length) +__attribute__ ((warn_unused_result)); + +#endif /* S1AP_ENB_DECODER_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_defs.h b/openair-cn/S1AP/s1ap_eNB_defs.h new file mode 100644 index 0000000000..1e6c38155b --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_defs.h @@ -0,0 +1,336 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "queue.h" +#include "tree.h" + +#include "sctp_eNB_defs.h" + +#ifndef S1AP_ENB_DEFS_H_ +#define S1AP_ENB_DEFS_H_ + +#define S1AP_ENB_NAME_LENGTH_MAX (150) + +typedef enum { + /* Disconnected state: initial state for any association. */ + S1AP_ENB_STATE_DISCONNECTED = 0x0, + /* State waiting for S1 Setup response message if eNB is MME accepted or + * S1 Setup failure if MME rejects the eNB. + */ + S1AP_ENB_STATE_WAITING = 0x1, + /* The eNB is successfully connected to MME, UE contexts can be created. */ + S1AP_ENB_STATE_CONNECTED = 0x2, + /* The MME has sent an overload start message. Once the MME disables the + * OVERLOAD marker, the state of the association will be + * S1AP_ENB_STATE_CONNECTED. + */ + S1AP_ENB_OVERLOAD = 0x3, + /* Max number of states available */ + S1AP_ENB_STATE_MAX, +} s1ap_eNB_state_t; + +/* If the Overload Action IE in the OVERLOAD START message is set to + * - “reject all RRC connection establishments for non-emergency mobile + * originated data transfer “ (i.e. reject traffic corresponding to RRC cause + * “mo-data “ (TS 36.331 [16])), or + * - “reject all RRC connection establishments for signalling “ (i.e. reject + * traffic corresponding to RRC cause “modata†and “mo-signalling†+ * (TS 36.331 [16])),or + * - “only permit RRC connection establishments for emergency sessions and + * mobile terminated services†(i.e. only permit traffic corresponding to RRC + * cause “emergency†and “mt-Access†(TS 36.331 [16])). + * + * NOTE: When the Overload Action IE is set to “only permit RRC connection + * establishments for emergency sessions and mobile terminated servicesâ€, + * emergency calls with RRC cause “highPriorityAcess†from high priority users + * are rejected (TS 24.301 [24]). + */ +typedef enum { + S1AP_OVERLOAD_REJECT_MO_DATA = 0x0, + S1AP_OVERLOAD_REJECT_ALL_SIGNALLING = 0x1, + S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT = 0x2, + S1AP_NO_OVERLOAD = 0x3, + S1AP_OVERLOAD_MAX, +} s1ap_overload_state_t; + +typedef enum { + PAGING_DRX_32 = 0x0, + PAGING_DRX_64 = 0x1, + PAGING_DRX_128 = 0x2, + PAGING_DRX_256 = 0x3, +} paging_drx_t; + +typedef struct { + /* Octet string data */ + uint8_t *buffer; + /* Length of the octet string */ + uint32_t length; +} nas_pdu_t, ue_radio_cap_t; + +typedef struct { + uint16_t mcc; + uint16_t mnc; + uint8_t mme_code; + uint16_t mme_group_id; +} gummei_t; + +typedef struct { + uint8_t mme_code; + uint32_t m_tmsi; +} s_tmsi_t; + +/* Provides the establishment cause for the RRC connection request as provided + * by the upper layers. W.r.t. the cause value names: highPriorityAccess + * concerns AC11..AC15, ‘mt’ stands for ‘Mobile Terminating’ and ‘mo’ for + * 'Mobile Originating'. Defined in TS 36.331. + */ +typedef enum { + RRC_CAUSE_EMERGENCY = 0x0, + RRC_CAUSE_HIGH_PRIO_ACCESS = 0x1, + RRC_CAUSE_MT_ACCESS = 0x2, + RRC_CAUSE_MO_SIGNALLING = 0x3, + RRC_CAUSE_MO_DATA = 0x4, + RRC_CAUSE_MAX = RRC_CAUSE_MO_DATA, +} rrc_establishment_cause_t; + +typedef struct { + uint8_t qci; + +} e_rab_level_qos_parameter_t; + +typedef struct { + /* Length of the transport layer address buffer. S1AP layer received a + * bit string<1..160> containing one of the following addresses: ipv4, + * ipv6, or ipv4 and ipv6. The layer doesn't interpret the buffer but + * silently forward it to S1-U. + */ + uint8_t length; + uint8_t buffer[20]; +} transport_layer_addr_t; + +typedef struct { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; + /* Quality of service for this e_rab */ + e_rab_level_qos_parameter_t qos; + /* The NAS PDU should be forwarded by the RRC layer to the NAS layer */ + nas_pdu_t nas_pdu; + /* The transport layer address for the IP packets */ + transport_layer_addr_t sgw_addr; + /* S-GW Tunnel endpoint identifier */ + uint32_t gtp_teid; +} e_rab_t; + +typedef struct { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; + /* The transport layer address for the IP packets */ + transport_layer_addr_t eNB_addr; + /* S-GW Tunnel endpoint identifier */ + uint32_t gtp_teid; +} e_rab_setup_t; + +typedef struct { + /* Unique e_rab_id for the UE. */ + uint8_t e_rab_id; + /* Cause of the failure */ +// cause_t cause; +} e_rab_failed_t; + +typedef struct { +#define S_TMSI_PROVIDED 0x0 +#define GUMMEI_PROVIDED 0x1 + unsigned present:1; + union { + gummei_t gummei; + s_tmsi_t s_tmsi; + } identity; +} ue_identity_t; + +typedef struct { + /* The NAS First Req is the first message exchanged between RRC and S1AP + * for an UE. + * The rnti uniquely identifies an UE within a cell. Later the enb_ue_s1ap_id + * will be the unique identifier used between RRC and S1AP. + */ + uint16_t rnti; + + rrc_establishment_cause_t establishment_cause; + nas_pdu_t nas_pdu; + /* If this flag is set S1AP layer is expecting the GUMMEI. If = 0, + * the temporary s-tmsi is used. + */ + ue_identity_t ue_identity; +} s1ap_nas_first_req_t; + +typedef struct { + unsigned eNB_ue_s1ap_id:24; + nas_pdu_t nas_pdu; +} s1ap_nas_uplink_t; + +typedef struct { + nas_pdu_t nas_pdu; +// cause_t cause; +} s1ap_nas_non_delivery_t; + +typedef struct { + uint16_t rnti; + unsigned eNB_ue_s1ap_id:24; + + /* Number of e_rab to be setup in the list */ + uint8_t nb_of_e_rabs; + /* list of e_rab to be setup by RRC layers */ + e_rab_t **e_rab_param; +} s1ap_e_rab_setup_req_t, +s1ap_initial_ctxt_setup_req_t; + +typedef struct { + unsigned eNB_ue_s1ap_id:24; + ue_radio_cap_t ue_radio_cap; +} s1ap_ue_cap_info_ind_t; + +typedef struct { + unsigned eNB_ue_s1ap_id:24; + + /* Number of e_rab setup-ed in the list */ + uint8_t nb_of_e_rabs; + /* list of e_rab setup-ed by RRC layers */ + e_rab_setup_t *e_rabs; + /* Number of e_rab failed to be setup in list */ + uint8_t nb_of_e_rabs_failed; + /* list of e_rabs that failed to be setup */ + e_rab_failed_t *e_rabs_failed; +} s1ap_initial_ctxt_setup_resp_t; + +typedef enum { + /** RRC -> S1AP API **/ +#define S1AP_API_REQ_IS_INPUT(x) (x & 0x10) + /* RRC should use this api request for the first NAS message */ + S1AP_API_NAS_FIRST_REQ = 0x10, + /* NAS messages with no context activation */ + S1AP_API_NAS_UPLINK = 0x11, + /* When the eNB decides to not start the delivery of a NAS message that has + * been received over a UE-associated logical S1-connection or the eNB is + * unable to ensure that the message has been received by the UE, it shall + * report the non-delivery of this NAS message. + */ + S1AP_API_NAS_NON_DELIVERY_IND = 0x12, + /* This message is sent by the eNB to request the MME to switch DL GTP + * tunnel termination point(s) from one end-point to another. + */ + S1AP_API_PATH_SWITCH_REQ = 0x13, + /* This message is used to report the outcome of the request from the + * S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ API request. + */ + S1AP_API_INITIAL_CONTEXT_SETUP_RESP = 0x14, + /* This message is used to report the unsuccessfull outcome of the request + * from the S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ API request. + */ + S1AP_API_INITIAL_CONTEXT_SETUP_FAIL = 0x15, + /* This message is used to report the outcome of the request from the + * S1AP_API_INITIAL_CONTEXT_SETUP_REQ API request. + */ + S1AP_API_E_RAB_SETUP_RESP = 0x16, + /* This message is used to report the outcome of the request from the + * S1AP_API_E_RAB_SETUP_REQ API request. + */ + S1AP_API_E_RAB_MODIFY_RESP = 0x17, + /* This message is used to report the outcome of the request from the + * S1AP_API_E_RAB_MODIFY_REQ API request. + */ + S1AP_API_E_RAB_RELEASE_RESP = 0x18, + /* The purpose of the UE Capability Info Indication procedure is to enable + * the eNB to provide to the MME UE capability-related information. + */ + S1AP_API_UE_CAP_INFO_IND = 0x19, + + /** S1AP -> RRC API **/ +#define S1AP_API_REQ_IS_OUTPUT(x) (x & 0x20) + /* S1AP layer received a valid downlink info transfer message */ + S1AP_API_NAS_DOWNLINK = 0x20, + /* The purpose of the Initial Context Setup procedure is to establish the + * necessary overall initial UE Context including ERAB context, the Security + * Key, Handover Restriction List, UE Radio capability and UE Security + * Capabilities etc. + */ + S1AP_API_NAS_INITIAL_CONTEXT_SETUP_REQ = 0x21, + /* The purpose of the E-RAB Setup procedure is to assign resources on Uu and + * S1 for one or several E-RABs and to setup corresponding Data Radio + * Bearers for a given UE. + */ + S1AP_API_E_RAB_SETUP_REQ = 0x22, + /* This message is sent by the MME and is used to request the eNB to modify + * the Data Radio Bearers and the allocated resources on Uu and S1 for one + * or several E-RABs. + */ + S1AP_API_E_RAB_MODIFY_REQ = 0x23, + /* This message is sent by the MME and is used to request the eNB to release + * allocated resources on Uu and S1 for one or several E-RABs. + */ + S1AP_API_E_RAB_RELEASE_REQ = 0x24, + + /** S1AP <-> RRC API **/ + /** Messages below are bi-directionnal and can be triggered by both RRC and + * S1AP. + **/ +#define S1AP_API_REQ_IS_BIDIR(x) (x & 0x40) + /* At reception of RESET message, the eNB (or MME) shall release all + * allocated resources on S1 and Uu related to the UE association(s) + * indicated explicitly or implicitly in the RESET message and remove the + * indicated UE contexts including S1AP ID. + */ + S1AP_API_RESET = 0x40, + S1AP_API_RESET_ACK = 0x41, +} s1ap_rrc_api_req_type_t; + +typedef struct { + /* The API request type */ + s1ap_rrc_api_req_type_t api_req; + union { + /** RRC -> S1AP requests **/ + s1ap_nas_first_req_t first_nas_req; + s1ap_nas_uplink_t nas_uplink; + s1ap_initial_ctxt_setup_resp_t initial_ctxt_resp; + s1ap_nas_non_delivery_t nas_non_delivery; + s1ap_ue_cap_info_ind_t ue_cap_info_ind; + /** S1AP -> RRC requests **/ + s1ap_e_rab_setup_req_t e_rab_setup_req; + s1ap_initial_ctxt_setup_req_t initial_ctxt_setup_req; + } msg; +} s1ap_rrc_api_req_t; + +/* Callback notifier. + * Called when a new event has to be notified between S1AP -> RRC + */ +typedef int (*rrc_event_notify_t)(s1ap_rrc_api_req_t *api_req); + +#endif /* S1AP_ENB_DEFS_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_encoder.c b/openair-cn/S1AP/s1ap_eNB_encoder.c new file mode 100644 index 0000000000..48cadebda2 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_encoder.c @@ -0,0 +1,300 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_encoder.c + * \brief s1ap pdu encode procedures for eNB + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +#include <stdio.h> +#include <string.h> + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_encoder.h" + +#include "assertions.h" +#include "conversions.h" + +static inline int s1ap_eNB_encode_initiating(s1ap_message *message, + uint8_t **buffer, + uint32_t *len); +static inline int s1ap_eNB_encode_successfull_outcome(s1ap_message *message, + uint8_t **buffer, uint32_t *len); +static inline int s1ap_eNB_encode_unsuccessfull_outcome(s1ap_message *message, + uint8_t **buffer, uint32_t *len); +static inline int s1ap_eNB_encode_s1_setup_request(S1SetupRequestIEs_t + *s1SetupRequestIEs, uint8_t **buffer, uint32_t *length); +static inline int s1ap_eNB_encode_trace_failure(TraceFailureIndicationIEs_t + *trace_failure_ies_p, uint8_t **buffer, + uint32_t *length); +static inline int s1ap_eNB_encode_initial_ue_message(InitialUEMessageIEs_t + *initialUEmessageIEs_p, uint8_t **buffer, + uint32_t *length); +static inline int s1ap_eNB_encode_uplink_nas_transport(UplinkNASTransportIEs_t + *uplinkNASTransportIEs, + uint8_t **buffer, + uint32_t *length); +static inline int s1ap_eNB_encode_ue_capability_info_indication( + UECapabilityInfoIndicationIEs_t *ueCapabilityInfoIndicationIEs, + uint8_t **buffer, + uint32_t *length); +static inline int s1ap_eNB_encode_initial_context_setup_response( + InitialContextSetupResponseIEs_t *initialContextSetupResponseIEs, + uint8_t **buffer, + uint32_t *length); + +int s1ap_eNB_encode_pdu(s1ap_message *message, uint8_t **buffer, uint32_t *len) +{ + DevAssert(message != NULL); + DevAssert(buffer != NULL); + DevAssert(len != NULL); + + switch(message->direction) { + case S1AP_PDU_PR_initiatingMessage: + return s1ap_eNB_encode_initiating(message, buffer, len); + case S1AP_PDU_PR_successfulOutcome: + return s1ap_eNB_encode_successfull_outcome(message, buffer, len); + case S1AP_PDU_PR_unsuccessfulOutcome: + return s1ap_eNB_encode_unsuccessfull_outcome(message, buffer, len); + default: + S1AP_DEBUG("Unknown message outcome (%d) or not implemented", + (int)message->direction); + break; + } + return -1; +} + +static inline +int s1ap_eNB_encode_initiating(s1ap_message *message, + uint8_t **buffer, + uint32_t *len) +{ + switch(message->procedureCode) { + case ProcedureCode_id_S1Setup: + return s1ap_eNB_encode_s1_setup_request(&message->msg.s1SetupRequestIEs, + buffer, len); + case ProcedureCode_id_uplinkNASTransport: + return s1ap_eNB_encode_uplink_nas_transport(&message->msg.uplinkNASTransportIEs, + buffer, len); + case ProcedureCode_id_UECapabilityInfoIndication: + return s1ap_eNB_encode_ue_capability_info_indication( + &message->msg.ueCapabilityInfoIndicationIEs, + buffer, len); + case ProcedureCode_id_initialUEMessage: + return s1ap_eNB_encode_initial_ue_message( + &message->msg.initialUEMessageIEs, + buffer, len); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for initiating message\n", + (int)message->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_eNB_encode_successfull_outcome(s1ap_message *message, + uint8_t **buffer, uint32_t *len) +{ + switch(message->procedureCode) { + case ProcedureCode_id_InitialContextSetup: + return s1ap_eNB_encode_initial_context_setup_response( + &message->msg.initialContextSetupResponseIEs, + buffer, len); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for successfull outcome message\n", + (int)message->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_eNB_encode_unsuccessfull_outcome(s1ap_message *message, + uint8_t **buffer, uint32_t *len) +{ + switch(message->procedureCode) { + default: + S1AP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)message->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_eNB_encode_ue_capability_info_indication( + UECapabilityInfoIndicationIEs_t *ueCapabilityInfoIndicationIEs, + uint8_t **buffer, + uint32_t *length) +{ + UECapabilityInfoIndication_t ueCapabilityInfoIndication; + UECapabilityInfoIndication_t *ueCapabilityInfoIndication_p = + &ueCapabilityInfoIndication; + + memset((void *)ueCapabilityInfoIndication_p, 0, + sizeof(UECapabilityInfoIndication_t)); + + if (s1ap_encode_uecapabilityinfoindicationies(ueCapabilityInfoIndication_p, + ueCapabilityInfoIndicationIEs) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_UECapabilityInfoIndication, + Criticality_ignore, + &asn_DEF_UECapabilityInfoIndication, + ueCapabilityInfoIndication_p); +} + +static inline +int s1ap_eNB_encode_uplink_nas_transport(UplinkNASTransportIEs_t + *uplinkNASTransportIEs, + uint8_t **buffer, + uint32_t *length) +{ + UplinkNASTransport_t uplinkNASTransport; + UplinkNASTransport_t *uplinkNASTransport_p = &uplinkNASTransport; + + memset((void *)uplinkNASTransport_p, 0, sizeof(UplinkNASTransport_t)); + + if (s1ap_encode_uplinknastransporties(uplinkNASTransport_p, + uplinkNASTransportIEs) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_uplinkNASTransport, + Criticality_ignore, + &asn_DEF_UplinkNASTransport, + uplinkNASTransport_p); +} + +static inline +int s1ap_eNB_encode_s1_setup_request(S1SetupRequestIEs_t + *s1SetupRequestIEs, + uint8_t **buffer, + uint32_t *length) +{ + S1SetupRequest_t s1SetupRequest; + S1SetupRequest_t *s1SetupRequest_p = &s1SetupRequest; + + memset((void *)s1SetupRequest_p, 0, sizeof(S1SetupRequest_t)); + + if (s1ap_encode_s1setuprequesties(s1SetupRequest_p, s1SetupRequestIEs) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_S1Setup, + Criticality_reject, + &asn_DEF_S1SetupRequest, + s1SetupRequest_p); +} + +static inline +int s1ap_eNB_encode_initial_ue_message(InitialUEMessageIEs_t + *initialUEmessageIEs_p, + uint8_t **buffer, + uint32_t *length) +{ + InitialUEMessage_t initialUEMessage; + InitialUEMessage_t *initialUEMessage_p = &initialUEMessage; + + memset((void *)initialUEMessage_p, 0, sizeof(InitialUEMessage_t)); + + if (s1ap_encode_initialuemessageies(initialUEMessage_p, + initialUEmessageIEs_p) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_initialUEMessage, + Criticality_reject, + &asn_DEF_InitialUEMessage, + initialUEMessage_p); +} + +static inline +int s1ap_eNB_encode_trace_failure(TraceFailureIndicationIEs_t + *trace_failure_ies_p, + uint8_t **buffer, + uint32_t *length) +{ + TraceFailureIndication_t trace_failure; + TraceFailureIndication_t *trace_failure_p = &trace_failure; + + memset((void *)trace_failure_p, 0, sizeof(TraceFailureIndication_t)); + + if (s1ap_encode_tracefailureindicationies(trace_failure_p, + trace_failure_ies_p) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_TraceFailureIndication, + Criticality_reject, + &asn_DEF_TraceFailureIndication, + trace_failure_p); +} + +static inline +int s1ap_eNB_encode_initial_context_setup_response( + InitialContextSetupResponseIEs_t *initialContextSetupResponseIEs, + uint8_t **buffer, + uint32_t *length) +{ + InitialContextSetupResponse_t initial_context_setup_response; + InitialContextSetupResponse_t *initial_context_setup_response_p = + &initial_context_setup_response; + + memset((void *)initial_context_setup_response_p, 0, + sizeof(InitialContextSetupResponse_t)); + + if (s1ap_encode_initialcontextsetupresponseies(initial_context_setup_response_p, + initialContextSetupResponseIEs) < 0) { + return -1; + } + + return s1ap_generate_successfull_outcome(buffer, + length, + ProcedureCode_id_InitialContextSetup, + Criticality_reject, + &asn_DEF_InitialContextSetupResponse, + initial_context_setup_response_p); +} diff --git a/openair-cn/S1AP/s1ap_eNB_encoder.h b/openair-cn/S1AP/s1ap_eNB_encoder.h new file mode 100644 index 0000000000..9480851ae6 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_encoder.h @@ -0,0 +1,37 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_ENCODER_H_ +#define S1AP_ENB_ENCODER_H_ + +int s1ap_eNB_encode_pdu(s1ap_message *message, uint8_t **buffer, uint32_t *len) +__attribute__ ((warn_unused_result)); + +#endif /* S1AP_ENB_ENCODER_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.c b/openair-cn/S1AP/s1ap_eNB_handlers.c new file mode 100644 index 0000000000..fe3891f2bd --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_handlers.c @@ -0,0 +1,382 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_handlers.c + * \brief s1ap messages handlers for eNB part + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +#include <stdint.h> + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB.h" +#include "s1ap_eNB_handlers.h" +#include "s1ap_eNB_decoder.h" + +#include "s1ap_eNB_ue_context.h" +#include "s1ap_eNB_trace.h" +#include "s1ap_eNB_nas_procedures.h" + +#include "eNB_default_values.h" + +#include "conversions.h" + +//Forward declaration +struct s1ap_message_s; + +/* Handlers matrix. Only eNB related procedure present here */ +s1ap_message_decoded_callback messages_callback[][3] = { + { 0, 0, 0 }, /* HandoverPreparation */ + { 0, 0, 0 }, /* HandoverResourceAllocation */ + { 0, 0, 0 }, /* HandoverNotification */ + { 0, 0, 0 }, /* PathSwitchRequest */ + { 0, 0, 0 }, /* HandoverCancel */ + { 0, 0, 0 }, /* E_RABSetup */ + { 0, 0, 0 }, /* E_RABModify */ + { 0, 0, 0 }, /* E_RABRelease */ + { 0, 0, 0 }, /* E_RABReleaseIndication */ + { s1ap_eNB_handle_initial_context_request, 0, 0 }, /* InitialContextSetup */ + { 0, 0, 0 }, /* Paging */ + { s1ap_eNB_handle_nas_downlink, 0, 0 }, /* downlinkNASTransport */ + { 0, 0, 0 }, /* initialUEMessage */ + { 0, 0, 0 }, /* uplinkNASTransport */ + { 0, 0, 0 }, /* Reset */ + { 0, 0, 0 }, /* ErrorIndication */ + { 0, 0, 0 }, /* NASNonDeliveryIndication */ + { 0, s1ap_eNB_handle_s1_setup_response, 0 }, /* S1Setup */ + { 0, 0, 0 }, /* UEContextReleaseRequest */ + { 0, 0, 0 }, /* DownlinkS1cdma2000tunneling */ + { 0, 0, 0 }, /* UplinkS1cdma2000tunneling */ + { 0, 0, 0 }, /* UEContextModification */ + { 0, 0, 0 }, /* UECapabilityInfoIndication */ + { 0, 0, 0 }, /* UEContextRelease */ + { 0, 0, 0 }, /* eNBStatusTransfer */ + { 0, 0, 0 }, /* MMEStatusTransfer */ + { s1ap_eNB_handle_deactivate_trace, 0, 0 }, /* DeactivateTrace */ + { s1ap_eNB_handle_trace_start, 0, 0 }, /* TraceStart */ + { 0, 0, 0 }, /* TraceFailureIndication */ + { 0, 0, 0 }, /* ENBConfigurationUpdate */ + { 0, 0, 0 }, /* MMEConfigurationUpdate */ + { 0, 0, 0 }, /* LocationReportingControl */ + { 0, 0, 0 }, /* LocationReportingFailureIndication */ + { 0, 0, 0 }, /* LocationReport */ + { 0, 0, 0 }, /* OverloadStart */ + { 0, 0, 0 }, /* OverloadStop */ + { 0, 0, 0 }, /* WriteReplaceWarning */ + { 0, 0, 0 }, /* eNBDirectInformationTransfer */ + { 0, 0, 0 }, /* MMEDirectInformationTransfer */ + { 0, 0, 0 }, /* PrivateMessage */ + { 0, 0, 0 }, /* eNBConfigurationTransfer */ + { 0, 0, 0 }, /* MMEConfigurationTransfer */ + { 0, 0, 0 }, /* CellTrafficTrace */ +#if defined(UPDATE_RELEASE_9) + { 0, 0, 0 }, /* Kill */ + { 0, 0, 0 }, /* DownlinkUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* UplinkUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* DownlinkNonUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* UplinkNonUEAssociatedLPPaTransport */ +#endif +}; + +static const char *direction2String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; + +int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p) +{ + struct s1ap_message_s message; + + DevAssert(eNB_desc_p != NULL); + DevAssert(packet_p != NULL); + + if (packet_p->ppid != S1AP_SCTP_PPID) { + S1AP_ERROR("Received data on unexpected PPID %d, expecting %d\n", + packet_p->ppid, S1AP_SCTP_PPID); + return -1; + } + + memset(&message, 0, sizeof(struct s1ap_message_s)); + + if (s1ap_eNB_decode_pdu(&message, packet_p->buffer, packet_p->length) < 0) { + S1AP_ERROR("Failed to decode PDU\n"); + return -1; + } + /* Checking procedure Code and direction of message */ + if (message.procedureCode > sizeof(messages_callback) / (3 * sizeof( + s1ap_message_decoded_callback)) + || (message.direction > S1AP_PDU_PR_unsuccessfulOutcome)) { + S1AP_ERROR("[SCTP %d] Either procedureCode %d or direction %d exceed expected\n", + packet_p->assoc_id, message.procedureCode, message.direction); + return -1; + } + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong direction). + */ + if (messages_callback[message.procedureCode][message.direction-1] == NULL) { + S1AP_ERROR("[SCTP %d] No handler for procedureCode %d in %s\n", + packet_p->assoc_id, message.procedureCode, + direction2String[message.direction]); + return -1; + } + + /* Calling the right handler */ + return (*messages_callback[message.procedureCode][message.direction-1])( + eNB_desc_p, packet_p, &message); +} + +int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + S1SetupResponseIEs_t *s1SetupResponse_p; + s1ap_eNB_mme_data_t *mme_desc_p; + int i; + + DevAssert(eNB_desc_p != NULL); + DevAssert(packet_p != NULL); + DevAssert(message_p != NULL); + + s1SetupResponse_p = &message_p->msg.s1SetupResponseIEs; + + /* S1 Setup Response == Non UE-related procedure -> stream 0 */ + if (packet_p->local_stream != 0) { + S1AP_ERROR("[SCTP %d] Received s1 setup response on stream != 0 (%d)\n", + packet_p->assoc_id, packet_p->local_stream); + return -1; + } + + if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) { + S1AP_ERROR("[SCTP %d] Received S1 setup response for non existing " + "MME context\n", packet_p->assoc_id); + return -1; + } + + /* The list of served gummei can contain at most 8 elements. + * LTE related gummei is the first element in the list, i.e with an id of 0. + */ + DevAssert(s1SetupResponse_p->servedGUMMEIs.list.count == 1); + + for (i = 0; i < s1SetupResponse_p->servedGUMMEIs.list.count; i++) { + struct ServedGUMMEIsItem *gummei_item_p; + struct served_gummei_s *new_gummei_p; + int j; + + gummei_item_p = (struct ServedGUMMEIsItem *) + s1SetupResponse_p->servedGUMMEIs.list.array[i]; + new_gummei_p = calloc(1, sizeof(struct served_gummei_s)); + + STAILQ_INIT(&new_gummei_p->served_plmns); + STAILQ_INIT(&new_gummei_p->served_group_ids); + STAILQ_INIT(&new_gummei_p->mme_codes); + + for (j = 0; j < gummei_item_p->servedPLMNs.list.count; j++) { + PLMNidentity_t *plmn_identity_p; + struct plmn_identity_s *new_plmn_identity_p; + + plmn_identity_p = gummei_item_p->servedPLMNs.list.array[i]; + new_plmn_identity_p = calloc(1, sizeof(struct plmn_identity_s)); + TBCD_TO_MCC_MNC(plmn_identity_p, new_plmn_identity_p->mcc, + new_plmn_identity_p->mnc); + STAILQ_INSERT_TAIL(&new_gummei_p->served_plmns, new_plmn_identity_p, next); + new_gummei_p->nb_served_plmns++; + } + for (j = 0; j < gummei_item_p->servedGroupIDs.list.count; j++) { + MME_Group_ID_t *mme_group_id_p; + struct served_group_id_s *new_group_id_p; + + mme_group_id_p = gummei_item_p->servedGroupIDs.list.array[i]; + new_group_id_p = calloc(1, sizeof(struct served_group_id_s)); + OCTET_STRING_TO_INT16(mme_group_id_p, new_group_id_p->mme_group_id); + STAILQ_INSERT_TAIL(&new_gummei_p->served_group_ids, new_group_id_p, next); + new_gummei_p->nb_group_id++; + } + for (j = 0; j < gummei_item_p->servedMMECs.list.count; j++) { + MME_Code_t *mme_code_p; + struct mme_code_s *new_mme_code_p; + + mme_code_p = gummei_item_p->servedMMECs.list.array[i]; + new_mme_code_p = calloc(1, sizeof(struct mme_code_s)); + + OCTET_STRING_TO_INT8(mme_code_p, new_mme_code_p->mme_code); + STAILQ_INSERT_TAIL(&new_gummei_p->mme_codes, new_mme_code_p, next); + new_gummei_p->nb_mme_code++; + } + STAILQ_INSERT_TAIL(&mme_desc_p->served_gummei, new_gummei_p, next); + } + /* Free contents of the list */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_ServedGUMMEIs, + (void *)&s1SetupResponse_p->servedGUMMEIs); + /* Set the capacity of this MME */ + mme_desc_p->relative_mme_capacity = s1SetupResponse_p->relativeMMECapacity; + /* Optionaly set the mme name */ + if (s1SetupResponse_p->presenceMask & S1SETUPRESPONSEIES_MMENAME_PRESENT) { + mme_desc_p->mme_name = calloc(s1SetupResponse_p->mmEname.size + 1, sizeof(char)); + memcpy(mme_desc_p->mme_name, s1SetupResponse_p->mmEname.buf, + s1SetupResponse_p->mmEname.size); + /* Convert the mme name to a printable string */ + mme_desc_p->mme_name[s1SetupResponse_p->mmEname.size] = '\0'; + } + /* The association is now ready as eNB and MME know parameters of each other. + * Mark the association as UP to enable UE contexts creation. + */ + mme_desc_p->state = S1AP_ENB_STATE_CONNECTED; + + /* We call back our self + * -> generate a dummy initial UE message + */ + { + extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p, + s1ap_rrc_api_req_t *api_req_p); + s1ap_rrc_api_req_t api_req; + s1ap_nas_first_req_t *nas_req_p; + + memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t)); + + nas_req_p = &api_req.msg.first_nas_req; + api_req.api_req = S1AP_API_NAS_FIRST_REQ; + + nas_req_p->rnti = 0xC03A; + nas_req_p->establishment_cause = RRC_CAUSE_MO_DATA; + nas_req_p->ue_identity.present = GUMMEI_PROVIDED; + + nas_req_p->ue_identity.identity.gummei.mcc = 208; + nas_req_p->ue_identity.identity.gummei.mnc = 34; + nas_req_p->ue_identity.identity.gummei.mme_code = 0; + nas_req_p->ue_identity.identity.gummei.mme_group_id = 0; + + /* NAS Attach request with IMSI */ + uint8_t nas_attach_req_imsi[] = + { + 0x07, 0x41, + /* EPS Mobile identity = IMSI */ + 0x71, 0x08, 0x29, 0x80, 0x43, 0x21, 0x43, 0x65, 0x87, + 0xF9, + /* End of EPS Mobile Identity */ + 0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03, + 0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00, + 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2, + 0x01, 0x27, 0x11, + }; + + /* NAS Attach request with GUTI */ + uint8_t nas_attach_req_guti[] = + { + 0x07, 0x41, + /* EPS Mobile identity = IMSI */ + 0x71, 0x0B, 0xF6, 0x12, 0xF2, 0x01, 0x80, 0x00, 0x01, 0xE0, 0x00, + 0xDA, 0x1F, + /* End of EPS Mobile Identity */ + 0x02, 0xE0, 0xE0, 0x00, 0x20, 0x02, 0x03, + 0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00, + 0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0D, 0x00, 0x00, 0x0A, 0x00, 0x52, 0x12, 0xF2, + 0x01, 0x27, 0x11, + }; + + nas_req_p->nas_pdu.buffer = nas_attach_req_guti; + nas_req_p->nas_pdu.length = sizeof(nas_attach_req_guti); + + s1ap_eNB_handle_api_req(eNB_desc_p, &api_req); + } + + return 0; +} + +int s1ap_eNB_handle_initial_context_request(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + s1ap_eNB_mme_data_t *mme_desc_p; + s1ap_eNB_ue_context_t *ue_desc_p; + + InitialContextSetupRequestIEs_t *initialContextSetupRequest_p; + + DevAssert(eNB_desc_p != NULL); + DevAssert(packet_p != NULL); + DevAssert(message_p != NULL); + + initialContextSetupRequest_p = &message_p->msg.initialContextSetupRequestIEs; + + DevAssert(packet_p->local_stream > 0); + + if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) { + S1AP_ERROR("[SCTP %d] Received initial context setup request for non " + "existing MME context\n", packet_p->assoc_id); + return -1; + } + if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p, + initialContextSetupRequest_p->eNB_UE_S1AP_ID)) == NULL) { + S1AP_ERROR("[SCTP %d] Received initial context setup request for non " + "existing UE context\n", packet_p->assoc_id); + return -1; + } + + ue_desc_p->mme_ue_s1ap_id = initialContextSetupRequest_p->mme_ue_s1ap_id; + + { + int i; + + extern int s1ap_eNB_handle_api_req(eNB_mme_desc_t *eNB_desc_p, + s1ap_rrc_api_req_t *api_req_p); + + s1ap_rrc_api_req_t api_req; + s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p; + + memset(&api_req, 0, sizeof(s1ap_rrc_api_req_t)); + + initial_ctxt_resp_p = &api_req.msg.initial_ctxt_resp; + api_req.api_req = S1AP_API_INITIAL_CONTEXT_SETUP_RESP; + + initial_ctxt_resp_p->eNB_ue_s1ap_id = ue_desc_p->eNB_ue_s1ap_id; + initial_ctxt_resp_p->e_rabs_failed = 0; + initial_ctxt_resp_p->nb_of_e_rabs + = initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count; + for (i = 0; i < initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.count; i++) + { + struct E_RABToBeSetupItemCtxtSUReq_s *item; + item = (struct E_RABToBeSetupItemCtxtSUReq_s *)initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq.e_RABToBeSetupItemCtxtSUReq.array[i]; + initial_ctxt_resp_p->e_rabs = realloc(initial_ctxt_resp_p->e_rabs, i * sizeof(e_rab_setup_t)); + initial_ctxt_resp_p->e_rabs[i].e_rab_id = 5; + + } + + s1ap_eNB_handle_api_req(eNB_desc_p, &api_req); + } + + return 0; +} diff --git a/openair-cn/S1AP/s1ap_eNB_handlers.h b/openair-cn/S1AP/s1ap_eNB_handlers.h new file mode 100644 index 0000000000..cc95cb7536 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_handlers.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_HANDLERS_H_ +#define S1AP_ENB_HANDLERS_H_ + +int s1ap_eNB_handle_message(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p); + +int s1ap_eNB_handle_s1_setup_response(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message); + +int s1ap_eNB_handle_s1_setup_failure(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message); + +int s1ap_eNB_handle_initial_context_request(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +#endif /* S1AP_ENB_HANDLERS_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_management_procedures.c b/openair-cn/S1AP/s1ap_eNB_management_procedures.c new file mode 100644 index 0000000000..c4e637f6f3 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_management_procedures.c @@ -0,0 +1,115 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "mme_sim.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_defs.h" +#include "s1ap_eNB.h" + +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_management_procedures.h" + +#include "sctp_primitives_client.h" + +#include "assertions.h" +#include "conversions.h" + +int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p, + s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p) +{ + struct s1ap_eNB_ue_context_s *ue_context_p; + UECapabilityInfoIndicationIEs_t *ue_cap_info_ind_ies_p; + + s1ap_message message; + + uint8_t *buffer; + uint32_t length; + int ret = -1; + + DevAssert(ue_cap_info_ind_p != NULL); + DevAssert(eNB_desc_p != NULL); + + if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, ue_cap_info_ind_p->eNB_ue_s1ap_id)) == NULL) + { + /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ + S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n", + ue_cap_info_ind_p->eNB_ue_s1ap_id); + return -1; + } + + /* UE capabilities message can occur either during an s1ap connected state + * or during initial attach (for example: NAS authentication). + */ + if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED || + ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) + { + S1AP_WARN("You are attempting to send NAS data over non-connected " + "eNB ue s1ap id: %u, current state: %d\n", + ue_cap_info_ind_p->eNB_ue_s1ap_id, ue_context_p->ue_state); + return -1; + } + + /* Prepare the S1AP message to encode */ + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_initiatingMessage; + message.procedureCode = ProcedureCode_id_UECapabilityInfoIndication; + + ue_cap_info_ind_ies_p = &message.msg.ueCapabilityInfoIndicationIEs; + + ue_cap_info_ind_ies_p->ueRadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer; + ue_cap_info_ind_ies_p->ueRadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length; + + ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID = ue_cap_info_ind_p->eNB_ue_s1ap_id; + ue_cap_info_ind_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + /* Encode procedure has failed... */ + S1AP_ERROR("Failed to encode UE capabilities indication\n"); + return -1; + } + + /* UE associated signalling -> use the allocated stream */ + if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID, + ue_context_p->stream, buffer, length)) < 0) + { + S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n", + ue_context_p->mme_ref->sctp_data.assoc_id, ret); + } + + free(buffer); + return ret; +} diff --git a/openair-cn/S1AP/s1ap_eNB_management_procedures.h b/openair-cn/S1AP/s1ap_eNB_management_procedures.h new file mode 100644 index 0000000000..3c550312ba --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_management_procedures.h @@ -0,0 +1,37 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_MANAGEMENT_PROCEDURES_H_ +#define S1AP_ENB_MANAGEMENT_PROCEDURES_H_ + +int s1ap_eNB_ue_capabilities(eNB_mme_desc_t *eNB_desc_p, + s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p); + +#endif /* S1AP_ENB_MANAGEMENT_PROCEDURES_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.c b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c new file mode 100644 index 0000000000..6ea899e391 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.c @@ -0,0 +1,260 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "mme_sim.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_defs.h" +#include "s1ap_eNB.h" + +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_nas_procedures.h" + +#include "sctp_primitives_client.h" + +#include "assertions.h" +#include "conversions.h" + +int s1ap_eNB_handle_nas_downlink(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + DownlinkNASTransportIEs_t *downlink_NAS_transport_p; + s1ap_eNB_mme_data_t *mme_desc_p; + s1ap_eNB_ue_context_t *ue_desc_p; + + DevAssert(eNB_desc_p != NULL); + DevAssert(packet_p != NULL); + DevAssert(message_p != NULL); + + downlink_NAS_transport_p = &message_p->msg.downlinkNASTransportIEs; + + /* UE-related procedure -> stream != 0 */ + if (packet_p->local_stream == 0) { + S1AP_ERROR("[SCTP %d] Received s1 setup response on stream == 0\n", + packet_p->assoc_id); + return -1; + } + + if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) { + S1AP_ERROR("[SCTP %d] Received initial context setup request for non " + "existing MME context\n", packet_p->assoc_id); + return -1; + } + if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p, + downlink_NAS_transport_p->eNB_UE_S1AP_ID)) == NULL) + { + S1AP_ERROR("[SCTP %d] Received initial context setup request for non " + "existing UE context\n", packet_p->assoc_id); + return -1; + } + + /* Is it the first outcome of the MME for this UE ? If so store the mme + * UE s1ap id. + */ + if (ue_desc_p->mme_ue_s1ap_id == 0) { + ue_desc_p->mme_ue_s1ap_id = downlink_NAS_transport_p->mme_ue_s1ap_id; + } else { + /* We already have a mme ue s1ap id check the received is the same */ + if (ue_desc_p->mme_ue_s1ap_id != downlink_NAS_transport_p->mme_ue_s1ap_id) { + S1AP_ERROR("[SCTP %d] Mismatch is MME UE S1AP ID (0x%08x != 0x%08x)\n", + downlink_NAS_transport_p->mme_ue_s1ap_id, + ue_desc_p->mme_ue_s1ap_id, + packet_p->assoc_id); + } + } + + /* TODO: forward NAS pdu to RRC for transmission */ + + return 0; +} + +int s1ap_eNB_nas_uplink(eNB_mme_desc_t *eNB_desc_p, + s1ap_nas_uplink_t *nas_uplink_p) +{ + struct s1ap_eNB_ue_context_s *ue_context_p; + UplinkNASTransportIEs_t *uplink_NAS_transport_p; + + s1ap_message message; + + uint8_t *buffer; + uint32_t length; + int ret = -1; + + DevAssert(nas_uplink_p != NULL); + DevAssert(eNB_desc_p != NULL); + + if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, nas_uplink_p->eNB_ue_s1ap_id)) == NULL) + { + /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ + S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n", + nas_uplink_p->eNB_ue_s1ap_id); + return -1; + } + + /* Uplink NAS transport can occur either during an s1ap connected state + * or during initial attach (for example: NAS authentication). + */ + if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED || + ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) + { + S1AP_WARN("You are attempting to send NAS data over non-connected " + "eNB ue s1ap id: %u, current state: %d\n", + nas_uplink_p->eNB_ue_s1ap_id, ue_context_p->ue_state); + return -1; + } + + /* Prepare the S1AP message to encode */ + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_initiatingMessage; + message.procedureCode = ProcedureCode_id_uplinkNASTransport; + + uplink_NAS_transport_p = &message.msg.uplinkNASTransportIEs; + + uplink_NAS_transport_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + uplink_NAS_transport_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id; + + uplink_NAS_transport_p->nas_pdu.buf = nas_uplink_p->nas_pdu.buffer; + uplink_NAS_transport_p->nas_pdu.size = nas_uplink_p->nas_pdu.length; + + MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc, + &uplink_NAS_transport_p->eutran_cgi.pLMNidentity); + MACRO_ENB_ID_TO_CELL_IDENTITY(eNB_desc_p->eNB_id, + &uplink_NAS_transport_p->eutran_cgi.cell_ID); + + /* MCC/MNC should be repeated in TAI and EUTRAN CGI */ + MCC_MNC_TO_PLMNID(eNB_desc_p->mcc, eNB_desc_p->mnc, + &uplink_NAS_transport_p->tai.pLMNidentity); + TAC_TO_ASN1(eNB_desc_p->tac, &uplink_NAS_transport_p->tai.tAC); + + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + S1AP_ERROR("Failed to encode uplink NAS transport\n"); + /* Encode procedure has failed... */ + return -1; + } + + /* UE associated signalling -> use the allocated stream */ + if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID, + ue_context_p->stream, buffer, length)) < 0) + { + S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n", + ue_context_p->mme_ref->sctp_data.assoc_id, ret); + } + + free(buffer); + return ret; +} + +int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p, + s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p) +{ + struct s1ap_eNB_ue_context_s *ue_context_p; + InitialContextSetupResponseIEs_t *initial_ies_p; + + s1ap_message message; + + uint8_t *buffer; + uint32_t length; + int ret = -1; + int i; + + DevAssert(initial_ctxt_resp_p != NULL); + DevAssert(eNB_desc_p != NULL); + + if ((ue_context_p = s1ap_eNB_get_ue_context(eNB_desc_p, + initial_ctxt_resp_p->eNB_ue_s1ap_id)) == NULL) + { + /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */ + S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n", + initial_ctxt_resp_p->eNB_ue_s1ap_id); + return -1; + } + + /* Uplink NAS transport can occur either during an s1ap connected state + * or during initial attach (for example: NAS authentication). + */ + if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED || + ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) + { + S1AP_WARN("You are attempting to send NAS data over non-connected " + "eNB ue s1ap id: %u, current state: %d\n", + initial_ctxt_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state); + return -1; + } + + /* Prepare the S1AP message to encode */ + memset(&message, 0, sizeof(s1ap_message)); + + message.direction = S1AP_PDU_PR_successfulOutcome; + message.procedureCode = ProcedureCode_id_InitialContextSetup; + + initial_ies_p = &message.msg.initialContextSetupResponseIEs; + + initial_ies_p->eNB_UE_S1AP_ID = initial_ctxt_resp_p->eNB_ue_s1ap_id; + initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id; + + for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++) + { + E_RABSetupItemCtxtSURes_t *new_item; + + new_item = calloc(1, sizeof(E_RABSetupItemCtxtSURes_t)); + + new_item->e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id; + GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &new_item->gTP_TEID); + new_item->transportLayerAddress.buf = initial_ctxt_resp_p->e_rabs[i].eNB_addr.buffer; + new_item->transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].eNB_addr.length; + new_item->transportLayerAddress.bits_unused = 0; + + ASN_SEQUENCE_ADD(&initial_ies_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes, new_item); + } + + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + S1AP_ERROR("Failed to encode uplink NAS transport\n"); + /* Encode procedure has failed... */ + return -1; + } + + /* UE associated signalling -> use the allocated stream */ + if ((ret = sctp_send_msg(&ue_context_p->mme_ref->sctp_data, S1AP_SCTP_PPID, + ue_context_p->stream, buffer, length)) < 0) + { + S1AP_ERROR("[SCTP %d] Failed to send message over SCTP: %d\n", + ue_context_p->mme_ref->sctp_data.assoc_id, ret); + } + + free(buffer); + return ret; +} diff --git a/openair-cn/S1AP/s1ap_eNB_nas_procedures.h b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h new file mode 100644 index 0000000000..4e0eb0001c --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_nas_procedures.h @@ -0,0 +1,44 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_NAS_PROCEDURES_H_ +#define S1AP_ENB_NAS_PROCEDURES_H_ + +int s1ap_eNB_nas_uplink(eNB_mme_desc_t *eNB_desc_p, + s1ap_nas_uplink_t *nas_uplink_p); + +int s1ap_eNB_handle_nas_downlink(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +int s1ap_eNB_initial_ctxt_resp(eNB_mme_desc_t *eNB_desc_p, + s1ap_initial_ctxt_setup_resp_t *initial_ctxt_resp_p); + +#endif /* S1AP_ENB_NAS_PROCEDURES_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_nnsf.c b/openair-cn/S1AP/s1ap_eNB_nnsf.c new file mode 100644 index 0000000000..0dd02092fc --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_nnsf.c @@ -0,0 +1,202 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_nnsf.c + * \brief s1ap NAS node selection functions + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "mme_sim.h" + +#include "s1ap_eNB.h" +#include "s1ap_eNB_nnsf.h" + +struct s1ap_eNB_mme_data_s * +s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p, + rrc_establishment_cause_t cause, + uint8_t mme_code) +{ + struct s1ap_eNB_mme_data_s *mme_data_p = NULL; + struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL; + uint8_t current_capacity = 0; + + RB_FOREACH(mme_data_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) { + struct served_gummei_s *gummei_p = NULL; + + if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) { + /* The association between MME and eNB is not ready for the moment, + * go to the next known MME. + */ + if (mme_data_p->state == S1AP_ENB_OVERLOAD) { + /* MME is overloaded. We have to check the RRC establishment + * cause and take decision to the select this MME depending on + * the overload state. + */ + if ((cause == RRC_CAUSE_MO_DATA) + && (mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_MO_DATA)) { + continue; + } + if ((mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_ALL_SIGNALLING) + && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) { + continue; + } + if ((mme_data_p->overload_state == S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT) + && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA) + || (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) { + continue; + } + /* At this point, the RRC establishment can be handled by the MME + * even if it is in overload state. + */ + } else { + /* The MME is not overloaded, association is simply not ready. */ + continue; + } + } + if (current_capacity < mme_data_p->relative_mme_capacity) { + /* We find a better MME, keep a reference to it */ + current_capacity = mme_data_p->relative_mme_capacity; + mme_highest_capacity_p = mme_data_p; + } + + /* Looking for MME code matching the one provided by NAS */ + STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) { + struct mme_code_s *mme_code_p = NULL; + + STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) { + if (mme_code_p->mme_code == mme_code) { + return mme_data_p; + } + } + } + } + + /* At this point no MME matches the provided GUMMEI. Select the one with the + * highest relative capacity. + * In case the list of known MME is empty, simply return NULL, that way the RRC + * layer should know about it and reject RRC connectivity. + */ + return mme_highest_capacity_p; +} + +struct s1ap_eNB_mme_data_s * +s1ap_eNB_nnsf_select_mme_by_gummei(eNB_mme_desc_t *eNB_desc_p, + rrc_establishment_cause_t cause, + gummei_t gummei) +{ + struct s1ap_eNB_mme_data_s *mme_data_p = NULL; + struct s1ap_eNB_mme_data_s *mme_highest_capacity_p = NULL; + uint8_t current_capacity = 0; + + RB_FOREACH(mme_data_p, s1ap_mme_map, &eNB_desc_p->s1ap_mme_head) { + struct served_gummei_s *gummei_p = NULL; + + if (mme_data_p->state != S1AP_ENB_STATE_CONNECTED) { + /* The association between MME and eNB is not ready for the moment, + * go to the next known MME. + */ + if (mme_data_p->state == S1AP_ENB_OVERLOAD) { + /* MME is overloaded. We have to check the RRC establishment + * cause and take decision to the select this MME depending on + * the overload state. + */ + if ((cause == RRC_CAUSE_MO_DATA) + && (mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_MO_DATA)) { + continue; + } + if ((mme_data_p->overload_state == S1AP_OVERLOAD_REJECT_ALL_SIGNALLING) + && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA))) { + continue; + } + if ((mme_data_p->overload_state == S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT) + && ((cause == RRC_CAUSE_MO_SIGNALLING) || (cause == RRC_CAUSE_MO_DATA) + || (cause == RRC_CAUSE_HIGH_PRIO_ACCESS))) { + continue; + } + /* At this point, the RRC establishment can be handled by the MME + * even if it is in overload state. + */ + } else { + /* The MME is not overloaded, association is simply not ready. */ + continue; + } + } + if (current_capacity < mme_data_p->relative_mme_capacity) { + /* We find a better MME, keep a reference to it */ + current_capacity = mme_data_p->relative_mme_capacity; + mme_highest_capacity_p = mme_data_p; + } + + /* Looking for MME gummei matching the one provided by NAS */ + STAILQ_FOREACH(gummei_p, &mme_data_p->served_gummei, next) { + struct served_group_id_s *group_id_p = NULL; + struct mme_code_s *mme_code_p = NULL; + struct plmn_identity_s *served_plmn_p = NULL; + + STAILQ_FOREACH(served_plmn_p, &gummei_p->served_plmns, next) { + if ((served_plmn_p->mcc == gummei.mcc) && + (served_plmn_p->mnc == gummei.mnc)) { + break; + } + } + STAILQ_FOREACH(mme_code_p, &gummei_p->mme_codes, next) { + if (mme_code_p->mme_code == gummei.mme_code) { + break; + } + } + STAILQ_FOREACH(group_id_p, &gummei_p->served_group_ids, next) { + if (group_id_p->mme_group_id == gummei.mme_group_id) { + break; + } + } + /* The MME matches the parameters provided by the NAS layer -> + * the MME is knwown and the association is ready. + * Return the reference to the MME to use it for this UE. + */ + if ((group_id_p != NULL) && + (mme_code_p != NULL) && + (served_plmn_p != NULL)) { + return mme_data_p; + } + } + } + + /* At this point no MME matches the provided GUMMEI. Select the one with the + * highest relative capacity. + * In case the list of known MME is empty, simply return NULL, that way the RRC + * layer should know about it and reject RRC connectivity. + */ + return mme_highest_capacity_p; +} diff --git a/openair-cn/S1AP/s1ap_eNB_nnsf.h b/openair-cn/S1AP/s1ap_eNB_nnsf.h new file mode 100644 index 0000000000..30169f8b61 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_nnsf.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/** @defgroup _s1ap_impl_ S1AP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +#ifndef S1AP_ENB_NNSF_H_ +#define S1AP_ENB_NNSF_H_ + +struct s1ap_eNB_mme_data_s* +s1ap_eNB_nnsf_select_mme_by_mme_code(eNB_mme_desc_t *eNB_desc_p, + rrc_establishment_cause_t cause, + uint8_t mme_code); + +struct s1ap_eNB_mme_data_s* +s1ap_eNB_nnsf_select_mme_by_gummei(eNB_mme_desc_t *eNB_desc_p, + rrc_establishment_cause_t cause, + gummei_t gummei); + +#endif /* S1AP_ENB_NNSF_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_overload.c b/openair-cn/S1AP/s1ap_eNB_overload.c new file mode 100644 index 0000000000..ccca7c920e --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_overload.c @@ -0,0 +1,109 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_overload.c + * \brief s1ap procedures for overload messages within eNB + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_defs.h" + +#include "s1ap_eNB.h" +#include "s1ap_eNB_ue_context.h" +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_overload.h" + +#include "sctp_primitives_client.h" + +#include "assertions.h" + +int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + OverloadStartIEs_t *overload_start_p; + s1ap_eNB_mme_data_t *mme_desc_p; + + overload_start_p = &message_p->msg.overloadStartIEs; + + DevCheck(overload_start_p->overloadResponse.present == + OverloadResponse_PR_overloadAction, + OverloadResponse_PR_overloadAction, 0, 0); + + /* Non UE-associated signalling -> stream 0 */ + DevCheck(packet_p->local_stream == 0, packet_p->local_stream, + packet_p->remote_port, packet_p->assoc_id); + + if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) { + /* No MME context associated */ + return -1; + } + + /* Mark the MME as overloaded and set the overload state according to + * the value received. + */ + mme_desc_p->state = S1AP_ENB_OVERLOAD; + mme_desc_p->overload_state = + overload_start_p->overloadResponse.choice.overloadAction; + + return 0; +} + +int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + /* We received Overload stop message, meaning that the MME is no more + * overloaded. This is an empty message, with only message header and no + * Information Element. + */ + s1ap_eNB_mme_data_t *mme_desc_p; + + /* Non UE-associated signalling -> stream 0 */ + DevCheck(packet_p->local_stream == 0, packet_p->local_stream, + packet_p->remote_port, packet_p->assoc_id); + + if ((mme_desc_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id)) == NULL) { + /* No MME context associated */ + return -1; + } + + mme_desc_p->state = S1AP_ENB_STATE_CONNECTED; + mme_desc_p->overload_state = S1AP_NO_OVERLOAD; + return 0; +} diff --git a/openair-cn/S1AP/s1ap_eNB_overload.h b/openair-cn/S1AP/s1ap_eNB_overload.h new file mode 100644 index 0000000000..5e836879dc --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_overload.h @@ -0,0 +1,48 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_OVERLOAD_H_ +#define S1AP_ENB_OVERLOAD_H_ + +/** + * \brief Handle an overload start message + **/ +int s1ap_eNB_handle_overload_start(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +/** + * \brief Handle an overload stop message + **/ +int s1ap_eNB_handle_overload_stop(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +#endif /* S1AP_ENB_OVERLOAD_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_trace.c b/openair-cn/S1AP/s1ap_eNB_trace.c new file mode 100644 index 0000000000..b99cc257fa --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_trace.c @@ -0,0 +1,124 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_eNB_defs.h" + +#include "s1ap_eNB.h" +#include "s1ap_eNB_ue_context.h" +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_trace.h" + +#include "eNB_default_values.h" + +#include "sctp_primitives_client.h" + +#include "assertions.h" + +int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p, + int32_t stream, + uint32_t eNB_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + E_UTRAN_Trace_ID_t *trace_id, + Cause_t *cause_p) +{ + s1ap_message message; + TraceFailureIndicationIEs_t *trace_failure_p; + uint8_t *buffer; + uint32_t length; + int ret; + + DevAssert(sctp_data_p != NULL); + + memset(&message, 0, sizeof(s1ap_message)); + + trace_failure_p = &message.msg.traceFailureIndicationIEs; + + trace_failure_p->mme_ue_s1ap_id = mme_ue_s1ap_id; + trace_failure_p->eNB_UE_S1AP_ID = eNB_ue_s1ap_id; + + memcpy(&trace_failure_p->e_UTRAN_Trace_ID, trace_id, sizeof(E_UTRAN_Trace_ID_t)); + memcpy(&trace_failure_p->cause, cause_p, sizeof(Cause_t)); + + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + return -1; + } + if ((ret = sctp_send_msg(sctp_data_p, S1AP_SCTP_PPID, + stream, buffer, length)) < 0) { + S1AP_ERROR("Failed to send Trace failure\n"); + } + free(buffer); + return ret; +} + +int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + TraceStartIEs_t *trace_start_p; + struct s1ap_eNB_ue_context_s *ue_desc_p; + + trace_start_p = &message_p->msg.traceStartIEs; + + if ((ue_desc_p = s1ap_eNB_get_ue_context(eNB_desc_p, + trace_start_p->eNB_UE_S1AP_ID)) == NULL) { + /* Could not find context associated with this eNB_ue_s1ap_id -> generate + * trace failure indication. + */ + struct s1ap_eNB_mme_data_s *mme_ref_p; + E_UTRAN_Trace_ID_t trace_id; + Cause_t cause; + + memset(&trace_id, 0, sizeof(E_UTRAN_Trace_ID_t)); + memset(&cause, 0, sizeof(Cause_t)); + mme_ref_p = s1ap_eNB_get_MME(eNB_desc_p, packet_p->assoc_id); + + cause.present = Cause_PR_radioNetwork; + cause.choice.radioNetwork = CauseRadioNetwork_unknown_pair_ue_s1ap_id; + + return s1ap_eNB_generate_trace_failure(&mme_ref_p->sctp_data, + packet_p->local_stream, + trace_start_p->eNB_UE_S1AP_ID, + trace_start_p->mme_ue_s1ap_id, &trace_id, &cause); + } + return 0; +} + +int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p) +{ + DeactivateTraceIEs_t *deactivate_trace_p; + + deactivate_trace_p = &message_p->msg.deactivateTraceIEs; + + return 0; +} diff --git a/openair-cn/S1AP/s1ap_eNB_trace.h b/openair-cn/S1AP/s1ap_eNB_trace.h new file mode 100644 index 0000000000..6b1f4ed105 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_trace.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_ENB_TRACE_H_ +#define S1AP_ENB_TRACE_H_ + +int s1ap_eNB_generate_trace_failure(sctp_data_t *sctp_data_p, + int32_t stream, + uint32_t eNB_ue_s1ap_id, + uint32_t mme_ue_s1ap_id, + E_UTRAN_Trace_ID_t *trace_id, + Cause_t *cause_p); + +int s1ap_eNB_handle_trace_start(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +int s1ap_eNB_handle_deactivate_trace(eNB_mme_desc_t *eNB_desc_p, + sctp_queue_item_t *packet_p, + struct s1ap_message_s *message_p); + +#endif /* S1AP_ENB_TRACE_H_ */ diff --git a/openair-cn/S1AP/s1ap_eNB_ue_context.c b/openair-cn/S1AP/s1ap_eNB_ue_context.c new file mode 100644 index 0000000000..3c1c45891e --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_ue_context.c @@ -0,0 +1,107 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_eNB_ue_context.c + * \brief s1ap UE context management within eNB + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> + +#include "tree.h" + +#include "s1ap_common.h" +#include "s1ap_eNB.h" +#include "s1ap_eNB_ue_context.h" + +inline int s1ap_eNB_compare_eNB_ue_s1ap_id( + struct s1ap_eNB_ue_context_s *p1, struct s1ap_eNB_ue_context_s *p2) +{ + if (p1->eNB_ue_s1ap_id > p2->eNB_ue_s1ap_id) { + return 1; + } + if (p1->eNB_ue_s1ap_id < p2->eNB_ue_s1ap_id) { + return -1; + } + return 0; +} + +/* Generate the tree management functions */ +RB_GENERATE(s1ap_ue_map, s1ap_eNB_ue_context_s, entries, + s1ap_eNB_compare_eNB_ue_s1ap_id); + +struct s1ap_eNB_ue_context_s *s1ap_eNB_allocate_new_UE_context(void) +{ + struct s1ap_eNB_ue_context_s *new_p; + + new_p = malloc(sizeof(struct s1ap_eNB_ue_context_s)); + + if (new_p == NULL) { + S1AP_ERROR("Cannot allocate new ue context\n"); + return NULL; + } + + memset(new_p, 0, sizeof(struct s1ap_eNB_ue_context_s)); + + return new_p; +} + +struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context( + struct eNB_mme_desc_s *eNB_desc_p, + uint32_t eNB_ue_s1ap_id) +{ + s1ap_eNB_ue_context_t temp; + + memset(&temp, 0, sizeof(struct s1ap_eNB_ue_context_s)); + + /* eNB ue s1ap id = 24 bits wide */ + temp.eNB_ue_s1ap_id = eNB_ue_s1ap_id & 0x00FFFFFF; + + return RB_FIND(s1ap_ue_map, &eNB_desc_p->s1ap_ue_head, &temp); +} + +void s1ap_eNB_free_ue_context(struct s1ap_eNB_ue_context_s *ue_context_p) +{ + if (ue_context_p == NULL) { + S1AP_ERROR("Trying to free a NULL context\n"); + return; + } + + /* TODO: check that context is currently not in the tree of known + * contexts. + */ + + free(ue_context_p); +} diff --git a/openair-cn/S1AP/s1ap_eNB_ue_context.h b/openair-cn/S1AP/s1ap_eNB_ue_context.h new file mode 100644 index 0000000000..621f1fc991 --- /dev/null +++ b/openair-cn/S1AP/s1ap_eNB_ue_context.h @@ -0,0 +1,90 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "tree.h" +#include "queue.h" + +#ifndef S1AP_ENB_UE_CONTEXT_H_ +#define S1AP_ENB_UE_CONTEXT_H_ + +// Forward declarations +struct s1ap_eNB_mme_data_s; +struct s1ap_ue_map; +struct eNB_mme_desc_s; + +typedef enum { + /* UE has not been registered to a MME or UE association has failed. */ + S1AP_UE_DECONNECTED = 0x0, + /* UE s1ap state is waiting for initial context setup request message. */ + S1AP_UE_WAITING_CSR = 0x1, + /* UE association is ready and bearers are established. */ + S1AP_UE_CONNECTED = 0x2, + S1AP_UE_STATE_MAX, +} s1ap_ue_state; + +typedef struct s1ap_eNB_ue_context_s { + /* Uniquely identifies the UE between MME and eNB within the eNB. + * This id is encoded on 24bits. + */ + unsigned eNB_ue_s1ap_id:24; + + /* RNTI of the UE as used on LTE-Uu interface */ + uint16_t rnti; + + /* Uniquely identifies the UE within MME. Encoded on 32 bits. */ + uint32_t mme_ue_s1ap_id; + + /* Stream used for this particular UE */ + int32_t stream; + + /* Current UE state. */ + s1ap_ue_state ue_state; + + /* Reference to MME data this UE is attached to */ + struct s1ap_eNB_mme_data_s *mme_ref; + + /* Tree related data */ + RB_ENTRY(s1ap_eNB_ue_context_s) entries; +} s1ap_eNB_ue_context_t; + +inline int s1ap_eNB_compare_eNB_ue_s1ap_id( + struct s1ap_eNB_ue_context_s *p1, struct s1ap_eNB_ue_context_s *p2); + +/* Generate the tree management functions prototypes */ +RB_PROTOTYPE(s1ap_ue_map, s1ap_eNB_ue_context_s, entries, + s1ap_eNB_compare_eNB_ue_s1ap_id); + +struct s1ap_eNB_ue_context_s *s1ap_eNB_allocate_new_UE_context(void); + +struct s1ap_eNB_ue_context_s *s1ap_eNB_get_ue_context(struct eNB_mme_desc_s + *eNB_desc_p, + uint32_t eNB_ue_s1ap_id); + +#endif /* S1AP_ENB_UE_CONTEXT_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme.c b/openair-cn/S1AP/s1ap_mme.c new file mode 100644 index 0000000000..865d005dec --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme.c @@ -0,0 +1,449 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#if !defined(MME_CLIENT_TEST) +# include "intertask_interface.h" +#endif +#include "s1ap_mme.h" +#include "s1ap_mme_decoder.h" +#include "s1ap_mme_handlers.h" +#include "s1ap_ies_defs.h" + +#include "s1ap_mme_nas_procedures.h" +#include "s1ap_mme_retransmission.h" + +#define S1AP_DEBUG_LIST +#ifdef S1AP_DEBUG_LIST +# define eNB_LIST_OUT(x, args...) S1AP_DEBUG("[eNB]%*s"x"\n", 4*indent, "", ##args) +# define UE_LIST_OUT(x, args...) S1AP_DEBUG("[UE] %*s"x"\n", 4*indent, "", ##args) +#else +# define eNB_LIST_OUT(x, args...) +# define UE_LIST_OUT(x, args...) +#endif + +#if !defined(MME_CLIENT_TEST) +// static pthread_t s1ap_task_thread; + +uint32_t nb_eNB_associated = 0; +eNB_description_t *eNB_list_head = NULL; +eNB_description_t *eNB_list_tail = NULL; +static int indent = 0; + +void *s1ap_mme_thread(void *args); + +static int s1ap_send_init_sctp(void) { + // Create and alloc new message + MessageDef *message_p; + message_p = alloc_new_message(TASK_S1AP, SCTP_INIT_MSG); + message_p->msg.sctpInit.port = S1AP_PORT_NUMBER; + message_p->msg.sctpInit.ppid = S1AP_SCTP_PPID; + message_p->msg.sctpInit.ipv4 = 1; + message_p->msg.sctpInit.ipv6 = 0; + message_p->msg.sctpInit.nb_ipv4_addr = 1; + message_p->msg.sctpInit.ipv4_address[0] + = mme_config.ipv4.mme_ip_address_for_S1_MME; + /* SR WARNING: ipv6 multi-homing fails sometimes for localhost. + * Disable it for now.*/ + message_p->msg.sctpInit.nb_ipv6_addr = 0; + message_p->msg.sctpInit.ipv6_address[0] = "0:0:0:0:0:0:0:1"; + + return send_msg_to_task(TASK_SCTP, INSTANCE_DEFAULT, message_p); +} + +void *s1ap_mme_thread(void *args) +{ + MessageDef *received_message_p; + + intertask_interface_mark_task_ready(TASK_S1AP); + while(1) { + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + receive_msg(TASK_S1AP, &received_message_p); + assert(received_message_p != NULL); + switch(received_message_p->header.messageId) { + case S1AP_SCTP_NEW_MESSAGE_IND: { + /* New message received from SCTP layer. + * Decode and handle it. + */ + s1ap_message message; + s1ap_sctp_new_msg_ind_t *s1ap_sctp_new_msg_ind_p; + s1ap_sctp_new_msg_ind_p = &received_message_p->msg.s1ap_sctp_new_msg_ind; + + memset((void *)&message, 0, sizeof(s1ap_message)); + /* Invoke S1AP message decoder */ + if (s1ap_mme_decode_pdu(&message, s1ap_sctp_new_msg_ind_p->buffer, s1ap_sctp_new_msg_ind_p->buf_length) < 0) { + // TODO: Notify eNB of failure with right cause + S1AP_ERROR("Failed to decode new buffer\n"); + } else { + s1ap_mme_handle_message(s1ap_sctp_new_msg_ind_p->assoc_id, s1ap_sctp_new_msg_ind_p->stream, &message); + } + // Free received PDU array + free(s1ap_sctp_new_msg_ind_p->buffer); + } break; + /* SCTP layer notifies S1AP of disconnection of a peer. */ + case SCTP_CLOSE_ASSOCIATION: { + sctp_close_association_t *sctp_close_association_p; + sctp_close_association_p = &received_message_p->msg.sctp_close_association; + + s1ap_handle_sctp_deconnection(sctp_close_association_p->assoc_id); + } break; + case SCTP_NEW_ASSOCIATION: { + s1ap_handle_new_association(&received_message_p->msg.sctp_new_peer); + } break; + case NAS_DOWNLINK_DATA_IND: { + /* New message received from NAS task. + * This corresponds to a S1AP downlink nas transport message. + */ + s1ap_generate_downlink_nas_transport(&received_message_p->msg.nas_dl_data_ind); + } break; + case NAS_ATTACH_ACCEPT: { + s1ap_handle_attach_accepted(&received_message_p->msg.nas_attach_accept); + } break; + case TIMER_HAS_EXPIRED: { + s1ap_handle_timer_expiry(&received_message_p->msg.timer_has_expired); + } break; + default: { + S1AP_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int s1ap_mme_init(const mme_config_t *mme_config_p) { + S1AP_DEBUG("Initializing S1AP interface\n"); + + if (get_asn1c_environment_version() < ASN1_MINIMUM_VERSION) { + S1AP_ERROR("ASN1C version %d fount, expecting at least %d\n", + get_asn1c_environment_version(), ASN1_MINIMUM_VERSION); + return -1; + } else { + S1AP_DEBUG("ASN1C version %d\n", get_asn1c_environment_version()); + } +#if defined(UPDATE_RELEASE_10) + S1AP_DEBUG("S1AP Release v10.5\n"); +#else +# if defined(UPDATE_RELEASE_9) + S1AP_DEBUG("S1AP Release v9.8\n"); +# else + S1AP_DEBUG("S1AP Release v8.10\n"); +# endif +#endif + + if (intertask_interface_create_task(TASK_S1AP, &s1ap_mme_thread, NULL) < 0) { + S1AP_ERROR("Error while creating S1AP task\n"); + return -1; + } + if (s1ap_send_init_sctp() < 0) { + S1AP_ERROR("Error while sendind SCTP_INIT_MSG to SCTP \n"); + return -1; + } + S1AP_DEBUG("Initializing S1AP interface: DONE\n"); + return 0; +} + +void s1ap_dump_eNB_list(void) { + eNB_description_t *eNB_ref = eNB_list_head; + + while (eNB_ref != NULL) { + s1ap_dump_eNB(eNB_ref); + eNB_ref = eNB_ref->next_eNB; + } +} + +void s1ap_dump_eNB(eNB_description_t *eNB_ref) { +#ifdef S1AP_DEBUG_LIST + ue_description_t *ue_ref; + //Reset indentation + indent = 0; + if (eNB_ref == NULL) return; + eNB_LIST_OUT(""); + eNB_LIST_OUT("eNB name: %s", eNB_ref->eNB_name == NULL ? "not present" : eNB_ref->eNB_name); + eNB_LIST_OUT("eNB ID: %d", eNB_ref->eNB_id); + eNB_LIST_OUT("SCTP assoc id: %d", eNB_ref->sctp_assoc_id); + eNB_LIST_OUT("SCTP instreams: %d", eNB_ref->instreams); + eNB_LIST_OUT("SCTP outstreams: %d", eNB_ref->outstreams); + eNB_LIST_OUT("UE attache to eNB: %d", eNB_ref->nb_ue_associated); + + indent++; + for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) { + s1ap_dump_ue(ue_ref); + } + indent--; + eNB_LIST_OUT(""); +#else + eNB_ref = eNB_ref; + s1ap_dump_ue(NULL); +#endif +} + +void s1ap_dump_ue(ue_description_t *ue_ref) { +#ifdef S1AP_DEBUG_LIST + if (ue_ref == NULL) return; + UE_LIST_OUT("eNB UE s1ap id: 0x%06x", ue_ref->eNB_ue_s1ap_id); + UE_LIST_OUT("MME UE s1ap id: 0x%08x", ue_ref->mme_ue_s1ap_id); + UE_LIST_OUT("SCTP stream recv: 0x%04x", ue_ref->sctp_stream_recv); + UE_LIST_OUT("SCTP stream send: 0x%04x", ue_ref->sctp_stream_send); +#else + ue_ref = ue_ref; +#endif +} + +eNB_description_t* s1ap_is_eNB_id_in_list(uint32_t eNB_id) { + + eNB_description_t *eNB_ref; + + for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) { + if (eNB_ref->eNB_id == eNB_id) + // We fount a matching reference, return it + break; + } + // No matching eNB, return NULL + return eNB_ref; +} + +eNB_description_t* s1ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id) { + + eNB_description_t *eNB_ref; + + for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) { + if (eNB_ref->sctp_assoc_id == sctp_assoc_id) + // We fount a matching reference, return it + break; + } + // No matching eNB or no eNB in list, return NULL + return eNB_ref; +} + +ue_description_t *s1ap_is_ue_eNB_id_in_list(eNB_description_t *eNB_ref, + uint32_t eNB_ue_s1ap_id) { + ue_description_t *ue_ref; + // No eNB_list_head in list, simply returning NULL + if (eNB_ref == NULL) return NULL; + + for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) { + if (ue_ref->eNB_ue_s1ap_id == eNB_ue_s1ap_id) + break; + } + // No matching UE, return NULL + return ue_ref; +} + +ue_description_t* s1ap_is_ue_mme_id_in_list(uint32_t mme_ue_s1ap_id) { + + ue_description_t *ue_ref; + eNB_description_t *eNB_ref; + // No eNB_list_head in list, simply returning NULL + if (eNB_list_head == NULL) return NULL; + for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) { + for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) { + // We fount a matching reference, return it + if (ue_ref->mme_ue_s1ap_id == mme_ue_s1ap_id) + return ue_ref; + } + } + // No matching UE, return NULL + return NULL; +} + +ue_description_t* s1ap_is_teid_in_list(uint32_t teid) { + + ue_description_t *ue_ref; + eNB_description_t *eNB_ref; + // No eNB_list_head in list, simply returning NULL + if (eNB_list_head == NULL) return NULL; + for (eNB_ref = eNB_list_head; eNB_ref; eNB_ref = eNB_ref->next_eNB) { + for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) { + // We fount a matching reference, return it + if (ue_ref->teid == teid) + return ue_ref; + } + } + // No matching UE, return NULL + return NULL; +} + +eNB_description_t* s1ap_new_eNB(void) { + + eNB_description_t *eNB_ref = NULL; + + eNB_ref = malloc(sizeof(eNB_description_t)); + + /* Something bad happened during malloc... + * May be we are running out of memory. + * TODO: Notify eNB with a cause like Hardware Failure. + */ + if (eNB_ref == NULL) return NULL; + + memset(eNB_ref, 0, sizeof(eNB_description_t)); + + eNB_ref->next_eNB = NULL; + eNB_ref->previous_eNB = NULL; + // No eNB present + if (eNB_list_head == NULL) { + eNB_list_head = eNB_ref; + // Point tail to head (single element in list) + eNB_list_tail = eNB_list_head; + } else { + eNB_ref->previous_eNB = eNB_list_tail; + eNB_list_tail->next_eNB = eNB_ref; + // Update list tail with the new eNB added + eNB_list_tail = eNB_ref; + } + + // Update number of eNB associated + nb_eNB_associated++; + eNB_ref->ue_list_head = NULL; + eNB_ref->ue_list_tail = NULL; + eNB_ref->nb_ue_associated = 0; + return eNB_ref; +} + +ue_description_t* s1ap_new_ue(uint32_t sctp_assoc_id) { + + eNB_description_t *eNB_ref = NULL; + ue_description_t *ue_ref = NULL; + + if ((eNB_ref = s1ap_is_eNB_assoc_id_in_list(sctp_assoc_id)) == NULL) { + /* No eNB attached to this SCTP assoc ID... + * return NULL. + */ + return NULL; + } + ue_ref = malloc(sizeof(ue_description_t)); + /* Something bad happened during malloc... + * May be we are running out of memory. + * TODO: Notify eNB with a cause like Hardware Failure. + */ + if (ue_ref == NULL) return NULL; + + memset(ue_ref, 0, sizeof(ue_description_t)); + + ue_ref->eNB = eNB_ref; + ue_ref->next_ue = NULL; + ue_ref->previous_ue = NULL; + + // Increment number of UE + eNB_ref->nb_ue_associated++; + if (eNB_ref->ue_list_head == NULL) { + // Currently no UE in active list + eNB_ref->ue_list_head = ue_ref; + ue_ref->previous_ue = NULL; + eNB_ref->ue_list_tail = eNB_ref->ue_list_head; + } else { + eNB_ref->ue_list_tail->next_ue = ue_ref; + ue_ref->previous_ue = eNB_ref->ue_list_tail; + eNB_ref->ue_list_tail = ue_ref; + } + + return ue_ref; +} + +void s1ap_remove_ue(ue_description_t *ue_ref) { + /* NULL reference... */ + if (ue_ref == NULL) return; + + /* Remove any attached timer */ + s1ap_timer_remove_ue(ue_ref->mme_ue_s1ap_id); + + if (ue_ref->next_ue != NULL) { + if (ue_ref->previous_ue != NULL) { + /* Not head and not tail */ + ue_ref->previous_ue->next_ue = ue_ref->next_ue; + ue_ref->next_ue->previous_ue = ue_ref->previous_ue; + } else { + /* Head but not tail */ + ue_ref->eNB->ue_list_head = ue_ref->next_ue; + ue_ref->next_ue->previous_ue = NULL; + } + } else { + if (ue_ref->previous_ue != NULL) { + /* Not head but tail */ + ue_ref->eNB->ue_list_tail = ue_ref->previous_ue; + ue_ref->previous_ue->next_ue = NULL; + } else { + /* Head and tail */ + ue_ref->eNB->ue_list_tail = ue_ref->eNB->ue_list_head = NULL; + } + } + /* Updating number of UE */ + ue_ref->eNB->nb_ue_associated--; + /* Freeing memory */ + free(ue_ref); +} + +void s1ap_remove_eNB(eNB_description_t *eNB_ref) { + ue_description_t *ue_ref; + + if (eNB_ref == NULL) return; + + /* Removing any ue context */ + for (ue_ref = eNB_ref->ue_list_head; ue_ref; ue_ref = ue_ref->next_ue) { + s1ap_remove_ue(ue_ref); + } + + if (eNB_ref->next_eNB != NULL) { + if (eNB_ref->previous_eNB != NULL) { + /* Not tail and not head */ + eNB_ref->previous_eNB->next_eNB = eNB_ref->next_eNB; + eNB_ref->next_eNB->previous_eNB = eNB_ref->previous_eNB; + } else { + /* Head but not tail */ + eNB_list_head = eNB_ref->next_eNB; + eNB_ref->next_eNB->previous_eNB = NULL; + } + } else { + if (eNB_ref->previous_eNB != NULL) { + /* Not head but tail */ + eNB_list_tail = eNB_ref->previous_eNB; + eNB_ref->previous_eNB->next_eNB = NULL; + } else { + /* Head and tail */ + eNB_list_tail = eNB_list_head = NULL; + } + } + free(eNB_ref); + nb_eNB_associated--; +} + +#endif diff --git a/openair-cn/S1AP/s1ap_mme.h b/openair-cn/S1AP/s1ap_mme.h new file mode 100644 index 0000000000..27329d13bd --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme.h @@ -0,0 +1,188 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if !defined(MME_CLIENT_TEST) +# include "intertask_interface.h" +#endif + +#include "mme_config.h" + +#ifndef S1AP_MME_H_ +#define S1AP_MME_H_ + +// Forward declarations +struct eNB_description_s; + +enum s1_eNB_state_s { + S1AP_RESETING, ///< After a reset request (eNB or MME initiated) + S1AP_READY ///< MME and eNB are S1 associated, UE contexts can be added +}; + +enum s1_ue_state_s { + S1AP_UE_WAITING_CSR, ///< Waiting for Initial Context Setup Response + S1AP_UE_HANDOVER, ///< Handover procedure triggered + S1AP_UE_CONNECTED, ///< UE context ready +}; + +/** Main structure representing UE association over s1ap + * Generated every time a new InitialUEMessage is received + **/ +typedef struct ue_description_s { + struct ue_description_s *next_ue; ///< Next UE in the list + struct ue_description_s *previous_ue; ///< Previous UE in the list + + struct eNB_description_s *eNB; ///< Which eNB this UE is attached to + + enum s1_ue_state_s s1_ue_state; ///< S1AP UE state + + unsigned eNB_ue_s1ap_id:24; ///< Unique UE id over eNB (24 bits wide) + uint32_t mme_ue_s1ap_id; ///< Unique UE id over MME (32 bits wide) + + /** SCTP stream on which S1 message will be sent/received. + * During an UE S1 connection, a pair of streams is + * allocated and is used during all the connection. + * Stream 0 is reserved for non UE signalling. + * @name sctp stream identifier + **/ + /*@{*/ + uint16_t sctp_stream_recv; ///< eNB -> MME stream + uint16_t sctp_stream_send; ///< MME -> eNB stream + /*@}*/ + + uint32_t teid; + + /* Timer for procedure outcume issued by MME that should be answered */ + long outcome_response_timer_id; +} ue_description_t; + +/* Main structure representing eNB association over s1ap + * Generated (or updated) every time a new S1SetupRequest is received. + */ +typedef struct eNB_description_s { + struct eNB_description_s *next_eNB; ///< Next eNB in the list of eNB + struct eNB_description_s *previous_eNB; ///< Previous eNB in the list of eNB + + enum s1_eNB_state_s s1_state; ///< State of the eNB S1AP association over MME + + /** eNB related parameters **/ + /*@{*/ + char eNB_name[150]; ///< Printable eNB Name + uint32_t eNB_id; ///< Unique eNB ID + uint8_t default_paging_drx; ///< Default paging DRX interval for eNB + /*@}*/ + + /** UE list for this eNB **/ + /*@{*/ + uint32_t nb_ue_associated; ///< Number of NAS associated UE on this eNB + ue_description_t *ue_list_head; ///< List head of NAS associated UE on this eNB + ue_description_t *ue_list_tail; ///< List tail of NAS associated UE on this eNB + /*@}*/ + + /** SCTP stuff **/ + /*@{*/ + uint32_t sctp_assoc_id; ///< SCTP association id on this machine + uint16_t next_sctp_stream; ///< Next SCTP stream + uint16_t instreams; ///< Number of streams avalaible on eNB -> MME + uint16_t outstreams; ///< Number of streams avalaible on MME -> eNB + /*@}*/ +} eNB_description_t; + +extern uint32_t nb_eNB_associated; +extern mme_config_t *global_mme_config_p; + +/** \brief S1AP layer top init + * @returns -1 in case of failure + **/ +int s1ap_mme_init(const mme_config_t *mme_config); + +/** \brief Look for given eNB id in the list + * \param eNB_id The unique eNB id to search in list + * @returns NULL if no eNB matchs the eNB id, or reference to the eNB element in list if matches + **/ +eNB_description_t* s1ap_is_eNB_id_in_list(uint32_t eNB_id); + +/** \brief Look for given eNB SCTP assoc id in the list + * \param eNB_id The unique sctp assoc id to search in list + * @returns NULL if no eNB matchs the sctp assoc id, or reference to the eNB element in list if matches + **/ +eNB_description_t* s1ap_is_eNB_assoc_id_in_list(uint32_t sctp_assoc_id); + +/** \brief Look for given ue eNB id in the list + * \param eNB_id The unique ue_eNB_id to search in list + * @returns NULL if no UE matchs the ue_eNB_id, or reference to the ue element in list if matches + **/ +ue_description_t* s1ap_is_ue_eNB_id_in_list(eNB_description_t *eNB_ref, + uint32_t eNB_ue_s1ap_id); + +/** \brief Look for given ue mme id in the list + * \param eNB_id The unique ue_mme_id to search in list + * @returns NULL if no UE matchs the ue_mme_id, or reference to the ue element in list if matches + **/ +ue_description_t* s1ap_is_ue_mme_id_in_list(uint32_t ue_mme_id); +ue_description_t* s1ap_is_teid_in_list(uint32_t teid); + +/** \brief Allocate and add to the list a new eNB descriptor + * @returns Reference to the new eNB element in list + **/ +eNB_description_t* s1ap_new_eNB(void); + +/** \brief Allocate and add to the right eNB list a new UE descriptor + * \param sctp_assoc_id association ID over SCTP + * @returns Reference to the new UE element in list + **/ +ue_description_t* s1ap_new_ue(uint32_t sctp_assoc_id); + +/** \brief Dump the eNB list + * Calls dump_eNB for each eNB in list + **/ +void s1ap_dump_eNB_list(void); + +/** \brief Dump eNB related information. + * Calls dump_ue for each UE in list + * \param eNB_ref eNB structure reference to dump + **/ +void s1ap_dump_eNB(eNB_description_t *eNB_ref); + +/** \brief Dump UE related information. + * \param ue_ref ue structure reference to dump + **/ +void s1ap_dump_ue(ue_description_t *ue_ref); + +/** \brief Remove target UE from the list + * \param ue_ref UE structure reference to remove + **/ +void s1ap_remove_ue(ue_description_t *ue_ref); + +/** \brief Remove target eNB from the list and remove any UE associated + * \param eNB_ref eNB structure reference to remove + **/ +void s1ap_remove_eNB(eNB_description_t *eNB_ref); + +#endif /* S1AP_MME_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_decoder.c b/openair-cn/S1AP/s1ap_mme_decoder.c new file mode 100644 index 0000000000..a304acb115 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_decoder.c @@ -0,0 +1,182 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_mme_decoder.c + * \brief s1ap decode procedures for MME + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_mme_decoder.h" +#include "s1ap_mme_handlers.h" + +#if !defined(MME_CLIENT_TEST) +# include "intertask_interface.h" +#endif + +#include "assertions.h" + +static int s1ap_mme_decode_initiating(s1ap_message *message, + InitiatingMessage_t *initiating_p) +{ + int ret = -1; + + DevAssert(initiating_p != NULL); + + message->procedureCode = initiating_p->procedureCode; + message->criticality = initiating_p->criticality; + + switch(initiating_p->procedureCode) { +// case ProcedureCode_id_downlinkNASTransport: +// return s1ap_decode_downlinknastransporties(&message->msg.downlinkNASTransportIEs, &initiating_p->value); + case ProcedureCode_id_uplinkNASTransport: + ret = s1ap_decode_uplinknastransporties(&message->msg.uplinkNASTransportIEs, + &initiating_p->value); + case ProcedureCode_id_S1Setup: { + ret = s1ap_decode_s1setuprequesties(&message->msg.s1SetupRequestIEs, + &initiating_p->value); + s1ap_xer_print_s1setuprequest(stdout, message); + } break; + case ProcedureCode_id_initialUEMessage: { + ret = s1ap_decode_initialuemessageies(&message->msg.initialUEMessageIEs, + &initiating_p->value); + s1ap_xer_print_initialuemessage(stdout, message); + } break; + case ProcedureCode_id_UEContextReleaseRequest: { + ret = s1ap_decode_uecontextreleaserequesties( + &message->msg.ueContextReleaseRequestIEs, &initiating_p->value); + s1ap_xer_print_uecontextreleaserequest(stdout, message); + } break; + case ProcedureCode_id_UECapabilityInfoIndication: { + ret = s1ap_decode_uecapabilityinfoindicationies( + &message->msg.ueCapabilityInfoIndicationIEs, &initiating_p->value); + s1ap_xer_print_uecapabilityinfoindication(stdout, message); + } break; +// case ProcedureCode_id_InitialContextSetup: +// return s1ap_decode_initialcontextsetuprequesties(&message->msg.initialContextSetupRequestIEs, &initiating_p->value); + default: + S1AP_ERROR("Unknown procedure ID (%d) for initiating message\n", + (int)initiating_p->procedureCode); + break; + } + return ret; +} + +static int s1ap_mme_decode_successfull_outcome(s1ap_message *message, + SuccessfulOutcome_t *successfullOutcome_p) +{ + DevAssert(successfullOutcome_p != NULL); + + message->procedureCode = successfullOutcome_p->procedureCode; + message->criticality = successfullOutcome_p->criticality; + + switch(successfullOutcome_p->procedureCode) { + case ProcedureCode_id_InitialContextSetup: + return s1ap_decode_initialcontextsetupresponseies( + &message->msg.initialContextSetupResponseIEs, &successfullOutcome_p->value); + case ProcedureCode_id_UEContextRelease: + return s1ap_decode_uecontextreleasecompleteies( + &message->msg.ueContextReleaseCompleteIEs, &successfullOutcome_p->value); + default: + S1AP_ERROR("Unknown procedure ID (%d) for successfull outcome message\n", + (int)successfullOutcome_p->procedureCode); + break; + } + return -1; +} + +static int s1ap_mme_decode_unsuccessfull_outcome(s1ap_message *message, + UnsuccessfulOutcome_t *unSuccessfulOutcome_p) +{ + DevAssert(unSuccessfulOutcome_p != NULL); + + message->procedureCode = unSuccessfulOutcome_p->procedureCode; + message->criticality = unSuccessfulOutcome_p->criticality; + + switch(unSuccessfulOutcome_p->procedureCode) { + case ProcedureCode_id_InitialContextSetup: + return s1ap_decode_initialcontextsetupfailureies( + &message->msg.initialContextSetupFailureIEs, &unSuccessfulOutcome_p->value); + default: + S1AP_ERROR("Unknown procedure ID (%d) for unsuccessfull outcome message\n", + (int)unSuccessfulOutcome_p->procedureCode); + break; + } + return -1; +} + +int s1ap_mme_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t len) +{ + S1AP_PDU_t pdu; + S1AP_PDU_t *pdu_p = &pdu; + asn_dec_rval_t dec_ret; + + DevAssert(buffer != NULL); + + memset((void *)pdu_p, 0, sizeof(S1AP_PDU_t)); + + dec_ret = aper_decode(NULL, + &asn_DEF_S1AP_PDU, + (void **)&pdu_p, + buffer, + len, + 0, + 0); + + if (dec_ret.code != RC_OK) { + S1AP_ERROR("Failed to decode PDU\n"); + return -1; + } + + message->direction = pdu_p->present; + + switch(pdu_p->present) { + case S1AP_PDU_PR_initiatingMessage: + return s1ap_mme_decode_initiating(message, &pdu_p->choice.initiatingMessage); + case S1AP_PDU_PR_successfulOutcome: + return s1ap_mme_decode_successfull_outcome(message, + &pdu_p->choice.successfulOutcome); + case S1AP_PDU_PR_unsuccessfulOutcome: + return s1ap_mme_decode_unsuccessfull_outcome(message, + &pdu_p->choice.unsuccessfulOutcome); + default: + S1AP_ERROR("Unknown message outcome (%d) or not implemented", + (int)pdu_p->present); + break; + } + return -1; +} diff --git a/openair-cn/S1AP/s1ap_mme_decoder.h b/openair-cn/S1AP/s1ap_mme_decoder.h new file mode 100644 index 0000000000..59ccc973ba --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_decoder.h @@ -0,0 +1,40 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" + +#ifndef S1AP_MME_DECODER_H_ +#define S1AP_MME_DECODER_H_ + +int s1ap_mme_decode_pdu(s1ap_message *message, uint8_t *buffer, uint32_t len) +__attribute__ ((warn_unused_result)); + +#endif /* S1AP_MME_DECODER_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_encoder.c b/openair-cn/S1AP/s1ap_mme_encoder.c new file mode 100644 index 0000000000..13f93fabc3 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_encoder.c @@ -0,0 +1,255 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s1ap_mme_encoder.c + * \brief s1ap encode procedures for MME + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2012 + * \version 0.1 + */ + +#include "intertask_interface.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_mme_encoder.h" +#include "s1ap_mme.h" + +#include "assertions.h" + +static inline +int s1ap_mme_encode_initial_context_setup_request(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length); +static inline +int s1ap_mme_encode_s1setupresponse(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length); +static inline +int s1ap_mme_encode_s1setupfailure(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length); +static inline +int s1ap_mme_encode_ue_context_release_command(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length); +static inline +int s1ap_mme_encode_downlink_nas_transport( + s1ap_message *message_p, uint8_t **buffer, uint32_t *length); + +static inline +int s1ap_mme_encode_initiating(s1ap_message *message_p, + uint8_t **buffer, + uint32_t *length); +static inline +int s1ap_mme_encode_successfull_outcome(s1ap_message *message_p, + uint8_t **buffer, uint32_t *len); +static inline +int s1ap_mme_encode_unsuccessfull_outcome(s1ap_message *message_p, + uint8_t **buffer, uint32_t *len); + +static inline +int s1ap_mme_encode_initial_context_setup_request(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + InitialContextSetupRequest_t initialContextSetupRequest; + InitialContextSetupRequest_t *initialContextSetupRequest_p = + &initialContextSetupRequest; + + memset(initialContextSetupRequest_p, 0, sizeof(InitialContextSetupRequest_t)); + + if (s1ap_encode_initialcontextsetuprequesties(initialContextSetupRequest_p, + &message_p->msg.initialContextSetupRequestIEs) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_InitialContextSetup, + Criticality_reject, + &asn_DEF_InitialContextSetupRequest, + initialContextSetupRequest_p); +} + +int s1ap_mme_encode_pdu(s1ap_message *message_p, uint8_t **buffer, uint32_t *length) +{ + DevAssert(message_p != NULL); + DevAssert(buffer != NULL); + DevAssert(length != NULL); + + switch(message_p->direction) { + case S1AP_PDU_PR_initiatingMessage: + return s1ap_mme_encode_initiating(message_p, buffer, length); + case S1AP_PDU_PR_successfulOutcome: + return s1ap_mme_encode_successfull_outcome(message_p, buffer, length); + case S1AP_PDU_PR_unsuccessfulOutcome: + return s1ap_mme_encode_unsuccessfull_outcome(message_p, buffer, length); + default: + S1AP_DEBUG("Unknown message outcome (%d) or not implemented", + (int)message_p->direction); + break; + } + return -1; +} + +static inline +int s1ap_mme_encode_initiating(s1ap_message *message_p, + uint8_t **buffer, + uint32_t *length) +{ + switch(message_p->procedureCode) { + case ProcedureCode_id_downlinkNASTransport: + return s1ap_mme_encode_downlink_nas_transport(message_p, buffer, length); + case ProcedureCode_id_InitialContextSetup: + return s1ap_mme_encode_initial_context_setup_request(message_p, buffer, length); + case ProcedureCode_id_UEContextRelease: + return s1ap_mme_encode_ue_context_release_command(message_p, buffer, length); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for initiating message_p\n", + (int)message_p->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_mme_encode_successfull_outcome(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + switch(message_p->procedureCode) { + case ProcedureCode_id_S1Setup: + return s1ap_mme_encode_s1setupresponse(message_p, buffer, length); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for successfull outcome message_p\n", + (int)message_p->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_mme_encode_unsuccessfull_outcome(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + switch(message_p->procedureCode) { + case ProcedureCode_id_S1Setup: + return s1ap_mme_encode_s1setupfailure(message_p, buffer, length); + default: + S1AP_DEBUG("Unknown procedure ID (%d) for unsuccessfull outcome message_p\n", + (int)message_p->procedureCode); + break; + } + return -1; +} + +static inline +int s1ap_mme_encode_s1setupresponse(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + S1SetupResponse_t s1SetupResponse; + S1SetupResponse_t *s1SetupResponse_p = &s1SetupResponse; + + memset(s1SetupResponse_p, 0, sizeof(S1SetupResponse_t)); + + if (s1ap_encode_s1setupresponseies(s1SetupResponse_p, &message_p->msg.s1SetupResponseIEs) < 0) { + return -1; + } + + return s1ap_generate_successfull_outcome(buffer, + length, + ProcedureCode_id_S1Setup, + message_p->criticality, + &asn_DEF_S1SetupResponse, + s1SetupResponse_p); +} + +static inline +int s1ap_mme_encode_s1setupfailure(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + S1SetupFailure_t s1SetupFailure; + S1SetupFailure_t *s1SetupFailure_p = &s1SetupFailure; + + memset(s1SetupFailure_p, 0, sizeof(S1SetupFailure_t)); + + if (s1ap_encode_s1setupfailureies(s1SetupFailure_p, &message_p->msg.s1SetupFailureIEs) < 0) { + return -1; + } + + return s1ap_generate_unsuccessfull_outcome(buffer, + length, + ProcedureCode_id_S1Setup, + message_p->criticality, + &asn_DEF_S1SetupFailure, + s1SetupFailure_p); +} + +static inline +int s1ap_mme_encode_downlink_nas_transport( + s1ap_message *message_p, uint8_t **buffer, uint32_t *length) +{ + DownlinkNASTransport_t downlinkNasTransport; + DownlinkNASTransport_t *downlinkNasTransport_p = &downlinkNasTransport; + + memset(downlinkNasTransport_p, 0, sizeof(DownlinkNASTransport_t)); + + /* Convert IE structure into asn1 message_p */ + if (s1ap_encode_downlinknastransporties(downlinkNasTransport_p, + &message_p->msg.downlinkNASTransportIEs) < 0) { + return -1; + } + + /* Generate Initiating message_p for the list of IEs */ + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_downlinkNASTransport, + message_p->criticality, + &asn_DEF_DownlinkNASTransport, + downlinkNasTransport_p); +} + +static inline +int s1ap_mme_encode_ue_context_release_command(s1ap_message *message_p, + uint8_t **buffer, uint32_t *length) +{ + UEContextReleaseCommand_t ueContextReleaseCommand; + UEContextReleaseCommand_t *ueContextReleaseCommand_p = &ueContextReleaseCommand; + + memset(ueContextReleaseCommand_p, 0, sizeof(UEContextReleaseCommand_t)); + + /* Convert IE structure into asn1 message_p */ + if (s1ap_encode_uecontextreleasecommandies(ueContextReleaseCommand_p, + &message_p->msg.ueContextReleaseCommandIEs) < 0) { + return -1; + } + + return s1ap_generate_initiating_message(buffer, + length, + ProcedureCode_id_UEContextRelease, + message_p->criticality, + &asn_DEF_UEContextReleaseCommand, + ueContextReleaseCommand_p); +} diff --git a/openair-cn/S1AP/s1ap_mme_encoder.h b/openair-cn/S1AP/s1ap_mme_encoder.h new file mode 100644 index 0000000000..da557ddce2 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_encoder.h @@ -0,0 +1,39 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#ifndef S1AP_MME_ENCODER_H_ +#define S1AP_MME_ENCODER_H_ + +int s1ap_mme_encode_pdu(s1ap_message *message, uint8_t **buffer, uint32_t *len) +__attribute__ ((warn_unused_result)); + +#endif /* S1AP_MME_ENCODER_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_handlers.c b/openair-cn/S1AP/s1ap_mme_handlers.c new file mode 100644 index 0000000000..5aae56e63b --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_handlers.c @@ -0,0 +1,892 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#include "mme_config.h" +#include "assertions.h" +#include "conversions.h" + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_mme_encoder.h" +#include "s1ap_mme_handlers.h" +#include "s1ap_mme_nas_procedures.h" + +#include "s1ap_mme_itti_messaging.h" + +#include "s1ap_mme.h" +#include "s1ap_mme_ta.h" + +static int s1ap_generate_s1_setup_response(eNB_description_t *eNB_association); +static int s1ap_mme_generate_ue_context_release_command( + ue_description_t *ue_ref); + +//Forward declaration +struct s1ap_message_s; + +/* Handlers matrix. Only mme related procedures present here. + */ +s1ap_message_decoded_callback messages_callback[][3] = { + { 0, 0, 0 }, /* HandoverPreparation */ + { 0, 0, 0 }, /* HandoverResourceAllocation */ + { 0, 0, 0 }, /* HandoverNotification */ + { s1ap_mme_handle_path_switch_request, 0, 0 }, /* PathSwitchRequest */ + { 0, 0, 0 }, /* HandoverCancel */ + { 0, 0, 0 }, /* E_RABSetup */ + { 0, 0, 0 }, /* E_RABModify */ + { 0, 0, 0 }, /* E_RABRelease */ + { 0, 0, 0 }, /* E_RABReleaseIndication */ + { + 0, s1ap_mme_handle_initial_context_setup_response, + s1ap_mme_handle_initial_context_setup_failure + }, /* InitialContextSetup */ + { 0, 0, 0 }, /* Paging */ + { 0, 0, 0 }, /* downlinkNASTransport */ + { s1ap_mme_handle_initial_ue_message, 0, 0 }, /* initialUEMessage */ + { s1ap_mme_handle_uplink_nas_transport, 0, 0 }, /* uplinkNASTransport */ + { 0, 0, 0 }, /* Reset */ + { 0, 0, 0 }, /* ErrorIndication */ + { s1ap_mme_handle_nas_non_delivery, 0, 0 }, /* NASNonDeliveryIndication */ + { s1ap_mme_handle_s1_setup_request, 0, 0 }, /* S1Setup */ + { 0, 0, 0 }, /* UEContextReleaseRequest */ + { 0, 0, 0 }, /* DownlinkS1cdma2000tunneling */ + { 0, 0, 0 }, /* UplinkS1cdma2000tunneling */ + { 0, 0, 0 }, /* UEContextModification */ + { s1ap_mme_handle_ue_cap_indication, 0, 0 }, /* UECapabilityInfoIndication*/ + { + s1ap_mme_handle_ue_context_release_request, + s1ap_mme_handle_ue_context_release_complete, 0 + }, /* UEContextRelease*/ + { 0, 0, 0 }, /* eNBStatusTransfer*/ + { 0, 0, 0 }, /* MMEStatusTransfer*/ + { 0, 0, 0 }, /* DeactivateTrace*/ + { 0, 0, 0 }, /* TraceStart*/ + { 0, 0, 0 }, /* TraceFailureIndication*/ + { 0, 0, 0 }, /* ENBConfigurationUpdate*/ + { 0, 0, 0 }, /* MMEConfigurationUpdate*/ + { 0, 0, 0 }, /* LocationReportingControl*/ + { 0, 0, 0 }, /* LocationReportingFailureIndication*/ + { 0, 0, 0 }, /* LocationReport*/ + { 0, 0, 0 }, /* OverloadStart*/ + { 0, 0, 0 }, /* OverloadStop*/ + { 0, 0, 0 }, /* WriteReplaceWarning*/ + { 0, 0, 0 }, /* eNBDirectInformationTransfer*/ + { 0, 0, 0 }, /* MMEDirectInformationTransfer*/ + { 0, 0, 0 }, /* PrivateMessage*/ + { 0, 0, 0 }, /* eNBConfigurationTransfer*/ + { 0, 0, 0 }, /* MMEConfigurationTransfer*/ + { 0, 0, 0 }, /* CellTrafficTrace */ +#if defined(UPDATE_RELEASE_9) + { 0, 0, 0 }, /* Kill */ + { 0, 0, 0 }, /* DownlinkUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* UplinkUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* DownlinkNonUEAssociatedLPPaTransport */ + { 0, 0, 0 }, /* UplinkNonUEAssociatedLPPaTransport */ +#endif +}; + +static const char *direction2String[] = { + "", /* Nothing */ + "Originating message", /* originating message */ + "Successfull outcome", /* successfull outcome */ + "UnSuccessfull outcome", /* successfull outcome */ +}; + +int s1ap_mme_handle_message(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + /* Checking procedure Code and direction of message */ + if ((message->procedureCode > (sizeof(messages_callback) / (3 * sizeof( + s1ap_message_decoded_callback)))) || + (message->direction > S1AP_PDU_PR_unsuccessfulOutcome)) { + + S1AP_DEBUG("[SCTP %d] Either procedureCode %d or direction %d exceed expected\n", + assoc_id, (int)message->procedureCode, (int)message->direction); + return -1; + } + /* No handler present. + * This can mean not implemented or no procedure for eNB (wrong message). + */ + if (messages_callback[message->procedureCode][message->direction-1] == NULL) { + S1AP_DEBUG("[SCTP %d] No handler for procedureCode %d in %s\n", assoc_id, + (int)message->procedureCode, + direction2String[(int)message->direction]); + return -2; + } + + /* Calling the right handler */ + return (*messages_callback[message->procedureCode][message->direction-1])( + assoc_id, stream, message); +} + +int s1ap_mme_set_cause(Cause_t *cause_p, Cause_PR cause_type, long cause_value) +{ + DevAssert(cause_p != NULL); + + cause_p->present = cause_type; + + switch(cause_type) + { + case Cause_PR_radioNetwork: + cause_p->choice.misc = cause_value; + break; + case Cause_PR_transport: + cause_p->choice.transport = cause_value; + break; + case Cause_PR_nas: + cause_p->choice.nas = cause_value; + break; + case Cause_PR_protocol: + cause_p->choice.protocol = cause_value; + break; + case Cause_PR_misc: + cause_p->choice.misc = cause_value; + break; + default: + return -1; + } + return 0; +} + +int s1ap_mme_generate_s1_setup_failure( + uint32_t assoc_id, Cause_PR cause_type, long cause_value, + long time_to_wait) +{ + uint8_t *buffer_p; + uint32_t length; + s1ap_message message; + S1SetupFailureIEs_t *s1_setup_failure_p; + + memset(&message, 0, sizeof(s1ap_message)); + + s1_setup_failure_p = &message.msg.s1SetupFailureIEs; + + message.procedureCode = ProcedureCode_id_S1Setup; + message.direction = S1AP_PDU_PR_unsuccessfulOutcome; + + s1ap_mme_set_cause(&s1_setup_failure_p->cause, cause_type, cause_value); + + /* Include the optional field time to wait only if the value is > -1 */ + if (time_to_wait > -1) { + s1_setup_failure_p->presenceMask |= S1SETUPFAILUREIES_TIMETOWAIT_PRESENT; + s1_setup_failure_p->timeToWait = time_to_wait; + } + + if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) { + S1AP_ERROR("Failed to encode s1 setup failure\n"); + return -1; + } + + return s1ap_mme_itti_send_sctp_request(buffer_p, length, assoc_id, 0); +} + +//////////////////////////////////////////////////////////////////////////////// +//************************** Management procedures ***************************// +//////////////////////////////////////////////////////////////////////////////// + +int s1ap_mme_handle_s1_setup_request(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + S1SetupRequestIEs_t *s1SetupRequest_p; + eNB_description_t *eNB_association; + uint32_t eNB_id = 0; + char *eNB_name = NULL; + int ta_ret; + uint16_t max_enb_connected; + + DevAssert(message != NULL); + + s1SetupRequest_p = &message->msg.s1SetupRequestIEs; + + /* We received a new valid S1 Setup Request on a stream != 0. + * This should not happen -> reject eNB s1 setup request. + */ + if (stream != 0) { + S1AP_DEBUG("Received new s1 setup request on stream != 0\n"); + /* Send a s1 setup failure with protocol cause unspecified */ + return s1ap_mme_generate_s1_setup_failure(assoc_id, Cause_PR_protocol, + CauseProtocol_unspecified, -1); + } + + S1AP_DEBUG("New s1 setup request incoming from "); + if ((s1SetupRequest_p->presenceMask & S1SETUPREQUESTIES_ENBNAME_PRESENT) == + S1SETUPREQUESTIES_ENBNAME_PRESENT) { + S1AP_DEBUG("%*s ", s1SetupRequest_p->eNBname.size, s1SetupRequest_p->eNBname.buf); + eNB_name = (char *)s1SetupRequest_p->eNBname.buf; + } + if (s1SetupRequest_p->global_ENB_ID.eNB_ID.present == ENB_ID_PR_homeENB_ID) { + // Home eNB ID = 28 bits + uint8_t *eNB_id_buf = + s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.homeENB_ID.buf; + if (s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.size != 28) { + //TODO: handle case were size != 28 -> notify ? reject ? + } + eNB_id = (eNB_id_buf[0] << 20) + (eNB_id_buf[1] << 12) + + (eNB_id_buf[2] << 4) + ((eNB_id_buf[3] & 0xf0) >> 4); + S1AP_DEBUG("home eNB id: %u\n", eNB_id); + } else { + // Macro eNB = 20 bits + uint8_t *eNB_id_buf = + s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf; + if (s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.size != 20) { + //TODO: handle case were size != 20 -> notify ? reject ? + } + eNB_id = (eNB_id_buf[0] << 12) + (eNB_id_buf[1] << 4) + (( + eNB_id_buf[2] & 0xf0) >> 4); + S1AP_DEBUG("macro eNB id: %u\n", eNB_id); + } + + config_read_lock(&mme_config); + max_enb_connected = mme_config.max_eNBs; + config_unlock(&mme_config); + + if (nb_eNB_associated == max_enb_connected) { + S1AP_DEBUG("There is too much eNB connected to MME, rejecting the association\n"); + S1AP_DEBUG("Connected = %d, maximum allowed = %d\n", nb_eNB_associated, + max_enb_connected); + + /* Send an overload cause... */ + return s1ap_mme_generate_s1_setup_failure(assoc_id, Cause_PR_misc, + CauseMisc_control_processing_overload, + TimeToWait_v20s); + } + + /* If none of the provided PLMNs/TAC match the one configured in MME, + * the s1 setup should be rejected with a cause set to Unknown PLMN. + */ + ta_ret = s1ap_mme_compare_ta_lists(&s1SetupRequest_p->supportedTAs); + + /* eNB and MME have no common PLMN */ + if (ta_ret != TA_LIST_RET_OK) { + return s1ap_mme_generate_s1_setup_failure(assoc_id, Cause_PR_misc, + CauseMisc_unknown_PLMN, + TimeToWait_v20s); + } + + S1AP_DEBUG("Adding eNB to the list of served eNBs\n"); + + if ((eNB_association = s1ap_is_eNB_id_in_list(eNB_id)) == NULL) { + /* eNB has not been fount in list of associated eNB, + * Add it to the tail of list and initialize data */ + if ((eNB_association = s1ap_is_eNB_assoc_id_in_list(assoc_id)) == NULL) { + /* ?? */ + return -1; + } else { + eNB_association->s1_state = S1AP_RESETING; + eNB_association->eNB_id = eNB_id; + eNB_association->default_paging_drx = s1SetupRequest_p->defaultPagingDRX; + + if (eNB_name != NULL) { + memcpy(eNB_association->eNB_name, s1SetupRequest_p->eNBname.buf, + s1SetupRequest_p->eNBname.size); + eNB_association->eNB_name[s1SetupRequest_p->eNBname.size] = '\0'; + } + } + } else { + eNB_association->s1_state = S1AP_RESETING; + /* eNB has been fount in list, consider the s1 setup request as a reset connection, + * reseting any previous UE state if sctp association is != than the previous one */ + if (eNB_association->sctp_assoc_id != assoc_id) { + S1SetupFailureIEs_t s1SetupFailure; + memset(&s1SetupFailure, 0, sizeof(S1SetupFailureIEs_t)); + + /* Send an overload cause... */ + s1SetupFailure.cause.present = Cause_PR_misc; //TODO: send the right cause + s1SetupFailure.cause.choice.misc = CauseMisc_control_processing_overload; + S1AP_DEBUG("Rejeting s1 setup request as eNB id %d is already associated to an active sctp association" + "Previous known: %d, new one: %d\n", + eNB_id, eNB_association->sctp_assoc_id, assoc_id); +// s1ap_mme_encode_s1setupfailure(&s1SetupFailure, +// receivedMessage->msg.s1ap_sctp_new_msg_ind.assocId); + return -1; + } + /* TODO: call the reset procedure */ + } + s1ap_dump_eNB(eNB_association); + return s1ap_generate_s1_setup_response(eNB_association); +} + +static +int s1ap_generate_s1_setup_response(eNB_description_t *eNB_association) +{ + int i; + int enc_rval = 0; + S1SetupResponseIEs_t *s1_setup_response_p; + ServedGUMMEIsItem_t servedGUMMEI; + s1ap_message message; + uint8_t *buffer; + uint32_t length; + + DevAssert(eNB_association != NULL); + + // Generating response + memset(&message, 0, sizeof(s1ap_message)); + memset(&servedGUMMEI, 0, sizeof(ServedGUMMEIsItem_t)); + + s1_setup_response_p = &message.msg.s1SetupResponseIEs; + + config_read_lock(&mme_config); + + s1_setup_response_p->relativeMMECapacity = mme_config.relative_capacity; + + /* Use the gummei parameters provided by configuration */ + for (i = 0; i < mme_config.gummei.nb_plmns; i++) { + PLMNidentity_t *plmn; + + /* FIXME: free object from list once encoded */ + plmn = calloc(1, sizeof(PLMNidentity_t)); + MCC_MNC_TO_PLMNID(mme_config.gummei.plmn_mcc[i], + mme_config.gummei.plmn_mnc[i], + plmn); + ASN_SEQUENCE_ADD(&servedGUMMEI.servedPLMNs.list, plmn); + } + for (i = 0; i < mme_config.gummei.nb_mme_gid; i++) { + MME_Group_ID_t *mme_gid; + + /* FIXME: free object from list once encoded */ + mme_gid = calloc(1, sizeof(MME_Group_ID_t)); + INT16_TO_OCTET_STRING(mme_config.gummei.mme_gid[i], mme_gid); + ASN_SEQUENCE_ADD(&servedGUMMEI.servedGroupIDs.list, mme_gid); + } + for (i = 0; i < mme_config.gummei.nb_mmec; i++) { + MME_Code_t *mmec; + + /* FIXME: free object from list once encoded */ + mmec = calloc(1, sizeof(MME_Code_t)); + INT8_TO_OCTET_STRING(mme_config.gummei.mmec[i], mmec); + ASN_SEQUENCE_ADD(&servedGUMMEI.servedMMECs.list, mmec); + } + + config_unlock(&mme_config); + + /* The MME is only serving E-UTRAN RAT, so the list contains only one element */ + ASN_SEQUENCE_ADD(&s1_setup_response_p->servedGUMMEIs, &servedGUMMEI); + + message.procedureCode = ProcedureCode_id_S1Setup; + message.direction = S1AP_PDU_PR_successfulOutcome; + + enc_rval = s1ap_mme_encode_pdu(&message, &buffer, &length); + /* Failed to encode s1 setup response... */ + if (enc_rval < 0) { + S1AP_DEBUG("Removed eNB %d\n", eNB_association->sctp_assoc_id); + s1ap_remove_eNB(eNB_association); + } else { + /* Consider the response as sent. S1AP is ready to accept UE contexts */ + eNB_association->s1_state = S1AP_READY; + } + + /* Non-UE signalling -> stream 0 */ + return s1ap_mme_itti_send_sctp_request(buffer, length, eNB_association->sctp_assoc_id, + 0); +} + +int s1ap_mme_handle_ue_cap_indication(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + ue_description_t *ue_ref; + UECapabilityInfoIndicationIEs_t *ue_cap_p; + + DevAssert(message != NULL); + + ue_cap_p = &message->msg.ueCapabilityInfoIndicationIEs; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list(ue_cap_p->mme_ue_s1ap_id)) == NULL) { + S1AP_DEBUG("No UE is attached to this mme UE s1ap id: 0x%08x\n", + (uint32_t)ue_cap_p->mme_ue_s1ap_id); + return -1; + } + if (ue_ref->eNB_ue_s1ap_id != ue_cap_p->eNB_UE_S1AP_ID) { + S1AP_DEBUG("Mismatch in eNB UE S1AP ID, known: 0x%06x, received: 0x%06x\n", + ue_ref->eNB_ue_s1ap_id, (uint32_t)ue_cap_p->eNB_UE_S1AP_ID); + return -1; + } + + /* Just display a warning when message received over wrong stream */ + if (ue_ref->sctp_stream_recv != stream) { + S1AP_ERROR("Received ue capability indication for " + "(MME UE S1AP ID/eNB UE S1AP ID) (0x%08x/0x%06x) over wrong stream " + "expecting %u, received on %u\n", + (uint32_t)ue_cap_p->mme_ue_s1ap_id, ue_ref->eNB_ue_s1ap_id, + ue_ref->sctp_stream_recv, stream); + } + + /* Forward the ue capabilities to MME application layer */ + { + MessageDef *message_p; + s1ap_ue_cap_ind_t *ue_cap_ind_p; + + message_p = alloc_new_message(TASK_S1AP, S1AP_UE_CAPABILITIES_IND); + + DevAssert(message_p != NULL); + + ue_cap_ind_p = &message_p->msg.s1ap_ue_cap_ind; + ue_cap_ind_p->eNB_ue_s1ap_id = ue_ref->eNB_ue_s1ap_id; + ue_cap_ind_p->mme_ue_s1ap_id = ue_ref->mme_ue_s1ap_id; + + DevCheck(ue_cap_p->ueRadioCapability.size < 100, + 100, ue_cap_p->ueRadioCapability.size, 0); + + memcpy(ue_cap_ind_p->radio_capabilities, ue_cap_p->ueRadioCapability.buf, + ue_cap_p->ueRadioCapability.size); + + ue_cap_ind_p->radio_capabilities_length = ue_cap_p->ueRadioCapability.size; + + return send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//******************* Context Management procedures **************************// +//////////////////////////////////////////////////////////////////////////////// + +int s1ap_mme_handle_initial_context_setup_response( + uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *message) +{ + + InitialContextSetupResponseIEs_t *initialContextSetupResponseIEs_p; + ue_description_t *ue_ref; + SgwModifyBearerRequest *modify_request_p; + MessageDef *message_p; + E_RABSetupItemCtxtSURes_t *eRABSetupItemCtxtSURes_p; + + initialContextSetupResponseIEs_p = &message->msg.initialContextSetupResponseIEs; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list( + (uint32_t)initialContextSetupResponseIEs_p->mme_ue_s1ap_id)) == NULL) { + S1AP_DEBUG("No UE is attached to this mme UE s1ap id: 0x%08x\n", + (uint32_t)initialContextSetupResponseIEs_p->mme_ue_s1ap_id); + return -1; + } + if (ue_ref->eNB_ue_s1ap_id != + initialContextSetupResponseIEs_p->eNB_UE_S1AP_ID) { + S1AP_DEBUG("Mismatch in eNB UE S1AP ID, known: 0x%06x, received: 0x%06x\n", + ue_ref->eNB_ue_s1ap_id, + (uint32_t)initialContextSetupResponseIEs_p->eNB_UE_S1AP_ID); + return -1; + } + + if (initialContextSetupResponseIEs_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes.count + != 1) { + S1AP_DEBUG("E-RAB creation has failed\n"); + return -1; + } + + ue_ref->s1_ue_state = S1AP_UE_CONNECTED; + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_REQUEST); + + if (message_p == NULL) { + return -1; + } + + eRABSetupItemCtxtSURes_p = (E_RABSetupItemCtxtSURes_t *) + initialContextSetupResponseIEs_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes.array[0]; + + modify_request_p = &message_p->msg.sgwModifyBearerRequest; +// modify_request_p->teid = ue_ref->teid; + modify_request_p->bearer_context_to_modify.eps_bearer_id = + eRABSetupItemCtxtSURes_p->e_RAB_ID; + modify_request_p->bearer_context_to_modify.s1_eNB_fteid.teid = *(( + uint32_t *)eRABSetupItemCtxtSURes_p->gTP_TEID.buf); + modify_request_p->bearer_context_to_modify.s1_eNB_fteid.ipv4 = 1; + memcpy(&modify_request_p->bearer_context_to_modify.s1_eNB_fteid.ipv4_address, + eRABSetupItemCtxtSURes_p->transportLayerAddress.buf, 4); + + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +int s1ap_mme_handle_ue_context_release_request(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message) +{ + UEContextReleaseRequestIEs_t *ueContextReleaseRequest_p; + ue_description_t *ue_ref = NULL; + + ueContextReleaseRequest_p = &message->msg.ueContextReleaseRequestIEs; + + /* The UE context release procedure is initiated if the cause is != than user inactivity. + * TS36.413 #8.3.2.2. + */ + if (ueContextReleaseRequest_p->cause.present == Cause_PR_radioNetwork) { + if (ueContextReleaseRequest_p->cause.choice.radioNetwork == + CauseRadioNetwork_user_inactivity) { + return -1; + } + } + if ((ue_ref = s1ap_is_ue_mme_id_in_list( + ueContextReleaseRequest_p->mme_ue_s1ap_id)) == NULL) { + /* MME doesn't know the MME UE S1AP ID provided. + * TODO + */ + return -1; + } else { + if (ue_ref->eNB_ue_s1ap_id == (ueContextReleaseRequest_p->eNB_UE_S1AP_ID & + 0x00ffffff)) { + /* Both eNB UE S1AP ID and MME UE S1AP ID match. + * -> Send a UE context Release Command to eNB. + * TODO + */ + } else { + // TODO + return -1; + } + } + return 0; +} + +static int s1ap_mme_generate_ue_context_release_command( + ue_description_t *ue_ref) +{ + uint8_t *buffer; + uint32_t length; + + s1ap_message message; + UEContextReleaseCommandIEs_t *ueContextReleaseCommandIEs_p; + + if (ue_ref == NULL) { + return -1; + } + memset(&message, 0, sizeof(s1ap_message)); + + message.procedureCode = ProcedureCode_id_UEContextRelease; + message.direction = S1AP_PDU_PR_successfulOutcome; + + ueContextReleaseCommandIEs_p = &message.msg.ueContextReleaseCommandIEs; + + /* Fill in ID pair */ + ueContextReleaseCommandIEs_p->uE_S1AP_IDs.present = UE_S1AP_IDs_PR_uE_S1AP_ID_pair; + ueContextReleaseCommandIEs_p->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID = + ue_ref->mme_ue_s1ap_id; + ueContextReleaseCommandIEs_p->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID = + ue_ref->eNB_ue_s1ap_id; + ueContextReleaseCommandIEs_p->uE_S1AP_IDs.choice.uE_S1AP_ID_pair.iE_Extensions = + NULL; + + ueContextReleaseCommandIEs_p->cause.present = Cause_PR_radioNetwork; + ueContextReleaseCommandIEs_p->cause.choice.radioNetwork = + CauseRadioNetwork_release_due_to_eutran_generated_reason; + + if (s1ap_mme_encode_pdu(&message, &buffer, &length) < 0) { + return -1; + } + return s1ap_mme_itti_send_sctp_request(buffer, length, ue_ref->eNB->sctp_assoc_id, + ue_ref->sctp_stream_send); +} + +int s1ap_mme_handle_ue_context_release_complete(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message) +{ + UEContextReleaseCompleteIEs_t *ueContextReleaseComplete_p; + ue_description_t *ue_ref = NULL; + + ueContextReleaseComplete_p = &message->msg.ueContextReleaseCompleteIEs; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list( + ueContextReleaseComplete_p->mme_ue_s1ap_id)) == NULL) { + /* MME doesn't know the MME UE S1AP ID provided. + * TODO + */ + return -1; + } + /* eNB has sent a release complete message. We can safely remove UE context. + * TODO: inform NAS and remove e-RABS. + */ + s1ap_remove_ue(ue_ref); + S1AP_DEBUG("Removed UE %u\n", + (uint32_t)ueContextReleaseComplete_p->mme_ue_s1ap_id); + return 0; +} + +int s1ap_mme_handle_initial_context_setup_failure(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message) +{ + InitialContextSetupFailureIEs_t *initialContextSetupFailureIEs_p; + ue_description_t *ue_ref = NULL; + + initialContextSetupFailureIEs_p = &message->msg.initialContextSetupFailureIEs; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list( + initialContextSetupFailureIEs_p->mme_ue_s1ap_id)) == NULL) { + /* MME doesn't know the MME UE S1AP ID provided. */ + return -1; + } + if (ue_ref->eNB_ue_s1ap_id != (initialContextSetupFailureIEs_p->eNB_UE_S1AP_ID + & 0x00ffffff)) { + return -1; + } + S1AP_DEBUG("Removed UE %u\n", + (uint32_t)initialContextSetupFailureIEs_p->mme_ue_s1ap_id); + s1ap_remove_ue(ue_ref); + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//************************ Handover signalling *******************************// +//////////////////////////////////////////////////////////////////////////////// + +int s1ap_mme_handle_path_switch_request(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + PathSwitchRequestIEs_t *pathSwitchRequest_p; + ue_description_t *ue_ref; + uint32_t eNB_ue_s1ap_id; + + pathSwitchRequest_p = &message->msg.pathSwitchRequestIEs; + + // eNB UE S1AP ID is limited to 24 bits + eNB_ue_s1ap_id = (uint32_t)(pathSwitchRequest_p->eNB_UE_S1AP_ID & 0x00ffffff); + + S1AP_DEBUG("Path Switch Request message received from eNB UE S1AP ID: %d\n", + (int)eNB_ue_s1ap_id); + + if ((ue_ref = s1ap_is_ue_mme_id_in_list( + pathSwitchRequest_p->sourceMME_UE_S1AP_ID)) == NULL) { + /* The MME UE S1AP ID provided by eNB doesn't point to any valid UE. + * MME replies with a PATH SWITCH REQUEST FAILURE message and start operation + * as described in TS 36.413 [11]. + * TODO + */ + } else { + if (ue_ref->eNB_ue_s1ap_id != eNB_ue_s1ap_id) { + /* Received unique UE eNB ID mismatch with the one known in MME. + * Handle this case as defined upper. + * TODO + */ + return -1; + } + //TODO: Switch the eRABs provided + } + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// +//************************* E-RAB management *********************************// +//////////////////////////////////////////////////////////////////////////////// + +int s1ap_handle_sctp_deconnection(uint32_t assoc_id) +{ + eNB_description_t *eNB_association; + + /* Checking that the assoc id has a valid eNB attached to. */ + if ((eNB_association = s1ap_is_eNB_assoc_id_in_list(assoc_id)) == NULL) { + S1AP_DEBUG("No eNB attached to this assoc_id: %d\n", + assoc_id); + return -1; + } + s1ap_remove_eNB(eNB_association); + s1ap_dump_eNB_list(); + + S1AP_DEBUG("Removed eNB attached to assoc_id: %d\n", + assoc_id); + return 0; +} + +int s1ap_handle_new_association(sctp_new_peer_t *sctp_new_peer_p) +{ + eNB_description_t *eNB_association; + + DevAssert(sctp_new_peer_p != NULL); + + /* Checking that the assoc id has a valid eNB attached to. */ + if ((eNB_association = s1ap_is_eNB_assoc_id_in_list(sctp_new_peer_p->assoc_id)) == NULL) { + S1AP_DEBUG("Create eNB context for assoc_id: %d\n", + sctp_new_peer_p->assoc_id); + /* Create new context */ + eNB_association = s1ap_new_eNB(); + if (eNB_association == NULL) { + /* We failed to allocate memory */ + /* TODO: send reject there */ + S1AP_ERROR("Failed to allocate eNB context for assoc_id: %d\n", + sctp_new_peer_p->assoc_id); + } + } else { + S1AP_DEBUG("eNB context already exists for assoc_id: %d, update it\n", + sctp_new_peer_p->assoc_id); + } + + eNB_association->sctp_assoc_id = sctp_new_peer_p->assoc_id; + + /* Fill in in and out number of streams available on SCTP connection. */ + eNB_association->instreams = sctp_new_peer_p->instreams; + eNB_association->outstreams = sctp_new_peer_p->outstreams; + + /* initialize the next sctp stream to 1 as 0 is reserved for non + * ue associated signalling. + */ + eNB_association->next_sctp_stream = 1; + + return 0; +} + +int s1ap_handle_create_session_response(SgwCreateSessionResponse + *session_response_p) +{ + /* We received create session response from S-GW on S11 interface abstraction. + * At least one bearer has been established. We can now send s1ap initial context setup request + * message to eNB. + */ + char supportedAlgorithms[] = { 0x02, 0xa0 }; + char securityKey[] = { 0xfd, 0x23, 0xad, 0x22, 0xd0, 0x21, 0x02, 0x90, 0x19, 0xed, + 0xcf, 0xc9, 0x78, 0x44, 0xba, 0xbb, 0x34, 0x6e, 0xff, 0x89, + 0x1c, 0x3a, 0x56, 0xf0, 0x81, 0x34, 0xdd, 0xee, 0x19, 0x55, + 0xf2, 0x1f + }; + + ue_description_t *ue_ref = NULL; + s1ap_message message; + InitialContextSetupRequestIEs_t *initialContextSetupRequest_p; + E_RABToBeSetupItemCtxtSUReq_t e_RABToBeSetup; + uint8_t *buffer_p; + uint32_t length; + + DevAssert(session_response_p != NULL); + + DevCheck(session_response_p->bearer_context_created.cause == REQUEST_ACCEPTED, + REQUEST_ACCEPTED, session_response_p->bearer_context_created.cause, 0); + + if ((session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4 == 0) && + (session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6 == 0)) + { + + S1AP_ERROR("No IP address provided for transport layer address\n" + " -->Sending Intial context setup failure\n"); + return -1; + } + + if ((ue_ref = s1ap_is_teid_in_list(session_response_p->s11_sgw_teid.teid)) == NULL) { + S1AP_DEBUG("[%d] is not attached to any UE context\n", + session_response_p->s11_sgw_teid.teid); + return -1; + } + + memset(&message, 0, sizeof(s1ap_message)); + memset(&e_RABToBeSetup, 0, sizeof(E_RABToBeSetupItemCtxtSUReq_t)); + + message.procedureCode = ProcedureCode_id_InitialContextSetup; + message.direction = S1AP_PDU_PR_initiatingMessage; + + initialContextSetupRequest_p = &message.msg.initialContextSetupRequestIEs; + + initialContextSetupRequest_p->mme_ue_s1ap_id = ue_ref->mme_ue_s1ap_id; + initialContextSetupRequest_p->eNB_UE_S1AP_ID = ue_ref->eNB_ue_s1ap_id; + + /* uEaggregateMaximumBitrateDL and uEaggregateMaximumBitrateUL expressed in term of bits/sec */ +// asn_int642INTEGER( +// &initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL, +// 100000000UL); +// asn_int642INTEGER( +// &initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL, +// 50000000UL); + + initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = 100000000UL; + initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL = 50000000UL; + + e_RABToBeSetup.e_RAB_ID = + session_response_p->bearer_context_created.eps_bearer_id; /* ??? */ + e_RABToBeSetup.e_RABlevelQoSParameters.qCI = 0; // ?? + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel + = 15; //No priority + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability + = Pre_emptionCapability_shall_not_trigger_pre_emption; + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability + = Pre_emptionVulnerability_not_pre_emptable; + +// e_RABToBeSetup.gTP_TEID.buf = calloc(4, sizeof(uint8_t)); +// INT32_TO_BUFFER(session_response_p->bearer_context_created.s1u_sgw_fteid.teid, +// e_RABToBeSetup.gTP_TEID.buf); +// e_RABToBeSetup.gTP_TEID.size = 4; + DevCheck(session_response_p->bearer_context_created.s1u_sgw_fteid.teid != 0, + session_response_p->bearer_context_created.s1u_sgw_fteid.teid, 0, 0); + INT32_TO_OCTET_STRING( + session_response_p->bearer_context_created.s1u_sgw_fteid.teid, + &e_RABToBeSetup.gTP_TEID); + if ((session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4 == 1) && + (session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6 == 0)) { + /* Only IPv4 supported */ + INT32_TO_BIT_STRING( + session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4_address, + &e_RABToBeSetup.transportLayerAddress); + } else if ((session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4 == 0) && + (session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6 == 1)) { + /* Only IPv6 supported */ + e_RABToBeSetup.transportLayerAddress.buf = calloc(16, sizeof(uint8_t)); + memcpy(e_RABToBeSetup.transportLayerAddress.buf, + (void *)&session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6_address, + 16); + e_RABToBeSetup.transportLayerAddress.size = 16; + e_RABToBeSetup.transportLayerAddress.bits_unused = 0; + } else if ((session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4 == 1) && + (session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6 == 1)) { + /* Both IPv4 and IPv6 supported */ + e_RABToBeSetup.transportLayerAddress.buf = calloc(20, sizeof(uint8_t)); + e_RABToBeSetup.transportLayerAddress.size = 20; + e_RABToBeSetup.transportLayerAddress.bits_unused = 0; + memcpy(e_RABToBeSetup.transportLayerAddress.buf, + &session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4_address, 4); + memcpy(e_RABToBeSetup.transportLayerAddress.buf + 4, + session_response_p->bearer_context_created.s1u_sgw_fteid.ipv6_address, 16); + } + + ASN_SEQUENCE_ADD(&initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq, + &e_RABToBeSetup); + + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.buf = + (uint8_t *)supportedAlgorithms; + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.size = 2; + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.bits_unused + = 0; + + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.buf + = (uint8_t *)supportedAlgorithms; + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.size + = 2; + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.bits_unused + = 0; + + initialContextSetupRequest_p->securityKey.buf = (uint8_t *) + securityKey; /* 256 bits length */ + initialContextSetupRequest_p->securityKey.size = 32; + initialContextSetupRequest_p->securityKey.bits_unused = 0; + + if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) { + return -1; + } + + return s1ap_mme_itti_send_sctp_request(buffer_p, length, ue_ref->eNB->sctp_assoc_id, + ue_ref->sctp_stream_send); + +// return s1ap_mme_encode_initial_context_setup_request(&initialContextSetupRequest, +// ue_ref); +} diff --git a/openair-cn/S1AP/s1ap_mme_handlers.h b/openair-cn/S1AP/s1ap_mme_handlers.h new file mode 100644 index 0000000000..a6113a08c5 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_handlers.h @@ -0,0 +1,91 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "s1ap_ies_defs.h" +#include "intertask_interface.h" + +#ifndef S1AP_MME_HANDLERS_H_ +#define S1AP_MME_HANDLERS_H_ + +/** \brief Handle decoded incoming messages from SCTP + * \param assoc_id SCTP association ID + * \param stream Stream number + * \param message_p The message decoded by the ASN1C decoder + * @returns int + **/ +int s1ap_mme_handle_message(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message_p); + +int s1ap_mme_handle_ue_cap_indication(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message); + +/** \brief Handle an S1 Setup request message. + * Typically add the eNB in the list of served eNB if not present, simply reset + * UEs association otherwise. S1SetupResponse message is sent in case of success or + * S1SetupFailure if the MME cannot accept the configuration received. + * \param assoc_id SCTP association ID + * \param stream Stream number + * \param message_p The message decoded by the ASN1C decoder + * @returns int + **/ +int s1ap_mme_handle_s1_setup_request(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message_p); + +int s1ap_mme_handle_path_switch_request(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message_p); + +int s1ap_mme_handle_ue_context_release_request(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message_p); + +int s1ap_mme_handle_ue_context_release_complete(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message_p); + +int s1ap_mme_handle_initial_context_setup_failure(uint32_t assoc_id, + uint32_t stream, struct s1ap_message_s *message_p); + +int s1ap_mme_handle_initial_context_setup_response( + uint32_t assoc_id, + uint32_t stream, + struct s1ap_message_s *message_p); + +int s1ap_handle_sctp_deconnection(uint32_t assoc_id); + +int s1ap_handle_new_association(sctp_new_peer_t *sctp_new_peer_p); + +int s1ap_handle_create_session_response(SgwCreateSessionResponse + *session_response_p); + +int s1ap_mme_set_cause(Cause_t *cause_p, Cause_PR cause_type, long cause_value); + +int s1ap_mme_generate_s1_setup_failure( + uint32_t assoc_id, Cause_PR cause_type, long cause_value, + long time_to_wait); + +#endif /* S1AP_MME_HANDLERS_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_itti_messaging.c b/openair-cn/S1AP/s1ap_mme_itti_messaging.c new file mode 100644 index 0000000000..82a4d9b389 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_itti_messaging.c @@ -0,0 +1,54 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "s1ap_mme_itti_messaging.h" + +int s1ap_mme_itti_send_sctp_request(uint8_t *buffer, uint32_t length, + uint32_t assoc_id, uint16_t stream) +{ + MessageDef *message_p; + SctpNewDataReq *sctpNewDataReq_p; + + message_p = alloc_new_message(TASK_SCTP, SCTP_NEW_DATA_REQ); + + sctpNewDataReq_p = &message_p->msg.sctpNewDataReq; + + sctpNewDataReq_p->buffer = buffer; + sctpNewDataReq_p->bufLen = length; + sctpNewDataReq_p->assocId = assoc_id; + sctpNewDataReq_p->stream = stream; + + return send_msg_to_task(TASK_SCTP, INSTANCE_DEFAULT, message_p); +} + +int s1ap_mme_itti_forward_nas_uplink(uint8_t *buffer, uint32_t length) +{ + return 0; +} diff --git a/openair-cn/S1AP/s1ap_mme_itti_messaging.h b/openair-cn/S1AP/s1ap_mme_itti_messaging.h new file mode 100644 index 0000000000..e92a7fc405 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_itti_messaging.h @@ -0,0 +1,41 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "intertask_interface.h" + +#ifndef S1AP_MME_ITTI_MESSAGING_H_ +#define S1AP_MME_ITTI_MESSAGING_H_ + +int s1ap_mme_itti_send_sctp_request(uint8_t *buffer, uint32_t length, + uint32_t assoc_id, uint16_t stream); + +#endif /* S1AP_MME_ITTI_MESSAGING_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_nas_procedures.c b/openair-cn/S1AP/s1ap_mme_nas_procedures.c new file mode 100644 index 0000000000..1bf88a3b23 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_nas_procedures.c @@ -0,0 +1,386 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "s1ap_common.h" +#include "s1ap_ies_defs.h" +#include "s1ap_mme_encoder.h" +#include "s1ap_mme_handlers.h" +#include "s1ap_mme_nas_procedures.h" +#include "s1ap_mme_retransmission.h" + +#include "s1ap_mme_itti_messaging.h" + +#include "s1ap_mme.h" + +#include "intertask_interface.h" +#include "timer.h" + +#include "assertions.h" +#include "conversions.h" + +/* Every time a new UE is associated, increment this variable. + * But care if it wraps to increment also the mme_ue_s1ap_id_has_wrapped + * variable. Limit: UINT32_MAX (in stdint.h). + */ +static uint32_t mme_ue_s1ap_id = 0; +static uint8_t mme_ue_s1ap_id_has_wrapped = 0; + +int s1ap_mme_handle_initial_ue_message(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + InitialUEMessageIEs_t *initialUEMessage_p; + ue_description_t *ue_ref; + eNB_description_t *eNB_ref; + uint32_t eNB_ue_s1ap_id; + + initialUEMessage_p = &message->msg.initialUEMessageIEs; + + if ((eNB_ref = s1ap_is_eNB_assoc_id_in_list(assoc_id)) == NULL) { + S1AP_DEBUG("Unkwnon eNB on assoc_id %d\n", assoc_id); + return -1; + } + + // eNB UE S1AP ID is limited to 24 bits + eNB_ue_s1ap_id = (uint32_t)(initialUEMessage_p->eNB_UE_S1AP_ID & 0x00ffffff); + + S1AP_DEBUG("New Initial UE message received with eNB UE S1AP ID: 0x%06x\n", + eNB_ue_s1ap_id); + + if ((ue_ref = s1ap_is_ue_eNB_id_in_list(eNB_ref, eNB_ue_s1ap_id)) == NULL) { + /* This UE eNB Id has currently no known s1 association. + * Create new UE context by associating new mme_ue_s1ap_id. + * Update eNB UE list. + * Forward message to NAS. + */ + if ((ue_ref = s1ap_new_ue(assoc_id)) == NULL) + // If we failed to allocate a new UE return -1 + { + return -1; + } + + ue_ref->s1_ue_state = S1AP_UE_WAITING_CSR; + ue_ref->eNB_ue_s1ap_id = eNB_ue_s1ap_id; + ue_ref->mme_ue_s1ap_id = (uint32_t)ue_ref; + // On which stream we received the message + ue_ref->sctp_stream_recv = stream; + ue_ref->sctp_stream_send = ue_ref->eNB->next_sctp_stream; + + /* Increment the sctp stream for the eNB association. + * If the next sctp stream is >= outstream negociated between eNB and MME, + * wrap to first stream. + * TODO: search for the first available stream instead. + */ + if (ue_ref->eNB->next_sctp_stream++ >= ue_ref->eNB->outstreams) { + ue_ref->eNB->next_sctp_stream = 1; + } + + /* Increment the unique UE mme s1ap id and + * take care about overflow case. + */ + if (mme_ue_s1ap_id_has_wrapped == 0) { + mme_ue_s1ap_id++; + if (mme_ue_s1ap_id == 0) { + mme_ue_s1ap_id_has_wrapped = 1; + } + } else { + /* TODO: should take the first available mme_ue_s1ap_id instead of + * the mme_ue_s1ap_id variable. + */ + assert(0); + } + s1ap_dump_eNB(ue_ref->eNB); + { + /* We received the first NAS transport message: initial UE message. + * The containt of the NAS pdu should be forwarded to NAS for processing + */ + MessageDef *message_p; + nas_establish_ind_t *con_ind_p; + + s1ap_initial_ue_message_t *s1ap_p; + + message_p = alloc_new_message(TASK_S1AP, NAS_CONNECTION_ESTABLISHMENT_IND); + /* We failed to allocate a new message... */ + if (message_p == NULL) { + return -1; + } + con_ind_p = &message_p->msg.nas_conn_est_ind.nas; + + s1ap_p = &message_p->msg.nas_conn_est_ind.transparent; + + s1ap_p->eNB_ue_s1ap_id = eNB_ue_s1ap_id; + s1ap_p->mme_ue_s1ap_id = ue_ref->mme_ue_s1ap_id; + +#if !defined(DISABLE_USE_NAS) + con_ind_p->UEid = ue_ref->mme_ue_s1ap_id; +#endif + + BIT_STRING_TO_CELL_IDENTITY(&initialUEMessage_p->eutran_cgi.cell_ID, + s1ap_p->e_utran_cgi.cell_identity); + TBCD_TO_PLMN_T(&initialUEMessage_p->eutran_cgi.pLMNidentity, + &s1ap_p->e_utran_cgi.plmn); + +#if !defined(DISABLE_USE_NAS) + /* Copy the TAI */ +// TBCD_TO_PLMN_T(&initialUEMessage_p->tai.pLMNidentity, &con_ind_p->tai.plmn); + OCTET_STRING_TO_INT16(&initialUEMessage_p->tai.tAC, con_ind_p->tac); +#else + /* TODO: copy the TAC */ +// TBCD_TO_PLMN_T(&initialUEMessage_p->tai.pLMNidentity, &con_ind_p->tai.plmn); + OCTET_STRING_TO_INT16(&initialUEMessage_p->tai.tAC, con_ind_p->tac); +#endif + /* Copy the NAS payload */ + con_ind_p->initialNasMsg.length = initialUEMessage_p->nas_pdu.size; + con_ind_p->initialNasMsg.data = malloc(sizeof(con_ind_p->initialNasMsg.data) * + initialUEMessage_p->nas_pdu.size); + memcpy(con_ind_p->initialNasMsg.data, initialUEMessage_p->nas_pdu.buf, + initialUEMessage_p->nas_pdu.size); + + return send_msg_to_task(TASK_NAS, INSTANCE_DEFAULT, message_p); + } + } + return 0; +} + +int s1ap_mme_handle_uplink_nas_transport(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + UplinkNASTransportIEs_t *uplinkNASTransport_p; + ue_description_t *ue_ref; + + uplinkNASTransport_p = &message->msg.uplinkNASTransportIEs; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list(uplinkNASTransport_p->mme_ue_s1ap_id)) + == NULL) { + S1AP_DEBUG("No UE is attached to this mme UE s1ap id: %d\n", + (int)uplinkNASTransport_p->mme_ue_s1ap_id); + return -1; + } + if (ue_ref->s1_ue_state != S1AP_UE_CONNECTED) { + S1AP_DEBUG("Received uplink NAS transport while UE in state != S1AP_UE_CONNECTED\n"); + return -1; + } + + //TODO: forward NAS PDU to NAS + DevMessage("TODO: forward NAS PDU to NAS\n"); + return 0; +} + +int s1ap_mme_handle_nas_non_delivery(uint32_t assoc_id, uint32_t stream, + struct s1ap_message_s *message) +{ + /* UE associated signalling on stream == 0 is not valid. */ + if (stream == 0) { + S1AP_DEBUG("Received new nas non delivery on stream == 0\n"); + return -1; + } + //TODO: forward NAS PDU to NAS + DevMessage("TODO: forward NAS PDU to NAS\n"); + return 0; +} + +int s1ap_generate_downlink_nas_transport(nas_dl_data_ind_t *nas_dl_data_ind) +{ + ue_description_t *ue_ref; + uint8_t *buffer_p; + uint32_t length; + + DevAssert(nas_dl_data_ind != NULL); + + if ((ue_ref = s1ap_is_ue_mme_id_in_list(nas_dl_data_ind->UEid)) == NULL) { + /* If the UE-associated logical S1-connection is not established, + * the MME shall allocate a unique MME UE S1AP ID to be used for the UE. + */ + DevMessage("This case is not handled right now\n"); + } else { + /* We have fount the UE in the list. + * Create new IE list message and encode it. + */ + DownlinkNASTransportIEs_t *downlinkNasTransport; + s1ap_message message; + + memset(&message, 0, sizeof(s1ap_message)); + + message.procedureCode = ProcedureCode_id_downlinkNASTransport; + message.direction = S1AP_PDU_PR_initiatingMessage; + + downlinkNasTransport = &message.msg.downlinkNASTransportIEs; + + /* Setting UE informations with the ones fount in ue_ref */ + downlinkNasTransport->mme_ue_s1ap_id = ue_ref->mme_ue_s1ap_id; + downlinkNasTransport->eNB_UE_S1AP_ID = ue_ref->eNB_ue_s1ap_id; + OCTET_STRING_fromBuf(&downlinkNasTransport->nas_pdu, + (char*)nas_dl_data_ind->nasMsg.data, + nas_dl_data_ind->nasMsg.length); + if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) { + // TODO: handle something + return -1; + } + + return s1ap_mme_itti_send_sctp_request(buffer_p, length, + ue_ref->eNB->sctp_assoc_id, + ue_ref->sctp_stream_send); + } + return 0; +} + +int s1ap_handle_attach_accepted(nas_attach_accept_t *attach_accept_p) +{ + /* We received create session response from S-GW on S11 interface abstraction. + * At least one bearer has been established. We can now send s1ap initial context setup request + * message to eNB. + */ + char supportedAlgorithms[] = { 0x02, 0xa0 }; + uint8_t offset = 0; + uint8_t *buffer_p; + uint32_t length; + + ue_description_t *ue_ref = NULL; + InitialContextSetupRequestIEs_t *initialContextSetupRequest_p; + s1ap_message message; + E_RABToBeSetupItemCtxtSUReq_t e_RABToBeSetup; + s1ap_initial_ctxt_setup_req_t *initial_p; + + DevAssert(attach_accept_p != NULL); + + initial_p = &attach_accept_p->transparent; + + if ((ue_ref = s1ap_is_ue_mme_id_in_list(initial_p->mme_ue_s1ap_id)) == NULL) { + S1AP_DEBUG("This mme ue s1ap id (%08x) is not attached to any UE context\n", + initial_p->mme_ue_s1ap_id); + return -1; + } + + /* Start the outcome response timer. + * When time is reached, MME consider that procedure outcome has failed. + */ + timer_setup(mme_config.s1ap_config.outcome_drop_timer_sec, 0, TASK_S1AP, INSTANCE_DEFAULT, + TIMER_ONE_SHOT, + NULL, + &ue_ref->outcome_response_timer_id); + /* Insert the timer in the MAP of mme_ue_s1ap_id <-> timer_id */ + s1ap_timer_insert(ue_ref->mme_ue_s1ap_id, ue_ref->outcome_response_timer_id); + + memset(&message, 0, sizeof(s1ap_message)); + memset(&e_RABToBeSetup, 0, sizeof(E_RABToBeSetupItemCtxtSUReq_t)); + + message.procedureCode = ProcedureCode_id_InitialContextSetup; + message.direction = S1AP_PDU_PR_initiatingMessage; + + initialContextSetupRequest_p = &message.msg.initialContextSetupRequestIEs; + + initialContextSetupRequest_p->mme_ue_s1ap_id = (unsigned long)ue_ref->mme_ue_s1ap_id; + initialContextSetupRequest_p->eNB_UE_S1AP_ID = (unsigned long)ue_ref->eNB_ue_s1ap_id; + + /* uEaggregateMaximumBitrateDL and uEaggregateMaximumBitrateUL expressed in term of bits/sec */ +// asn_int642INTEGER( +// &initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL, +// initial_p->ambr.br_dl); +// asn_int642INTEGER( +// &initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL, +// initial_p->ambr.br_ul); + + initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL = initial_p->ambr.br_dl; + initialContextSetupRequest_p->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL = initial_p->ambr.br_ul; + + e_RABToBeSetup.e_RAB_ID = initial_p->ebi; + e_RABToBeSetup.e_RABlevelQoSParameters.qCI = initial_p->qci; + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel + = initial_p->prio_level; //No priority + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability + = initial_p->pre_emp_capability; + e_RABToBeSetup.e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability + = initial_p->pre_emp_vulnerability; + + /* Set the GTP-TEID. This is the S1-U S-GW TEID */ + INT32_TO_OCTET_STRING(initial_p->teid, &e_RABToBeSetup.gTP_TEID); + + /* S-GW IP address(es) for user-plane */ + if ((initial_p->s_gw_address.pdn_type == IPv4) || + (initial_p->s_gw_address.pdn_type == IPv4_AND_v6)) + { + e_RABToBeSetup.transportLayerAddress.buf = calloc(4, sizeof(uint8_t)); + /* Only IPv4 supported */ + memcpy(e_RABToBeSetup.transportLayerAddress.buf, + initial_p->s_gw_address.address.ipv4_address, + 4); + offset += 4; + e_RABToBeSetup.transportLayerAddress.size = 4; + e_RABToBeSetup.transportLayerAddress.bits_unused = 0; + } + if ((initial_p->s_gw_address.pdn_type == IPv6) || + (initial_p->s_gw_address.pdn_type == IPv4_AND_v6)) + { + if (offset == 0) { + /* Both IPv4 and IPv6 provided */ + /* TODO: check memory allocation */ + e_RABToBeSetup.transportLayerAddress.buf = calloc(16, sizeof(uint8_t)); + } else { + /* Only IPv6 supported */ + /* TODO: check memory allocation */ + e_RABToBeSetup.transportLayerAddress.buf + = realloc(e_RABToBeSetup.transportLayerAddress.buf, (16 + offset) * sizeof(uint8_t)); + } + memcpy(&e_RABToBeSetup.transportLayerAddress.buf[offset], + initial_p->s_gw_address.address.ipv6_address, + 16); + e_RABToBeSetup.transportLayerAddress.size = 16 + offset; + e_RABToBeSetup.transportLayerAddress.bits_unused = 0; + } + + ASN_SEQUENCE_ADD(&initialContextSetupRequest_p->e_RABToBeSetupListCtxtSUReq, + &e_RABToBeSetup); + + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.buf = + (uint8_t *)supportedAlgorithms; + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.size = 2; + initialContextSetupRequest_p->ueSecurityCapabilities.encryptionAlgorithms.bits_unused + = 0; + + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.buf + = (uint8_t *)supportedAlgorithms; + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.size + = 2; + initialContextSetupRequest_p->ueSecurityCapabilities.integrityProtectionAlgorithms.bits_unused + = 0; + + initialContextSetupRequest_p->securityKey.buf = initial_p->keNB; /* 256 bits length */ + initialContextSetupRequest_p->securityKey.size = 32; + initialContextSetupRequest_p->securityKey.bits_unused = 0; + + if (s1ap_mme_encode_pdu(&message, &buffer_p, &length) < 0) { + // TODO: handle something + return -1; + } + + return s1ap_mme_itti_send_sctp_request(buffer_p, length, ue_ref->eNB->sctp_assoc_id, + ue_ref->sctp_stream_send); +} diff --git a/openair-cn/S1AP/s1ap_mme_nas_procedures.h b/openair-cn/S1AP/s1ap_mme_nas_procedures.h new file mode 100644 index 0000000000..5c4d217e10 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_nas_procedures.h @@ -0,0 +1,71 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "s1ap_ies_defs.h" +#include "intertask_interface.h" + +#ifndef S1AP_MME_NAS_PROCEDURES_H_ +#define S1AP_MME_NAS_PROCEDURES_H_ + +/** \brief Handle an Initial UE message. + * \param assocId lower layer assoc id (SCTP) + * \param stream SCTP stream on which data had been received + * \param message The message as decoded by the ASN.1 codec + * @returns -1 on failure, 0 otherwise + **/ +int s1ap_mme_handle_initial_ue_message(uint32_t assocId, uint32_t stream, + struct s1ap_message_s *message); + +/** \brief Handle an Uplink NAS transport message. + * Process the RRC transparent container and forward it to NAS entity. + * \param assocId lower layer assoc id (SCTP) + * \param stream SCTP stream on which data had been received + * \param message The message as decoded by the ASN.1 codec + * @returns -1 on failure, 0 otherwise + **/ +int s1ap_mme_handle_uplink_nas_transport(uint32_t assocId, uint32_t stream, + struct s1ap_message_s *message); + +/** \brief Handle a NAS non delivery indication message from eNB + * \param assocId lower layer assoc id (SCTP) + * \param stream SCTP stream on which data had been received + * \param message The message as decoded by the ASN.1 codec + * @returns -1 on failure, 0 otherwise + **/ +int s1ap_mme_handle_nas_non_delivery(uint32_t assocId, uint32_t stream, + struct s1ap_message_s *message); + +int s1ap_handle_attach_accepted(nas_attach_accept_t *attach_accept_p); + +int s1ap_generate_downlink_nas_transport(nas_dl_data_ind_t *message); + +#endif /* S1AP_MME_NAS_PROCEDURES_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_retransmission.c b/openair-cn/S1AP/s1ap_mme_retransmission.c new file mode 100644 index 0000000000..ddf1784c1c --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_retransmission.c @@ -0,0 +1,146 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> + +#include "tree.h" +#include "assertions.h" + +#include "intertask_interface.h" + +#include "timer.h" +#include "s1ap_common.h" +#include "s1ap_mme_retransmission.h" + +inline int s1ap_mme_timer_map_compare_id( + struct s1ap_timer_map_s *p1, struct s1ap_timer_map_s *p2); + +/* Reference to tree root element */ +RB_HEAD(s1ap_timer_map, s1ap_timer_map_s) s1ap_timer_tree = RB_INITIALIZER(); + +/* RB tree functions for s1ap timer map are not exposed to the rest of the code + * only declare prototypes here. + */ +RB_PROTOTYPE(s1ap_timer_map, s1ap_timer_map_s, entries, + s1ap_mme_timer_map_compare_id); + +RB_GENERATE(s1ap_timer_map, s1ap_timer_map_s, entries, + s1ap_mme_timer_map_compare_id); + +inline int s1ap_mme_timer_map_compare_id( + struct s1ap_timer_map_s *p1, struct s1ap_timer_map_s *p2) +{ + if (p1->mme_ue_s1ap_id > 0) { + if (p1->mme_ue_s1ap_id > p2->mme_ue_s1ap_id) { + return 1; + } + if (p1->mme_ue_s1ap_id < p2->mme_ue_s1ap_id) { + return -1; + } + return 0; + } + if (p1->timer_id > p2->timer_id) { + return 1; + } + if (p1->timer_id < p2->timer_id) { + return -1; + } + /* Match -> return 0 */ + return 0; +} + +int s1ap_timer_insert(uint32_t mme_ue_s1ap_id, long timer_id) +{ + struct s1ap_timer_map_s *new; + + new = malloc(sizeof(struct s1ap_timer_map_s)); + + new->timer_id = timer_id; + new->mme_ue_s1ap_id = mme_ue_s1ap_id; + + if (RB_INSERT(s1ap_timer_map, &s1ap_timer_tree, new) != NULL) { + S1AP_ERROR("Timer with id 0x%lx already exists\n", timer_id); + free(new); + return -1; + } + + return 0; +} + +int s1ap_handle_timer_expiry(timer_has_expired_t *timer_has_expired) +{ + struct s1ap_timer_map_s *find; + struct s1ap_timer_map_s elm; + + DevAssert(timer_has_expired != NULL); + + memset(&elm, 0, sizeof(elm)); + + elm.timer_id = timer_has_expired->timer_id; + + if ((find = RB_FIND(s1ap_timer_map, &s1ap_timer_tree, &elm)) == NULL) { + S1AP_WARN("Timer id 0x%lx has not been found in tree. Maybe the timer " + "reference has been removed before receiving tiemr signal\n", + timer_has_expired->timer_id); + return 0; + } + + /* Remove the timer from the map */ + RB_REMOVE(s1ap_timer_map, &s1ap_timer_tree, find); + + /* Destroy the element */ + free(find); + + /* TODO: notify NAS and remove ue context */ + return 0; +} + +int s1ap_timer_remove_ue(uint32_t mme_ue_s1ap_id) +{ + struct s1ap_timer_map_s *find; + + S1AP_DEBUG("Removing timer associated with UE 0x%08x\n", + mme_ue_s1ap_id); + + DevAssert(mme_ue_s1ap_id != 0); + + RB_FOREACH(find, s1ap_timer_map, &s1ap_timer_tree) { + if (find->mme_ue_s1ap_id == mme_ue_s1ap_id) { + timer_remove(find->timer_id); + /* Remove the timer from the map */ + RB_REMOVE(s1ap_timer_map, &s1ap_timer_tree, find); + /* Destroy the element */ + free(find); + } + } + return 0; +} diff --git a/openair-cn/S1AP/s1ap_mme_retransmission.h b/openair-cn/S1AP/s1ap_mme_retransmission.h new file mode 100644 index 0000000000..3fd4646c97 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_retransmission.h @@ -0,0 +1,52 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "tree.h" + +#ifndef S1AP_MME_RETRANSMISSION_H_ +#define S1AP_MME_RETRANSMISSION_H_ + +typedef struct s1ap_timer_map_s { + long timer_id; + uint32_t mme_ue_s1ap_id; + + RB_ENTRY(s1ap_timer_map_s) entries; +} s1ap_timer_map_t; + +inline int s1ap_mme_timer_map_compare_id( + struct s1ap_timer_map_s *p1, struct s1ap_timer_map_s *p2); + +int s1ap_handle_timer_expiry(timer_has_expired_t *timer_has_expired); + +int s1ap_timer_insert(uint32_t mme_ue_s1ap_id, long timer_id); + +int s1ap_timer_remove_ue(uint32_t mme_ue_s1ap_id); + +#endif /* S1AP_MME_RETRANSMISSION_H_ */ diff --git a/openair-cn/S1AP/s1ap_mme_ta.c b/openair-cn/S1AP/s1ap_mme_ta.c new file mode 100644 index 0000000000..97191978f8 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_ta.c @@ -0,0 +1,150 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "assertions.h" +#include "conversions.h" + +#include "mme_config.h" + +#include "s1ap_mme.h" +#include "s1ap_common.h" +#include "s1ap_mme_ta.h" + +static +int s1ap_mme_compare_plmn(PLMNidentity_t *plmn) +{ + int i; + uint16_t mcc; + uint16_t mnc; + + DevAssert(plmn != NULL); + + TBCD_TO_MCC_MNC(plmn, mcc, mnc); + + config_read_lock(&mme_config); + + for (i = 0; i < mme_config.gummei.nb_mme_gid; i++) { + if (mme_config.gummei.plmn_mcc[i] == mcc && + mme_config.gummei.plmn_mnc[i] == mnc) + /* There is a matching plmn */ + return TA_LIST_AT_LEAST_ONE_MATCH; + } + + config_unlock(&mme_config); + + return TA_LIST_NO_MATCH; +} + +/* @brief compare a list of broadcasted plmns against the MME configured. + */ +static +int s1ap_mme_compare_plmns(BPLMNs_t *b_plmns) +{ + int i; + int matching_occurence = 0; + + DevAssert(b_plmns != NULL); + + for (i = 0; i < b_plmns->list.count; i++) { + if (s1ap_mme_compare_plmn(b_plmns->list.array[i]) + == TA_LIST_AT_LEAST_ONE_MATCH) + matching_occurence++; + } + + if (matching_occurence == 0) + return TA_LIST_NO_MATCH; + else if (matching_occurence == b_plmns->list.count - 1) + return TA_LIST_COMPLETE_MATCH; + else + return TA_LIST_AT_LEAST_ONE_MATCH; +} + +/* @brief compare a TAC + */ +static +int s1ap_mme_compare_tac(TAC_t *tac) +{ + int i; + uint16_t tac_value; + + DevAssert(tac != NULL); + + OCTET_STRING_TO_TAC(tac, tac_value); + + config_read_lock(&mme_config); + + for (i = 0; i < mme_config.gummei.nb_mme_gid; i++) { + if (mme_config.gummei.plmn_tac[i] == tac_value) + return TA_LIST_AT_LEAST_ONE_MATCH; + } + + config_unlock(&mme_config); + + return TA_LIST_NO_MATCH; +} + +/* @brief compare a given ta list against the one provided by mme configuration. + * @param ta_list + * @return - TA_LIST_UNKNOWN_PLMN if at least one TAC match and no PLMN match + * - TA_LIST_UNKNOWN_TAC if at least one PLMN match and no TAC match + * - TA_LIST_RET_OK if both tac and plmn match at least one element + */ +int s1ap_mme_compare_ta_lists(SupportedTAs_t *ta_list) +{ + int i; + int tac_ret, bplmn_ret; + + DevAssert(ta_list != NULL); + + /* Parse every item in the list and try to find matching parameters */ + for (i = 0; i < ta_list->list.count; i++) { + SupportedTAs_Item_t *ta; + + ta = ta_list->list.array[i]; + DevAssert(ta != NULL); + + tac_ret = s1ap_mme_compare_tac(&ta->tAC); + bplmn_ret = s1ap_mme_compare_plmns(&ta->broadcastPLMNs); + if (tac_ret == TA_LIST_NO_MATCH && bplmn_ret == TA_LIST_NO_MATCH) { + return TA_LIST_UNKNOWN_PLMN + TA_LIST_UNKNOWN_TAC; + } else { + if (tac_ret > TA_LIST_NO_MATCH && bplmn_ret == TA_LIST_NO_MATCH) { + return TA_LIST_UNKNOWN_PLMN; + } else if (tac_ret == TA_LIST_NO_MATCH && bplmn_ret > TA_LIST_NO_MATCH) { + return TA_LIST_UNKNOWN_TAC; + } + } + } + return TA_LIST_RET_OK; +} diff --git a/openair-cn/S1AP/s1ap_mme_ta.h b/openair-cn/S1AP/s1ap_mme_ta.h new file mode 100644 index 0000000000..6b5cbd7896 --- /dev/null +++ b/openair-cn/S1AP/s1ap_mme_ta.h @@ -0,0 +1,45 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S1AP_MME_TA_H_ +#define S1AP_MME_TA_H_ + +enum { + TA_LIST_UNKNOWN_TAC = -2, + TA_LIST_UNKNOWN_PLMN = -1, + TA_LIST_RET_OK = 0, + TA_LIST_NO_MATCH = 0x1, + TA_LIST_AT_LEAST_ONE_MATCH = 0x2, + TA_LIST_COMPLETE_MATCH = 0x3, +}; + +int s1ap_mme_compare_ta_lists(SupportedTAs_t *ta_list); + +#endif /* S1AP_MME_TA_H_ */ diff --git a/openair-cn/S6A/Makefile.am b/openair-cn/S6A/Makefile.am new file mode 100644 index 0000000000..bf4d2923c1 --- /dev/null +++ b/openair-cn/S6A/Makefile.am @@ -0,0 +1,18 @@ +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/UTILS + +noinst_LTLIBRARIES = libs6a.la +libs6a_la_LDFLAGS = -all-static + +libs6a_la_SOURCES = \ + s6a_defs.h s6a_messages.h \ + s6a_auth_info.c \ + s6a_dict.c \ + s6a_error.c \ + s6a_peer.c \ + s6a_subscription_data.c \ + s6a_task.c \ + s6a_up_loc.c diff --git a/openair-cn/S6A/freediameter/README.txt b/openair-cn/S6A/freediameter/README.txt new file mode 100644 index 0000000000..a1c80e1cab --- /dev/null +++ b/openair-cn/S6A/freediameter/README.txt @@ -0,0 +1,15 @@ +Pre-requisities: +Cmake libgnutls-3.1.0 + +The best way to install freeDiameter is to use to script provided in this folder. + +download tarball here: http://www.freediameter.net/hg/freeDiameter/archive/1.1.5.tar.gz +extract it somewhere. +cd freeDiameter-1.1.5 +patch -p1 < freediameter-1.1.5.patch +mkdir build && cd build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ +sudo make install + +if you choose to install libraries in default path (/usr/local/lib), you will have + to tell configure to use LDFLAGS='-L/usr/local/lib' \ No newline at end of file diff --git a/openair-cn/S6A/freediameter/freediameter-1.1.5.patch b/openair-cn/S6A/freediameter/freediameter-1.1.5.patch new file mode 100644 index 0000000000..3b03890675 --- /dev/null +++ b/openair-cn/S6A/freediameter/freediameter-1.1.5.patch @@ -0,0 +1,4296 @@ +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/extensions/CMakeLists.txt freeDiameter-1.1.5/extensions/CMakeLists.txt +--- freeDiameter-1.1.5-unmodified/extensions/CMakeLists.txt 2012-11-03 18:45:41.000000000 +0100 ++++ freeDiameter-1.1.5/extensions/CMakeLists.txt 2013-02-14 14:40:40.605217128 +0100 +@@ -35,7 +35,7 @@ + + #### + # Diameter applications dictionaries +- ++FD_EXTENSION_SUBDIR(dict_s6a "3GPP S6A TS.29.279-990" ON) + FD_EXTENSION_SUBDIR(dict_nasreq "NASREQ (RFC4005) Dictionary definitions" ON) + FD_EXTENSION_SUBDIR(dict_eap "Diameter EAP (RFC4072) Dictionary definitions" ON) + +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/extensions/dict_s6a/CMakeLists.txt freeDiameter-1.1.5/extensions/dict_s6a/CMakeLists.txt +--- freeDiameter-1.1.5-unmodified/extensions/dict_s6a/CMakeLists.txt 1970-01-01 01:00:00.000000000 +0100 ++++ freeDiameter-1.1.5/extensions/dict_s6a/CMakeLists.txt 2012-11-22 17:14:40.177272498 +0100 +@@ -0,0 +1,13 @@ ++# The dict_rfc5777 extension ++PROJECT("S6a protocol based on 3GPP 29.272-990" C) ++ ++# Compile as a module ++FD_ADD_EXTENSION(dict_s6a dict_s6a.c) ++ ++ ++#### ++## INSTALL section ## ++ ++INSTALL(TARGETS dict_s6a ++ LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX} ++ COMPONENT freeDiameter-dictionary-s6a) +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/extensions/dict_s6a/dict_s6a.c freeDiameter-1.1.5/extensions/dict_s6a/dict_s6a.c +--- freeDiameter-1.1.5-unmodified/extensions/dict_s6a/dict_s6a.c 1970-01-01 01:00:00.000000000 +0100 ++++ freeDiameter-1.1.5/extensions/dict_s6a/dict_s6a.c 2013-02-13 09:08:27.026025453 +0100 +@@ -0,0 +1,4212 @@ ++/********************************************************************************************************* ++* Software License Agreement (BSD License) * ++* Author: Sebastien ROUX <sebastien.roux@eurecom.fr> * ++* * ++* Copyright (c) 2013, Eurecom * ++* All rights reserved. * ++* * ++* Redistribution and use of this software in source and binary forms, with or without modification, are * ++* permitted provided that the following conditions are met: * ++* * ++* * Redistributions of source code must retain the above * ++* copyright notice, this list of conditions and the * ++* following disclaimer. * ++* * ++* * Redistributions in binary form must reproduce the above * ++* copyright notice, this list of conditions and the * ++* following disclaimer in the documentation and/or other * ++* materials provided with the distribution. * ++* * ++* * Neither the name of the Teraoka Laboratory nor the * ++* names of its contributors may be used to endorse or * ++* promote products derived from this software without * ++* specific prior written permission of Teraoka Laboratory * ++* * ++* * ++* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * ++* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * ++* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ++* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * ++* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * ++* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * ++* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ++* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ++*********************************************************************************************************/ ++ ++#include <freeDiameter/extension.h> ++ ++/* The content of this file follows the same structure as dict_base_proto.c */ ++ ++#define CHECK_dict_new( _type, _data, _parent, _ref ) \ ++ CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) ); ++ ++#define CHECK_dict_search( _type, _criteria, _what, _result ) \ ++ CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); ++ ++struct local_rules_definition { ++ char *avp_name; ++ enum rule_position position; ++ int min; ++ int max; ++}; ++ ++#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 ) ++ ++#define PARSE_loc_rules( _rulearray, _parent) { \ ++ int __ar; \ ++ for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \ ++ struct dict_rule_data __data = { NULL, \ ++ (_rulearray)[__ar].position, \ ++ 0, \ ++ (_rulearray)[__ar].min, \ ++ (_rulearray)[__ar].max}; \ ++ __data.rule_order = RULE_ORDER(__data.rule_position); \ ++ CHECK_FCT( fd_dict_search( \ ++ fd_g_config->cnf_dict, \ ++ DICT_AVP, \ ++ AVP_BY_NAME_ALL_VENDORS, \ ++ (_rulearray)[__ar].avp_name, \ ++ &__data.rule_avp, 0 ) ); \ ++ if ( !__data.rule_avp ) { \ ++ TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name ); \ ++ return ENOENT; \ ++ } \ ++ CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \ ++ { \ ++ TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \ ++ (_rulearray)[__ar].avp_name ); \ ++ return EINVAL; \ ++ } ); \ ++ } \ ++} ++ ++#define enumval_def_u32( _val_, _str_ ) \ ++ { _str_, { .u32 = _val_ }} ++ ++#define enumval_def_os( _len_, _val_, _str_ ) \ ++ { _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}} ++ ++/* Defines if there are any */ ++ ++/* Dictionary */ ++ ++int dict_s6a_init(char * conffile) ++{ ++#define VENDOR_3GPP_Id 10415 ++ ++ TRACE_ENTRY("%p", conffile); ++ ++ struct dict_object * vendor_dict; ++ { ++ struct dict_vendor_data vendor_data = { VENDOR_3GPP_Id, "3GPP" }; ++ CHECK_dict_new (DICT_VENDOR, &vendor_data, NULL, &vendor_dict); ++ } ++ ++ struct dict_object * s6a_dict; ++ { ++ struct dict_application_data data = { 16777251, "Diameter S6a 3GPP" }; ++ CHECK_dict_new( DICT_APPLICATION, &data , NULL, &s6a_dict); ++ } ++ ++ /* AVP section */ ++ { ++ /* Loading the derived data formats */ ++ ++ struct dict_object * Time_type; ++ struct dict_object * Address_type; ++ struct dict_object * UTF8String_type; ++ ++ CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Time", &Time_type); ++ CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Address", &Address_type); ++ CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "UTF8String", &UTF8String_type); ++ ++ /* 3GPP-Charging-Characteristics */ ++ { ++ struct dict_avp_data data = { ++ 13, /* Code */ ++ 0, /* Vendor */ ++ "3GPP-Charging-Characteristics", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); ++ } ++ ++ /* Service-Selection - RFC 5778 */ ++ { ++ struct dict_avp_data data = { ++ 493, /* Code */ ++ 0, /* Vendor */ ++ "Service-Selection", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); ++ } ++ ++ /* Max-Requested-Bandwidth-DL AVP - 3GPP TS 29.214 #5.3.14 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 515, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Max-Requested-Bandwidth-DL", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Max-Requested-Bandwidth-UL AVP - 3GPP TS 29.214 #5.3.15 */ ++ { ++ struct dict_avp_data data = { ++ 516, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Max-Requested-Bandwidth-UL", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Visited-Network-Identifier AVP - 3GPP TS 29.229 #6.3.1 */ ++ { ++ struct dict_avp_data data = { ++ 600, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Visited-Network-Identifier", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Confidentiality-Key AVP - 3GPP TS 29.229 #6.3.27 */ ++ { ++ struct dict_avp_data data = { ++ 625, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Confidentiality-Key", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Integrity-Key AVP - 3GPP TS 29.229 #6.3.28 */ ++ { ++ struct dict_avp_data data = { ++ 626, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Integrity-Key", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Feature-List-ID AVP - 3GPP TS 29.229 #6.3.29 */ ++ { ++ struct dict_avp_data data = { ++ 629, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Feature-List-ID", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Feature-List AVP - 3GPP TS 29.229 #6.3.30 */ ++ { ++ struct dict_avp_data data = { ++ 630, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Feature-List", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* MSISDN AVP - 3GPP TS 29.329 #6.3.2 */ ++ { ++ struct dict_avp_data data = { ++ 701, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MSISDN", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Served-Party-IP-Address AVP - 3GPP TS 32.299 #7.2.187 ++ * The Served-Party-IP-Address AVP (AVP code 848) is of type Address ++ * and holds the IP address of either the calling or called party, ++ * depending on whether the P-CSCF is in touch with the calling or the ++ * called party. This AVP is only provided by the P-CSCF. ++ */ ++ { ++ struct dict_avp_data data = { ++ 848, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Served-Party-IP-Address", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , Address_type, NULL); ++ } ++ ++ /* QoS-Class-Identifier AVP - 3GPP TS 29.212 #5.3.17 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(QoS-Class-Identifier)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_1 = { "QCI_1", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "QCI_2", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "QCI_3", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "QCI_4", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "QCI_5", { .i32 = 5 }}; ++ struct dict_enumval_data t_6 = { "QCI_6", { .i32 = 6 }}; ++ struct dict_enumval_data t_7 = { "QCI_7", { .i32 = 7 }}; ++ struct dict_enumval_data t_8 = { "QCI_8", { .i32 = 8 }}; ++ struct dict_enumval_data t_9 = { "QCI_9", { .i32 = 9 }}; ++ ++ struct dict_avp_data data = { ++ 1028, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "QoS-Class-Identifier", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata, NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_6, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_7, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_8, avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_9, avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* RAT-Type AVP - 3GPP TS 29.212 #5.3.31 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(RAT-Type)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "WLAN", { .u32 = 0 }}; ++ struct dict_enumval_data t_1 = { "VIRTUAL", { .u32 = 1 }}; ++ struct dict_enumval_data t_1000 = { "UTRAN", { .u32 = 1000 }}; ++ struct dict_enumval_data t_1001 = { "GERAN", { .u32 = 1001 }}; ++ struct dict_enumval_data t_1002 = { "GAN", { .u32 = 1002 }}; ++ struct dict_enumval_data t_1003 = { "HSPA_EVOLUTION", { .u32 = 1003 }}; ++ struct dict_enumval_data t_1004 = { "EUTRAN", { .u32 = 1004 }}; ++ struct dict_enumval_data t_2000 = { "CDMA2000_1X", { .u32 = 2000 }}; ++ struct dict_enumval_data t_2001 = { "HRPD", { .u32 = 2001 }}; ++ struct dict_enumval_data t_2002 = { "UMB", { .u32 = 2002 }}; ++ struct dict_enumval_data t_2003 = { "EHRPD", { .u32 = 2003 }}; ++ ++ struct dict_avp_data data = { ++ 1032, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "RAT-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1000 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1001 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1002 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1003 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1004 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2000 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2001 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2002 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2003 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Priority-Level AVP - 3GPP TS 29.272 #5.3.45 */ ++ { ++ struct dict_avp_data data = { ++ 1046, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Priority-Level", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Pre-emption-Capability AVP - 3GPP TS 29.212 #5.3.46 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Pre-emption-Capability)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "PRE-EMPTION_CAPABILITY_ENABLED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "PRE-EMPTION_CAPABILITY_DISABLED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1047, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Pre-emption-Capability", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Pre-emption-Vulnerability AVP - 3GPP TS 29.212 #5.3.47 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Pre-emption-Vulnerability)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "PRE-EMPTION_VULNERABILITY_ENABLED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "PRE-EMPTION_VULNERABILITY_DISABLED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1048, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Pre-emption-Vulnerability", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Allocation-Retention-Priority AVP - 3GPP TS 29.272 #5.3.32 */ ++ { ++ /* ++ ++ Allocation-Retention-Priority ::= < AVP Header: 1034 > ++ { Priority-Level } ++ [ Pre-emption-Capability ] ++ [ Pre-emption-Vulnerability ] ++ ++ The Allocation-Retention-Priority AVP (AVP code 1034) is of type ++ Grouped, and it is used to indicate the priority of allocation and ++ retention, the pre-emption capability and pre-emption vulnerability ++ for the SDF if provided within the QoS-Information-AVP or for the ++ EPS default bearer if provided within the Default-EPS-Bearer-QoS AVP. ++ */ ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1034, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Allocation-Retention-Priority", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Priority-Level", RULE_REQUIRED, -1, 1 } ++ ,{ "Pre-emption-Capability", RULE_OPTIONAL, -1, 1 } ++ ,{ "Pre-emption-Vulnerability", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* PDP-Address AVP - 3GPP TS 32.299 #6.3.2 */ ++ { ++ /* ++ * The PDP-Address-Prefix-Length AVP needs not be available for IPv6 ++ * typed IP-address prefix length of 64 bits. ++ */ ++ struct dict_avp_data data = { ++ 1227, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PDP-Address", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , Address_type, NULL); ++ } ++ ++ /* Subscriber-Status - 3GPP TS 29.272 #7.3.29 */ ++ { ++ struct dict_object * type; ++ struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Subscriber-Status)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "SERVICE_GRANTED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "OPERATOR_DETERMINED_BARRING", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1424, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Subscriber-Status", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata, NULL, &type); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0, type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1, type, NULL); ++ CHECK_dict_new( DICT_AVP, &data, NULL, &type); ++ } ++ ++ /* STN-SR AVP - 3GPP TS 29.272 #7.3.33 */ ++ { ++ struct dict_avp_data data = { ++ 1433, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "STN-SR", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); ++ } ++ ++ /* ICS-Indicator AVP - 3GPP TS 29.272 #7.3.104 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(ICS-Indicator)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "FALSE", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "TRUE", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1491, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "ICS-Indicator", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* IMEI AVP - 3GPP TS 29.272 #7.3.4 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1402, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "IMEI", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, &avp); ++ } ++ ++ /* 3GPP2-MEID AVP - 3GPP TS 29.272 #7.3.6 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1471, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "3GPP2-MEID", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Software Version - 3GPP TS 29.272 #7.3.5 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1403, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Software-Version", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, &avp); ++ } ++ ++ /* Terminal Information AVP - 3GPP TS 29.272 #7.3.3 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1401, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Terminal-Information", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "IMEI", RULE_REQUIRED, 1, 1 } ++ ,{ "3GPP2-MEID", RULE_REQUIRED, 1, 1 } ++ ,{ "Software-Version", RULE_REQUIRED, 1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* ULA-Flags - 3GPP TS 29.272 #7.3.8 */ ++ { ++ struct dict_avp_data data = { ++ 1406, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "ULA-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Visited-PLMN-Id AVP - 3GPP TS 29.272 #7.3.9 */ ++ { ++ struct dict_avp_data data = { ++ 1407, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Visited-PLMN-Id", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Number-Of-Requested-Vectors - 3GPP TS 29.272 #7.3.14 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1410, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Number-Of-Requested-Vectors", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Re-Synchronization-Info - 3GPP TS 29.272 #7.3.15 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1411, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Re-Synchronization-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Immediate-Response-Preferred - 3GPP TS 29.272 #7.3.16 */ ++ { ++ struct dict_avp_data data = { ++ 1412, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Immediate-Response-Preferred", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Requested-EUTRAN-Authentication-Info AVP - 3GPP TS 29.272 #7.3.11 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1408, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Requested-EUTRAN-Authentication-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Number-Of-Requested-Vectors", RULE_OPTIONAL, -1, 1 } ++ ,{ "Immediate-Response-Preferred", RULE_OPTIONAL, -1, 1 } ++ ,{ "Re-Synchronization-Info", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Requested-UTRAN-GERAN-Authentication-Info AVP - 3GPP TS 29.272 #7.3.12 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1409, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Requested-UTRAN-GERAN-Authentication-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Number-Of-Requested-Vectors", RULE_OPTIONAL, -1, 1 } ++ ,{ "Immediate-Response-Preferred", RULE_OPTIONAL, -1, 1 } ++ ,{ "Re-Synchronization-Info", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Item-Number AVP - 3GPP TS 29.272 #7.3.23 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1419, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Item-Number", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* RAND AVP - 3GPP TS 29.272 #7.3.53 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1447, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "RAND", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* XRES AVP - 3GPP TS 29.272 #7.3.54 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1448, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "XRES", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* AUTN AVP - 3GPP TS 29.272 #7.3.55 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1449, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "AUTN", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* SRES AVP - 3GPP TS 29.272 #7.3.60 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1454, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SRES", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* KASME AVP - 3GPP TS 29.272 #7.3.56 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1450, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "KASME", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Kc AVP - 3GPP TS 29.272 #7.3.59 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1453, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Kc", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Trace-Collection-Entity AVP - 3GPP TS 29.272 #7.3.96 */ ++ { ++ struct dict_avp_data data = { ++ 1452, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Collection-Entity", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, Address_type, NULL); ++ } ++ ++ /* E-UTRAN-Vector - 3GPP TS 29.272 #7.3.18 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1414, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "E-UTRAN-Vector", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Item-Number", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAND", RULE_REQUIRED, -1, 1 } ++ ,{ "XRES", RULE_REQUIRED, -1, 1 } ++ ,{ "AUTN", RULE_REQUIRED, -1, 1 } ++ ,{ "KASME", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* UTRAN-Vector - 3GPP TS 29.272 #7.3.19 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1415, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "UTRAN-Vector", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Item-Number", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAND", RULE_REQUIRED, -1, 1 } ++ ,{ "XRES", RULE_REQUIRED, -1, 1 } ++ ,{ "AUTN", RULE_REQUIRED, -1, 1 } ++ ,{ "Confidentiality-Key", RULE_REQUIRED, -1, 1 } ++ ,{ "Integrity-Key", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* GERAN-Vector - 3GPP TS 29.272 #7.3.20 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1416, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "GERAN-Vector", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Item-Number", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAND", RULE_REQUIRED, -1, 1 } ++ ,{ "SRES", RULE_REQUIRED, -1, 1 } ++ ,{ "Kc", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Authentication-Info - 3GPP TS 29.272 #7.3.17 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1413, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Authentication-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "E-UTRAN-Vector", RULE_OPTIONAL, -1, -1 } ++ ,{ "UTRAN-Vector", RULE_OPTIONAL, -1, -1 } ++ ,{ "GERAN-Vector", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Network-Access-Mode - 3GPP TS 29.272 #7.3.21 */ ++ { ++ struct dict_object * type; ++ struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Network-Access-Mode)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "PACKET_AND_CIRCUIT", { .u32 = 0 }}; ++ struct dict_enumval_data t_1 = { "ONLY_PACKET", { .u32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1417, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Network-Access-Mode", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , type, NULL); ++ CHECK_dict_new( DICT_AVP, &data , type, NULL); ++ } ++ ++ /* HPLMN-ODB AVP - 3GPP TS 29.272 #7.3.22 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1418, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "HPLMN-ODB", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Cancellation-Type - 3GPP TS 29.272 #7.3.24 */ ++ { ++ struct dict_object * type; ++ struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Cancellation-Type)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "MME_UPDATE_PROCEDURE", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "SGSN_UPDATE_PROCEDURE", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "SUBSCRIPTION_WITHDRAWAL", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "UPDATE_PROCEDURE_IWF", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "INITIAL_ATTACH_PROCEDURE", { .i32 = 4 }}; ++ ++ struct dict_avp_data data = { ++ 1420, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Cancellation-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata, NULL, &type); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0, type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1, type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2, type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3, type, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4, type, NULL); ++ CHECK_dict_new( DICT_AVP, &data, NULL, &type); ++ } ++ ++ /* DSR-Flags AVP - 3GPP TS 29.272 #7.3.25 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1421, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "DSR-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* DSA-Flags AVP - 3GPP TS 29.272 #7.3.26 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1422, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "DSA-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Context-Identifier AVP - 3GPP TS 29.272 #7.3.27 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1423, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Context-Identifier", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Operator-Determined-Barring AVP - 3GPP TS 29.272 #7.3.30 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1425, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Operator-Determined-Barring", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Access-Restriction-Data AVP - 3GPP TS 29.272 #7.3.31 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1426, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Access-Restriction-Data", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* APN-OI-Replacement AVP - 3GPP TS 29.272 #7.3.32 */ ++ { ++ struct dict_avp_data data = { ++ 1427, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "APN-OI-Replacement", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); ++ } ++ ++ /* All-APN-Configurations-Included-Indicator AVP - 3GPP TS 29.272 #7.3.33 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(All-APN-Configurations-Included-Indicator)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "All_APN_CONFIGURATIONS_INCLUDED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "MODIFIED/ADDED_APN_CONFIGURATIONS_INCLUDED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1428, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "All-APN-Configurations-Included-Indicator", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* PDN-Type AVP - 3GPP TS 29.272 #7.3.62 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(PDN-Type)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "IPv4", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "IPv6", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "IPv4v6", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "IPv4_OR_IPv6", { .i32 = 3 }}; ++ ++ struct dict_avp_data data = { ++ 1456, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PDN-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* EPS-Subscribed-QoS-Profile AVP - 3GPP TS 29.272 #7.3.37 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1431, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "EPS-Subscribed-QoS-Profile", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "QoS-Class-Identifier", RULE_REQUIRED, -1, 1 } ++ ,{ "Allocation-Retention-Priority", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* VPLMN-Dynamic-Address-Allowed AVP - 3GPP TS 29.272 #7.3.38 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(VPLMN-Dynamic-Address-Allowed)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "NOTALLOWED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "ALLOWED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1432, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "VPLMN-Dynamic-Address-Allowed", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Alert-Reason AVP - 3GPP TS 29.272 #7.3.83 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Alert-Reason)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "UE_PRESENT", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "UE_MEMORY_AVAILABLE", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1434, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Alert-Reason", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* PDN-GW-Allocation-Type AVP - 3GPP TS 29.272 #7.3.44 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(PDN-GW-Allocation-Type)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "STATIC", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "DYNAMIC", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1438, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PDN-GW-Allocation-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Expiration-Date AVP - 3GPP TS 29.272 #7.3.80 */ ++ { ++ struct dict_avp_data data = { ++ 1439, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Expiration-Date", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , Time_type, NULL); ++ } ++ ++ /* CSG-Id AVP - 3GPP TS 29.272 #7.3.79 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1437, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "CSG-Id", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* AMBR AVP - 3GPP TS 29.272 #7.3.41 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1435, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "AMBR", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Max-Requested-Bandwidth-UL", RULE_REQUIRED, -1, 1 } ++ ,{ "Max-Requested-Bandwidth-DL", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Specific-APN-Info AVP - 3GPP TS 29.272 #7.3.82 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1472, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Specific-APN-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Service-Selection", RULE_REQUIRED, -1, 1 } ++ ,{ "MIP6-Agent-Info", RULE_REQUIRED, -1, 1 } ++ ,{ "Visited-Network-Identifier", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* SIPTO-Permission AVP - 3GPP TS 29.272 #7.3.135 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(SIPTO-Permission)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "SIPTO_ALLOWED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "SIPTO_NOTALLOWED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1613, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SIPTO-Permission", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* LIPA-Permission AVP - 3GPP TS 29.272 #7.3.133 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(LIPA-Permission)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "LIPA-PROHIBITED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "LIPA-ONLY", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "LIPA-CONDITIONAL", { .i32 = 2 }}; ++ ++ struct dict_avp_data data = { ++ 1618, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "LIPA-Permission", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* List-Of-Measurements AVP - 3GPP TS 29.272 #7.3.139 */ ++ { ++ struct dict_avp_data data = { ++ 1625, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "List-Of-Measurements", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Reporting-Trigger AVP - 3GPP TS 29.272 #7.3.140 */ ++ { ++ struct dict_avp_data data = { ++ 1626, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Reporting-Trigger", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Report-Interval AVP - 3GPP TS 29.272 #7.3.141 and TS 32.422 #5.10.5 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Report-Interval)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "250ms", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "500ms", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "1000ms", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "2000ms", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "3000ms", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "4000ms", { .i32 = 5 }}; ++ struct dict_enumval_data t_6 = { "6000ms", { .i32 = 6 }}; ++ struct dict_enumval_data t_7 = { "8000ms", { .i32 = 7 }}; ++ struct dict_enumval_data t_8 = { "12000ms", { .i32 = 8 }}; ++ struct dict_enumval_data t_9 = { "16000ms", { .i32 = 9 }}; ++ struct dict_enumval_data t_10 = { "20000ms", { .i32 = 10 }}; ++ struct dict_enumval_data t_11 = { "24000ms", { .i32 = 11 }}; ++ struct dict_enumval_data t_12 = { "28000ms", { .i32 = 12 }}; ++ struct dict_enumval_data t_13 = { "32000ms", { .i32 = 13 }}; ++ struct dict_enumval_data t_14 = { "64000ms", { .i32 = 14 }}; ++ /* Possible in LTE */ ++ struct dict_enumval_data t_15 = { "120ms", { .i32 = 15 }}; ++ struct dict_enumval_data t_16 = { "240ms", { .i32 = 16 }}; ++ struct dict_enumval_data t_17 = { "480ms", { .i32 = 17 }}; ++ struct dict_enumval_data t_18 = { "640ms", { .i32 = 18 }}; ++ struct dict_enumval_data t_19 = { "1024ms", { .i32 = 19 }}; ++ struct dict_enumval_data t_20 = { "2048ms", { .i32 = 20 }}; ++ struct dict_enumval_data t_21 = { "5120ms", { .i32 = 21 }}; ++ struct dict_enumval_data t_22 = { "10240ms", { .i32 = 22 }}; ++ struct dict_enumval_data t_23 = { "1min", { .i32 = 23 }}; ++ struct dict_enumval_data t_24 = { "6min", { .i32 = 24 }}; ++ struct dict_enumval_data t_25 = { "12min", { .i32 = 25 }}; ++ struct dict_enumval_data t_26 = { "30min", { .i32 = 26 }}; ++ struct dict_enumval_data t_27 = { "60min", { .i32 = 27 }}; ++ ++ struct dict_avp_data data = { ++ 1627, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Report-Interval", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_6 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_7 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_8 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_9 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_10 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_11 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_12 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_13 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_14 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_15 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_16 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_17 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_18 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_19 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_20 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_21 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_22 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_23 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_24 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_25 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_26 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_27 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Report-Amount AVP - 3GPP TS 29.272 #7.3.142 and TS 32.422 #5.10.6 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Report-Amount)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "1", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "2", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "4", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "8", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "16", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "32", { .i32 = 5 }}; ++ struct dict_enumval_data t_6 = { "64", { .i32 = 6 }}; ++ struct dict_enumval_data t_7 = { "infinity", { .i32 = 7 }}; ++ ++ struct dict_avp_data data = { ++ 1628, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Report-Amount", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_6 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_7 , avp, NULL); ++ ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Event-Threshold-RSRP AVP - 3GPP TS 29.272 #7.3.143 */ ++ { ++ struct dict_avp_data data = { ++ 1629, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Event-Threshold-RSRP", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Event-Threshold-RSRQ AVP - 3GPP TS 29.272 #7.3.144 */ ++ { ++ struct dict_avp_data data = { ++ 1630, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Event-Threshold-RSRQ", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Logging-Interval AVP - 3GPP TS 29.272 #7.3.145 and TS 32.422 #5.10.8 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Logging-Interval)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "1.28", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "2.56", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "5.12", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "10.24", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "20.48", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "30.72", { .i32 = 5 }}; ++ struct dict_enumval_data t_6 = { "40.96", { .i32 = 6 }}; ++ struct dict_enumval_data t_7 = { "61.44", { .i32 = 7 }}; ++ ++ struct dict_avp_data data = { ++ 1631, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Logging-Interval", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_6 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_7 , avp, NULL); ++ ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Logging-Duration AVP - 3GPP TS 29.272 #7.3.145 and TS 32.422 #5.10.9 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Logging-Duration)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "600sec", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "1200sec", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "2400sec", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "3600sec", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "5400sec", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "7200sec", { .i32 = 5 }}; ++ ++ struct dict_avp_data data = { ++ 1632, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Logging-Duration", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* APN-Configuration AVP - 3GPP TS 29.272 #7.3.35 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1430, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "APN-Configuration", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Context-Identifier", RULE_REQUIRED, -1, 1 } ++ ,{ "Served-Party-IP-Address", RULE_OPTIONAL, -1, 2 } ++ ,{ "PDN-Type", RULE_REQUIRED, -1, 1 } ++ ,{ "Service-Selection", RULE_REQUIRED, -1, 1 } ++ ,{ "EPS-Subscribed-QoS-Profile", RULE_OPTIONAL, -1, 1 } ++ ,{ "VPLMN-Dynamic-Address-Allowed", RULE_OPTIONAL, -1, 1 } ++ ,{ "MIP6-Agent-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Visited-Network-Identifier", RULE_OPTIONAL, -1, 1 } ++ ,{ "PDN-GW-Allocation-Type", RULE_OPTIONAL, -1, 1 } ++ ,{ "3GPP-Charging-Characteristics", RULE_OPTIONAL, -1, 1 } ++ ,{ "AMBR", RULE_OPTIONAL, -1, 1 } ++ ,{ "Specific-APN-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "APN-OI-Replacement", RULE_OPTIONAL, -1, 1 } ++ ,{ "SIPTO-Permission", RULE_OPTIONAL, -1, 1 } ++ ,{ "LIPA-Permission", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* APN-Configuration-Profile AVP - 3GPP TS 29.272 #7.3.34 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1429, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "APN-Configuration-Profile", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Context-Identifier", RULE_REQUIRED, -1, 1 } ++ ,{ "All-APN-Configurations-Included-Indicator", RULE_REQUIRED, -1, 1 } ++ ,{ "APN-Configuration", RULE_REQUIRED, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* CSG-Subscription-Data AVP - 3GPP TS 29.272 #7.3.78 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1436, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "CSG-Subscription-Data", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "CSG-Id", RULE_REQUIRED, -1, 1 } ++ ,{ "Expiration-Date", RULE_OPTIONAL, -1, 1 } ++ ,{ "Service-Selection", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* RAT-Frequency-Selection-Priority-ID AVP - 3GPP TS 29.272 #7.3.46 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1440, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "RAT-Frequency-Selection-Priority-ID", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* IDA-Flags AVP - 3GPP TS 29.272 #7.3.47 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1441, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "IDA-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* PUA-Flags AVP - 3GPP TS 29.272 #7.3.48 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1442, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PUA-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* NOR-Flags AVP - 3GPP TS 29.272 #7.3.49 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1443, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "NOR-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* User-Id AVP - 3GPP TS 29.272 #7.3.50 */ ++ { ++ struct dict_avp_data data = { ++ 1444, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "User-Id", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); ++ } ++ ++ /* Equipment-Status AVP - 3GPP TS 29.272 #7.3.51 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Equipment-Status)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "WHITELISTED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "BLACKLISTED", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "GREYLISTED", { .i32 = 2 }}; ++ ++ struct dict_avp_data data = { ++ 1445, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Equipment-Status", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Regional-Subscription-Zone-Code AVP - 3GPP TS 29.272 #7.3.52 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1446, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Regional-Subscription-Zone-Code", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Roaming-Restricted-Due-To-Unsupported-Feature AVP - 3GPP TS 29.272 #7.3.81 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Roaming-Restricted-Due-To-Unsupported-Feature)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "Roaming-Restricted-Due-To-Unsupported-Feature", { .i32 = 0 }}; ++ ++ struct dict_avp_data data = { ++ 1457, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Roaming-Restricted-Due-To-Unsupported-Feature", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Trace-Reference AVP - 3GPP TS 29.272 #7.3.64 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1459, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Reference", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Trace-Depth AVP - 3GPP TS 29.272 #7.3.67 and 3GPP TS 32.422 #5.3 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Trace-Depth)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "Minimum", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "Medium", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "Maximum", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "MinimumWithoutVendorSpecificExtension", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "MediumWithoutVendorSpecificExtension", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "MaximumWithoutVendorSpecificExtension", { .i32 = 5 }}; ++ ++ struct dict_avp_data data = { ++ 1462, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Depth", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Trace-NE-Type-List AVP - 3GPP TS 29.272 #7.3.68 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1463, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-NE-Type-List", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Trace-Event-List AVP - 3GPP TS 29.272 #7.3.69 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1464, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Interface-List", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Trace-Event-List AVP - 3GPP TS 29.272 #7.3.70 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1465, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Event-List", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* OMC-Id AVP - 3GPP TS 29.272 #7.3.71 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1466, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "OMC-Id", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Complete-Data-List-Included-Indicator AVP - 3GPP TS 29.272 #7.3.73 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Complete-Data-List-Included-Indicator)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "All_PDP_CONTEXTS_INCLUDED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "MODIFIED/ADDED_PDP CONTEXTS_INCLUDED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1468, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Complete-Data-List-Included-Indicator", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* PDP-Type AVP - 3GPP TS 29.272 #7.3.75 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1470, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PDP-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* GMLC-Number AVP - 3GPP TS 29.272 #7.3.85 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1474, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "GMLC-Number", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* SS-Code AVP - 3GPP TS 29.272 #7.3.87 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1476, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SS-Code", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* SS-Status AVP - 3GPP TS 29.272 #7.3.88 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1477, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SS-Status", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* Notification-To-UE-User AVP - 3GPP TS 29.272 #7.3.89 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Notification-To-UE-User)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "NOTIFY_LOCATION_ALLOWED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "NOTIFYANDVERIFY_LOCATION_ALLOWED_IF_NO_RESPONSE", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "NOTIFYANDVERIFY_LOCATION_NOT_ALLOWED_IF_NO_RESPONSE", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "LOCATION_NOT_ALLOWED", { .i32 = 3 }}; ++ ++ struct dict_avp_data data = { ++ 1478, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Notification-To-UE-User", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* Client-Identity AVP - 3GPP TS 29.272 #7.3.91 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1480, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Client-Identity", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* GMLC-Restriction AVP - 3GPP TS 29.272 #7.3.92 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(GMLC-Restriction)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "GMLC_LIST", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "HOME_COUNTRY", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1481, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "GMLC-Restriction", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* PLMN-Client AVP - 3GPP TS 29.272 #7.3.92 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(PLMN-Client)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "BROADCAST_SERVICE", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "O_AND_M_HPLMN", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "O_AND_M_VPLMN", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "ANONYMOUS_LOCATION", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "TARGET_UE_SUBSCRIBED_SERVICE", { .i32 = 4 }}; ++ ++ struct dict_avp_data data = { ++ 1482, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PLMN-Client", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* ServiceTypeIdentity AVP - 3GPP TS 29.272 #7.3.95 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1484, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "ServiceTypeIdentity", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ } ++ ++ /* QoS-Subscribed - 3GPP TS 29.272 #7.3.77 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1404, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "QoS-Subscribed", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* ULR-Flags - 3GPP TS 29.272 #7.3.7 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1405, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "ULR-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Ext-PDP-Type AVP - 3GPP TS 29.272 #7.3.75A */ ++ { ++ struct dict_avp_data data = { ++ 1620, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Ext-PDP-Type", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Ext-PDP-Address AVP - 3GPP TS 29.272 #7.3.129 */ ++ { ++ struct dict_avp_data data = { ++ 1621, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Ext-PDP-Address", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, Address_type, NULL); ++ } ++ ++ /* TS-Code AVP - 3GPP TS 29.272 #7.3.100 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1487, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "TS-Code", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* External-Client AVP - 3GPP TS 29.272 #7.3.90 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1479, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "External-Client", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Client-Identity", RULE_REQUIRED, -1, 1 } ++ ,{ "GMLC-Restriction", RULE_OPTIONAL, -1, 1 } ++ ,{ "Notification-To-UE-User", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Service-Type AVP - 3GPP TS 29.272 #7.3.94 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1483, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Service-Type", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "ServiceTypeIdentity", RULE_REQUIRED, -1, 1 } ++ ,{ "GMLC-Restriction", RULE_OPTIONAL, -1, 1 } ++ ,{ "Notification-To-UE-User", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* LCS-PrivacyException AVP - 3GPP TS 29.272 #7.3.86 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1475, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "LCS-PrivacyException", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "SS-Code", RULE_REQUIRED, -1, 1 } ++ ,{ "SS-Status", RULE_REQUIRED, -1, 1 } ++ ,{ "Notification-To-UE-User", RULE_OPTIONAL, -1, 1 } ++ ,{ "External-Client", RULE_OPTIONAL, -1, -1 } ++ ,{ "PLMN-Client", RULE_OPTIONAL, -1, -1 } ++ ,{ "Service-Type", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* MO-LR AVP - 3GPP TS 29.272 #7.3.96 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1485, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MO-LR", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "SS-Code", RULE_REQUIRED, -1, 1 } ++ ,{ "SS-Status", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* LCS-Info AVP - 3GPP TS 29.272 #7.3.84 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1473, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "LCS-Info", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "GMLC-Number", RULE_OPTIONAL, -1, -1 } ++ ,{ "LCS-PrivacyException", RULE_OPTIONAL, -1, -1 } ++ ,{ "MO-LR", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* PDP-Context AVP - 3GPP TS 29.272 #7.3.74 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1469, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PDP-Context", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Context-Identifier", RULE_REQUIRED, -1, 1 } ++ ,{ "PDP-Type", RULE_REQUIRED, -1, 1 } ++ ,{ "PDP-Address", RULE_OPTIONAL, -1, 1 } ++ ,{ "QoS-Subscribed", RULE_REQUIRED, -1, 1 } ++ ,{ "VPLMN-Dynamic-Address-Allowed", RULE_OPTIONAL, -1, 1 } ++ ,{ "Service-Selection", RULE_REQUIRED, -1, 1 } ++ ,{ "3GPP-Charging-Characteristics", RULE_OPTIONAL, -1, 1 } ++ ,{ "Ext-PDP-Type", RULE_OPTIONAL, -1, 1 } ++ ,{ "Ext-PDP-Address", RULE_OPTIONAL, -1, 1 } ++ ,{ "AMBR", RULE_OPTIONAL, -1, 1 } ++ ,{ "SIPTO-Permission", RULE_OPTIONAL, -1, 1 } ++ ,{ "LIPA-Permission", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* GPRS-Subscription-Data AVP - 3GPP TS 29.272 #7.3.72 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1467, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "GPRS-Subscription-Data", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Complete-Data-List-Included-Indicator", RULE_REQUIRED, -1, 1 } ++ ,{ "PDP-Context", RULE_REQUIRED, -1, 50 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Teleservice-List AVP - 3GPP TS 29.272 #7.3.99 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1486, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Teleservice-List", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "TS-Code", RULE_REQUIRED, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Call-Barring-Infor-List AVP - 3GPP TS 29.272 #7.3.101 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1488, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Call-Barring-Infor-List", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "SS-Code", RULE_REQUIRED, 1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* SGSN-Number AVP - 3GPP TS 29.272 #7.3.102 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1489, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SGSN-Number", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* IDR-Flags AVP - 3GPP TS 29.272 #7.3.103 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1490, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "IDR-Flags", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* IMS-Voice-Over-PS-Sessions-Supported AVP - 3GPP TS 29.272 #7.3.106 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(IMS-Voice-Over-PS-Sessions-Supported)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "NOT_SUPPORTED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "SUPPORTED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1492, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "IMS-Voice-Over-PS-Sessions-Supported", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ /* Create the Enumerated type, and then the AVP */ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , avp, NULL); ++ } ++ ++ /* SGSN-Number AVP - 3GPP TS 29.272 #7.3.102 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Homogeneous-Support-of-IMS-Voice-Over-PSSessions)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "NOT_SUPPORTED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "SUPPORTED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1493, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Homogeneous-Support-of-IMS-Voice-Over-PSSessions", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Last-UE-Activity-Time AVP - 3GPP TS 29.272 #7.3.108 */ ++ { ++ struct dict_avp_data data = { ++ 1494, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Last-UE-Activity-Time", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , Time_type, NULL); ++ } ++ ++ /* E-UTRAN-Cell-Global-Identity AVP - 3GPP TS 29.272 #7.3.117 */ ++ { ++ struct dict_avp_data data = { ++ 1602, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "E-UTRAN-Cell-Global-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Tracking-Area-Identity AVP - 3GPP TS 29.272 #7.3.118 */ ++ { ++ struct dict_avp_data data = { ++ 1603, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Tracking-Area-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Cell-Global-Identity AVP - 3GPP TS 29.272 #7.3.119 */ ++ { ++ struct dict_avp_data data = { ++ 1604, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Cell-Global-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Routing-Area-Identity AVP - 3GPP TS 29.272 #7.3.120 */ ++ { ++ struct dict_avp_data data = { ++ 1605, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Routing-Area-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Location-Area-Identity AVP - 3GPP TS 29.272 #7.3.121 */ ++ { ++ struct dict_avp_data data = { ++ 1606, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Location-Area-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Service-Area-Identity AVP - 3GPP TS 29.272 #7.3.122 */ ++ { ++ struct dict_avp_data data = { ++ 1607, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Service-Area-Identity", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Geographical-Information AVP - 3GPP TS 29.272 #7.3.123 */ ++ { ++ struct dict_avp_data data = { ++ 1608, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Geographical-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Geodetic-Information AVP - 3GPP TS 29.272 #7.3.124 */ ++ { ++ struct dict_avp_data data = { ++ 1609, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Geodetic-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, NULL); ++ } ++ ++ /* Current-Location-Retrieved AVP - 3GPP TS 29.272 #7.3.125 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Current-Location-Retrieved)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "ACTIVE-LOCATION-RETRIEVAL", { .i32 = 0 }}; ++ ++ struct dict_avp_data data = { ++ 1610, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Current-Location-Retrieved", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Age-Of-Location-Information AVP - 3GPP TS 29.272 #7.3.126 */ ++ { ++ struct dict_avp_data data = { ++ 1611, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Age-Of-Location-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* UE-SRVCC-Capability AVP - 3GPP TS 29.272 #7.3.130 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(UE-SRVCC-Capability)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "UE-SRVCC-NOT-SUPPORTED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "UE-SRVCC-SUPPORTED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1615, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "UE-SRVCC-Capability", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* MPS-Priority AVP - 3GPP TS 29.272 #7.3.131 */ ++ { ++ struct dict_avp_data data = { ++ 1616, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MPS-Priority", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* VPLMN-LIPA-Allowed AVP - 3GPP TS 29.272 #7.3.132 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(VPLMN-LIPA-Allowed)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "LIPA-NOTALLOWED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "LIPA-ALLOWED", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1617, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "VPLMN-LIPA-Allowed", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Subscribed-Periodic-RAU-TAU-Timer AVP - 3GPP TS 29.272 #7.3.134 */ ++ { ++ struct dict_avp_data data = { ++ 1619, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Subscribed-Periodic-RAU-TAU-Timer", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* Job-Type AVP - 3GPP TS 29.272 #7.3.132 and 3GPP TS 32.422 #5.10.1 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Job-Type)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "Immediate-MDT-Only", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "Logged-MDT-only", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "Trace-Only", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "Immediate-MDT-and-Trace", { .i32 = 3 }}; ++ ++ struct dict_avp_data data = { ++ 1623, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Job-Type", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* Relay-Node-Indicator AVP - 3GPP TS 29.272 #7.3.147 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Relay-Node-Indicator)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "NOT_RELAY_NODE", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "RELAY_NODE", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1633, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Relay-Node-Indicator", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* MDT-User-Consent AVP - 3GPP TS 29.272 #7.3.148 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(MDT-User-Consent)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "CONSENT_NOT_GIVEN", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "CONSENT_GIVEN", { .i32 = 1 }}; ++ ++ struct dict_avp_data data = { ++ 1634, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MDT-User-Consent", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* PUR-Flags AVP - 3GPP TS 29.272 #7.3.149 */ ++ { ++ struct dict_avp_data data = { ++ 1635, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "PUR-Flags", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_UNSIGNED32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, NULL); ++ } ++ ++ /* User-State AVP - 3GPP TS 29.272 #7.3.114 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(User-State)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "DETACHED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "ATTACHED_NOT_REACHABLE_FOR_PAGING", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "ATTACHED_REACHABLE_FOR_PAGING", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "CONNECTED_NOT_REACHABLE_FOR_PAGING", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "CONNECTED_REACHABLE_FOR_PAGING", { .i32 = 4 }}; ++ struct dict_enumval_data t_5 = { "NETWORK_DETERMINED_NOT_REACHABLE", { .i32 = 5 }}; ++ ++ struct dict_avp_data data = { ++ 1499, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "User-State", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_5 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* MME-User-State AVP - 3GPP TS 29.272 #7.3.112 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1497, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MME-User-State", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "User-State", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* SGSN-User-State AVP - 3GPP TS 29.272 #7.3.113 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1498, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SGSN-User-State", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "User-State", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* EPS-User-State AVP - 3GPP TS 29.272 #7.3.110 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1495, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "EPS-User-State", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "MME-User-State", RULE_OPTIONAL, -1, 1 } ++ ,{ "SGSN-User-State", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* MME-Location-Information AVP - 3GPP TS 29.272 #7.3.115 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1600, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MME-Location-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "E-UTRAN-Cell-Global-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Tracking-Area-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Geographical-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "Geodetic-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "Current-Location-Retrieved", RULE_OPTIONAL, -1, 1 } ++ ,{ "Age-Of-Location-Information", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* SGSN-Location-Information AVP - 3GPP TS 29.272 #7.3.116 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1601, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "SGSN-Location-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Cell-Global-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Location-Area-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Service-Area-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Routing-Area-Identity", RULE_OPTIONAL, -1, 1 } ++ ,{ "Geographical-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "Geodetic-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "Current-Location-Retrieved", RULE_OPTIONAL, -1, 1 } ++ ,{ "Age-Of-Location-Information", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Area-Scope AVP - 3GPP TS 29.272 #7.3.138 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1624, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Area-Scope", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Cell-Global-Identity", RULE_OPTIONAL, -1, -1 } ++ ,{ "E-UTRAN-Cell-Global-Identity", RULE_OPTIONAL, -1, -1 } ++ ,{ "Routing-Area-Identity", RULE_OPTIONAL, -1, -1 } ++ ,{ "Location-Area-Identity", RULE_OPTIONAL, -1, -1 } ++ ,{ "Tracking-Area-Identity", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* MDT-Configuration AVP - 3GPP TS 29.272 #7.3.136 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1622, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "MDT-Configuration", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Job-Type", RULE_REQUIRED, -1, 1 } ++ ,{ "Area-Scope", RULE_OPTIONAL, -1, 1 } ++ ,{ "List-Of-Measurements", RULE_OPTIONAL, -1, 1 } ++ ,{ "Reporting-Trigger", RULE_OPTIONAL, -1, 1 } ++ ,{ "Report-Interval", RULE_OPTIONAL, -1, 1 } ++ ,{ "Report-Amount", RULE_OPTIONAL, -1, 1 } ++ ,{ "Event-Threshold-RSRP", RULE_OPTIONAL, -1, 1 } ++ ,{ "Event-Threshold-RSRQ", RULE_OPTIONAL, -1, 1 } ++ ,{ "Logging-Interval", RULE_OPTIONAL, -1, 1 } ++ ,{ "Logging-Duration", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* EPS-Location-Information AVP - 3GPP TS 29.272 #7.3.111 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1496, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "EPS-Location-Information", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "MME-Location-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "SGSN-Location-Information", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Active-APN AVP - 3GPP TS 29.173 #7.3.127 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1612, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Active-APN", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Context-Identifier", RULE_REQUIRED, -1, 1 } ++ ,{ "Service-Selection", RULE_OPTIONAL, -1, 1 } ++ ,{ "MIP6-Agent-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Visited-Network-Identifier", RULE_OPTIONAL, -1, 1 } ++ ,{ "Specific-APN-Info", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Error-Diagnostic AVP - 3GPP TS 29.272 #7.3.128 */ ++ { ++ struct dict_object * avp; ++ struct dict_type_data tdata = { AVP_TYPE_INTEGER32, "Enumerated(Error-Diagnostic)" , NULL, NULL, NULL }; ++ struct dict_enumval_data t_0 = { "GPRS_DATA_SUBSCRIBED", { .i32 = 0 }}; ++ struct dict_enumval_data t_1 = { "NO_GPRS_DATA_SUBSCRIBED", { .i32 = 1 }}; ++ struct dict_enumval_data t_2 = { "ODB-ALL-APN", { .i32 = 2 }}; ++ struct dict_enumval_data t_3 = { "ODB-HPLMN-APN", { .i32 = 3 }}; ++ struct dict_enumval_data t_4 = { "ODB-VPLMN-APN", { .i32 = 4 }}; ++ ++ struct dict_avp_data data = { ++ 1614, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Error-Diagnostic", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_INTEGER32 /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_TYPE, &tdata , NULL, &avp); ++ CHECK_dict_new( DICT_ENUMVAL, &t_0 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_1 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_2 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_3 , avp, NULL); ++ CHECK_dict_new( DICT_ENUMVAL, &t_4 , avp, NULL); ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ } ++ ++ /* GMLC-Address AVP - 3GPP TS 29.173 #6.4.7 */ ++ { ++ struct dict_avp_data data = { ++ 2405, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "GMLC-Address", /* Name */ ++ AVP_FLAG_VENDOR, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_OCTETSTRING /* base type of data */ ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , Address_type, NULL); ++ } ++ ++ /* Supported Features AVP - 3GPP TS 29.229 */ ++ { ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 628, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Supported-Features", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Vendor-Id", RULE_REQUIRED, 1, 1 } ++ ,{ "Feature-List-ID", RULE_REQUIRED, 1, 1 } ++ ,{ "Feature-List", RULE_REQUIRED, 1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Trace-Data AVP - 3GPP TS 29.272 #7.3.63 */ ++ { ++ struct dict_object * avp; ++ ++ struct dict_avp_data data = { ++ 1458, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Trace-Data", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Trace-Reference", RULE_REQUIRED, -1, 1 } ++ ,{ "Trace-Depth", RULE_REQUIRED, -1, 1 } ++ ,{ "Trace-NE-Type-List", RULE_REQUIRED, -1, 1 } ++ ,{ "Trace-Interface-List", RULE_OPTIONAL, -1, 1 } ++ ,{ "Trace-Event-List", RULE_REQUIRED, -1, 1 } ++ ,{ "OMC-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Trace-Collection-Entity", RULE_REQUIRED, -1, 1 } ++ ,{ "MDT-Configuration", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data, NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* Subscription-Data AVP - 3GPP TS 29.272 #7.3.2 */ ++ { ++ /* ++ ++ * The Subscription-Data AVP is of type Grouped. It shall contain ++ * the information related to the user profile relevant for ++ * EPS and GERAN/UTRAN. ++ ++ Subscription-Data ::= <AVP header: 1400 10415> ++ [ Subscriber-Status ] ++ [ MSISDN ] ++ [ STN-SR ] ++ [ ICS-Indicator ] ++ [ Network-Access-Mode ] ++ [ Operator-Determined-Barring ] ++ [ HPLMN-ODB ] ++ *10[ Regional-Subscription-Zone-Code] ++ [ Access-Restriction-Data ] ++ [ APN-OI-Replacement ] ++ [ LCS-Info ] ++ [ Teleservice-List ] ++ [ Call-Barring-Infor-List ] ++ [ 3GPP-Charging-Characteristics ] ++ [ AMBR ] ++ [ APN-Configuration-Profile ] ++ [ RAT-Frequency-Selection-Priority-ID ] ++ [ Trace-Data] ++ [ GPRS-Subscription-Data ] ++ *[ CSG-Subscription-Data ] ++ [ Roaming-Restricted-Due-To-Unsupported-Feature ] ++ [ Subscribed-Periodic-RAU-TAU-Timer ] ++ [ MPS-Priority ] ++ [ VPLMN-LIPA-Allowed ] ++ [ Relay-Node-Indicator ] ++ [ MDT-User-Consent ] ++ *[ AVP ] ++ ++ * The AMBR included in this grouped AVP shall include the AMBR ++ * associated to the user’s subscription (UE-AMBR); ++ * Max-Requested-Bandwidth-UL and Max-Requested-Bandwidth-DL within ++ * this AVP shall not both be set to "0". ++ * The APN-OI-Replacement included in this grouped AVP shall include ++ * the UE level APN-OI-Replacement associated to the user’s subscription. ++ */ ++ struct dict_object * avp; ++ struct dict_avp_data data = { ++ 1400, /* Code */ ++ VENDOR_3GPP_Id, /* Vendor */ ++ "Subscription-Data", /* Name */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ ++ AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flag values */ ++ AVP_TYPE_GROUPED /* base type of data */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Subscriber-Status", RULE_OPTIONAL, -1, 1 } ++ ,{ "MSISDN", RULE_OPTIONAL, -1, 1 } ++ ,{ "STN-SR", RULE_OPTIONAL, -1, 1 } ++ ,{ "ICS-Indicator", RULE_OPTIONAL, -1, 1 } ++ ,{ "Network-Access-Mode", RULE_OPTIONAL, -1, 1 } ++ ,{ "Operator-Determined-Barring", RULE_OPTIONAL, -1, 1 } ++ ,{ "HPLMN-ODB", RULE_OPTIONAL, -1, 1 } ++ ,{ "Regional-Subscription-Zone-Code", RULE_OPTIONAL, -1, 10 } ++ ,{ "Access-Restriction-Data", RULE_OPTIONAL, -1, 1 } ++ ,{ "APN-OI-Replacement", RULE_OPTIONAL, -1, 1 } ++ ,{ "LCS-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Teleservice-List", RULE_OPTIONAL, -1, 1 } ++ ,{ "Call-Barring-Infor-List", RULE_OPTIONAL, -1, 1 } ++ ,{ "3GPP-Charging-Characteristics", RULE_OPTIONAL, -1, 1 } ++ ,{ "AMBR", RULE_OPTIONAL, -1, 1 } ++ ,{ "APN-Configuration-Profile", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAT-Frequency-Selection-Priority-ID", RULE_OPTIONAL, -1, 1 } ++ ,{ "Trace-Data", RULE_OPTIONAL, -1, 1 } ++ ,{ "GPRS-Subscription-Data", RULE_OPTIONAL, -1, 1 } ++ ,{ "CSG-Subscription-Data", RULE_OPTIONAL, -1, -1 } ++ ,{ "Roaming-Restricted-Due-To-Unsupported-Feature", RULE_OPTIONAL, -1, 1 } ++ ,{ "Subscribed-Periodic-RAU-TAU-Timer", RULE_OPTIONAL, -1, 1 } ++ ,{ "MPS-Priority", RULE_OPTIONAL, -1, 1 } ++ ,{ "VPLMN-LIPA-Allowed", RULE_OPTIONAL, -1, 1 } ++ ,{ "Relay-Node-Indicator", RULE_OPTIONAL, -1, 1 } ++ ,{ "MDT-User-Consent", RULE_OPTIONAL, -1, 1 } ++ }; ++ ++ CHECK_dict_new( DICT_AVP, &data , NULL, &avp); ++ PARSE_loc_rules( rules, avp ); ++ } ++ ++ /* S6A-Update Location Request - 3GPP TS 29.272 #7.2.3 */ ++ { ++ /* ++ ++ The Update-Location-Request (ULR) command, indicated by the ++ Command-Code field set to 316 and the "R" bit set in ++ the Command Flags field, is sent from MME or SGSN to HSS. ++ ++ < Update-Location-Request> ::= < Diameter Header: 316, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Destination-Host ] ++ { Destination-Realm } ++ { User-Name } ++ *[ Supported-Features ] ++ [ Terminal-Information ] ++ { RAT-Type } ++ { ULR-Flags } ++ [ UE-SRVCC-Capability ] ++ { Visited-PLMN-Id } ++ [ SGSN-Number ] ++ [ Homogeneous-Support-of-IMS-Voice-Over-PS-Sessions ] ++ [ GMLC-Address ] ++ *[ Active-APN ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 316, /* Code */ ++ "Update-Location-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Terminal-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAT-Type", RULE_REQUIRED, 1, 1 } ++ ,{ "ULR-Flags", RULE_REQUIRED, 1, 1 } ++ ,{ "UE-SRVCC-Capability", RULE_OPTIONAL, -1, 1 } ++ ,{ "Visited-PLMN-Id", RULE_REQUIRED, 1, 1 } ++ ,{ "SGSN-Number", RULE_OPTIONAL, -1, 1 } ++ ,{ "Homogeneous-Support-of-IMS-Voice-Over-PSSessions", RULE_OPTIONAL, -1, 1 } ++ ,{ "GMLC-Address", RULE_OPTIONAL, -1, 1 } ++ ,{ "Active-APN", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* S6A-Update Location Answer - 3GPP TS 29.272 #7.2.4 */ ++ { ++ /* ++ ++ The Update-Location-Answer (ULA) command, indicated by the ++ Command-Code field set to 316 and the 'R' bit cleared ++ in the Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Update-Location-Answer> ::= < Diameter Header: 316, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ [ Error-Diagnostic ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ *[ Supported-Features ] ++ [ ULA-Flags ] ++ [ Subscription-Data ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 316, /* Code */ ++ "Update-Location-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Error-Diagnostic", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "ULA-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Subscription-Data", RULE_OPTIONAL, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* S6A-Cancel-Location-Request - 3GPP TS 29.272 #7.2.7 */ ++ { ++ /* ++ ++ The Cancel-Location-Request (CLR) command, indicated by the ++ Command-Code field set to 317 and the 'R' bit set in ++ the Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Cancel-Location-Request> ::= < Diameter Header: 317, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ { Destination-Host } ++ { Destination-Realm } ++ { User-Name } ++ *[Supported-Features ] ++ { Cancellation-Type } ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 317, /* Code */ ++ "Cancel-Location-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Cancellation-Type", RULE_REQUIRED, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* S6A-Cancel-Location-Answer - 3GPP TS 29.272 #7.2.8 */ ++ { ++ /* ++ ++ The Cancel-Location-Answer (CLA) command, indicated by the ++ Command-Code field set to 317 and the 'R' bit cleared ++ in the Command Flags field, is sent from MME or SGSN to HSS. ++ ++ < Cancel-Location-Answer> ::= < Diameter Header: 317, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ *[ Supported-Features ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 317, /* Code */ ++ "Cancel-Location-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* S6A-Authentication-Information-Request - 3GPP TS 29.272 #7.2.4 */ ++ { ++ /* ++ ++ The Authentication-Information-Request (AIR) command, indicated by ++ the Command-Code field set to 318 and the 'R' ++ bit set in the Command Flags field, is sent from MME or SGSN to HSS. ++ ++ < Authentication-Information-Request> ::= < Diameter Header: 318, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Destination-Host ] ++ { Destination-Realm } ++ { User-Name } ++ *[ Supported-Features ] ++ [ Requested-EUTRAN-Authentication-Info ] ++ [ Requested-UTRAN-GERAN-Authentication-Info ] ++ { Visited-PLMN-Id } ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 318, /* Code */ ++ "Authentication-Information-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Requested-EUTRAN-Authentication-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Requested-UTRAN-GERAN-Authentication-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Visited-PLMN-Id", RULE_REQUIRED, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* S6A-Authentication-Information-Answer - 3GPP TS 29.272 #7.2.6 */ ++ { ++ /* ++ ++ The Authentication-Information-Answer (AIA) command, indicated by ++ the Command-Code field set to318 and the 'R' bit cleared in the ++ Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Authentication-Information-Answer> ::= < Diameter Header: 318, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ [ Error-Diagnostic ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ *[ Supported-Features ] ++ [ Authentication-Info ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 318, /* Code */ ++ "Authentication-Information-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Error-Diagnostic", RULE_OPTIONAL, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Authentication-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Insert-Subscriber-Data-Request IDR Command - 3GPP TS 29.272 #7.2.9 */ ++ { ++ /* ++ ++ The Insert-Subscriber-Data-Request (IDR) command, indicated by the ++ Command-Code field set to 319 and the 'R' bit set in the Command ++ Flags field, is sent from HSS to MME or SGSN. ++ ++ < Insert-Subscriber-Data-Request> ::= < Diameter Header: 319, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ { Destination-Host } ++ { Destination-Realm } ++ { User-Name } ++ *[ Supported-Features] ++ { Subscription-Data} ++ [IDR- Flags ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 319, /* Code */ ++ "Insert-Subscriber-Data-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Subscription-Data", RULE_REQUIRED, -1, 1 } ++ ,{ "IDR-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Insert-Subscriber-Data-Answer IDA Command - 3GPP TS 29.272 #7.2.10 */ ++ { ++ /* ++ ++ The Insert-Subscriber-Data-Request (IDR) command, indicated by the ++ Command-Code field set to 319 and the 'R' bit set in the Command ++ Flags field, is sent from HSS to MME or SGSN. ++ ++ < Insert-Subscriber-Data-Answer> ::= < Diameter Header: 319, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ *[ Supported-Features ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ IMS-Voice-Over-PS-Sessions-Supported ] ++ [ Last-UE-Activity-Time ] ++ [ RAT-Type ] ++ [ IDA-Flags ] ++ [ EPS-User-State ] ++ [ EPS-Location-Information ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 319, /* Code */ ++ "Insert-Subscriber-Data-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "IMS-Voice-Over-PS-Sessions-Supported", RULE_OPTIONAL, -1, 1 } ++ ,{ "Last-UE-Activity-Time", RULE_OPTIONAL, -1, 1 } ++ ,{ "RAT-Type", RULE_OPTIONAL, -1, 1 } ++ ,{ "IDA-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "EPS-User-State", RULE_OPTIONAL, -1, 1 } ++ ,{ "EPS-Location-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Delete-Subscriber-Data-Request (DSR) Command - 3GPP TS 29.272 #7.2.11 */ ++ { ++ /* ++ ++ The Delete-SubscriberData-Request (DSR) command, indicated by ++ the Command-Code field set to 320 and the 'R' bit ++ set in the Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Delete-Subscriber-Data-Request > ::= < Diameter Header: 320, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ { Destination-Host } ++ { Destination-Realm } ++ { User-Name } ++ *[ Supported-Features ] ++ { DSR-Flags } ++ *[ Context-Identifier ] ++ [ Trace-Reference ] ++ *[ TS-Code ] ++ *[ SS-Code ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 320, /* Code */ ++ "Delete-SubscriberData-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "DSR-Flags", RULE_REQUIRED, -1, 1 } ++ ,{ "Context-Identifier", RULE_OPTIONAL, -1, -1 } ++ ,{ "Trace-Reference", RULE_OPTIONAL, -1, 1 } ++ ,{ "TS-Code", RULE_OPTIONAL, -1, -1 } ++ ,{ "SS-Code", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Delete-Subscriber-Data-Answer (DSA) Command - 3GPP TS 29.272 #7.2.12 */ ++ { ++ /* ++ ++ The Delete-SubscriberData-Answer (DSA) command, indicated by the ++ Command-Code field set to 320 and the 'R' bit ++ cleared in the Command Flags field, is sent from MME or SGSN to HSS. ++ ++ < Delete-Subscriber-Data-Answer> ::= < Diameter Header: 320, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ *[ Supported-Features ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ DSA-Flags ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 320, /* Code */ ++ "Delete-SubscriberData-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "DSA-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Purge-UE-Request (PUR) Command - 3GPP TS 29.272 #7.2.13 */ ++ { ++ /* ++ ++ The Delete-SubscriberData-Request (DSR) command, indicated by ++ the Command-Code field set to 320 and the 'R' bit ++ set in the Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Purge-UE-Request> ::= < Diameter Header: 321, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Destination-Host ] ++ { Destination-Realm } ++ { User-Name } ++ [ PUR-Flags ] ++ *[ Supported-Features ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 321, /* Code */ ++ "Purge-UE-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "PUR-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Purge-UE-Answer (PUA) Command - 3GPP TS 29.272 #7.2.14 */ ++ { ++ /* ++ ++ The Purge-UE-Answer (PUA) command, indicated by the Command-Code ++ field set to 321 and the 'R' bit cleared in the ++ Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Purge-UE-Answer> ::= < Diameter Header: 321, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ *[ Supported-Features ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ PUA-Flags ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 321, /* Code */ ++ "Purge-UE-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "PUA-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Reset-Request (RSR) Command - 3GPP TS 29.272 #7.2.15 */ ++ { ++ /* ++ ++ The Reset-Request (RSR) command, indicated by the Command-Code ++ field set to 322 and the 'R' bit set in the ++ Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Reset-Request> ::= < Diameter Header: 322, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ { Destination-Host } ++ { Destination-Realm } ++ *[ Supported-Features ] ++ *[ User-Id ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 322, /* Code */ ++ "Reset-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "User-Id", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Reset-Answer (RSA) Command - 3GPP TS 29.272 #7.2.16 */ ++ { ++ /* ++ ++ The Authentication-Information-Answer (RSA) command, indicated by ++ the Command-Code field set to 322 and the 'R' ++ bit cleared in the Command Flags field, is sent from MME or SGSN to HSS. ++ ++ < Reset-Answer> ::= < Diameter Header: 322, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ *[ Supported-Features ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 322, /* Code */ ++ "Reset-Anwer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Notify-Request (NOR) Command - 3GPP TS 29.272 #7.2.17 */ ++ { ++ /* ++ ++ The Notify-Request (NOR) command, indicated by the Command-Code ++ field set to 323 and the 'R' bit set in the Command Flags field, ++ is sent from MME or SGSN to HSS. ++ ++ < Notify-Request> ::= < Diameter Header: 323, REQ, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Destination-Host ] ++ { Destination-Realm } ++ { User-Name } ++ *[ Supported-Features ] ++ [ Terminal-Information ] ++ [ MIP6-Agent-Info ] ++ [ Visited-Network-Identifier ] ++ [ Context-Identifier ] ++ [ Service-Selection ] ++ [ Alert-Reason ] ++ [ UE-SRVCC-Capability ] ++ [ NOR-Flags ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 323, /* Code */ ++ "Notify-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Terminal-Information", RULE_OPTIONAL, -1, 1 } ++ ,{ "MIP6-Agent-Info", RULE_OPTIONAL, -1, 1 } ++ ,{ "Visited-Network-Identifier", RULE_OPTIONAL, -1, 1 } ++ ,{ "Context-Identifier", RULE_OPTIONAL, -1, 1 } ++ ,{ "Service-Selection", RULE_OPTIONAL, -1, 1 } ++ ,{ "Alert-Reason", RULE_OPTIONAL, -1, 1 } ++ ,{ "UE-SRVCC-Capability", RULE_OPTIONAL, -1, 1 } ++ ,{ "NOR-Flags", RULE_OPTIONAL, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* Notify-Answer (NOA) Command - 3GPP TS 29.272 #7.2.18 */ ++ { ++ /* ++ ++ The Notify-Answer (NOA) command, indicated by the Command-Code ++ field set to 323 and the 'R' bit cleared in the ++ Command Flags field, is sent from HSS to MME or SGSN. ++ ++ < Notify-Answer> ::= < Diameter Header: 323, PXY, 16777251 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ *[ Supported-Features ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 323, /* Code */ ++ "Notify-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Supported-Features", RULE_OPTIONAL, -1, -1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* ME-Identity-Check-Request (ECR) Command - 3GPP TS 29.272 #7.2.19 */ ++ { ++ /* ++ ++ The ME-Identity-Check-Request (ECR) command, indicated by the ++ Command-Code field set to 324 and the 'R' bit set ++ in the Command Flags field, is sent from MME or SGSN to EIR. ++ ++ < ME-Identity-Check-Request > ::= < Diameter Header: 324, REQ, PXY, 16777252 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Destination-Host ] ++ { Destination-Realm } ++ { Terminal-Information } ++ [ User-Name ] ++ *[ AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 324, /* Code */ ++ "ME-Identity-Check-Request", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } ++ ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Terminal-Information", RULE_REQUIRED, -1, 1 } ++ ,{ "User-Name", RULE_OPTIONAL, -1, 1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ ++ /* ME-Identity-Check-Answer (ECA) Command - 3GPP TS 29.272 #7.2.20 */ ++ { ++ /* ++ ++ The ME-Identity-Check-Answer (ECA) command, indicated by the ++ Command-Code field set to 324 and the 'R' bit ++ cleared in the Command Flags field, is sent from EIR to MME or SGSN. ++ ++ < ME-Identity-Check-Answer> ::= < Diameter Header: 324, PXY, 16777252 > ++ < Session-Id > ++ [ Vendor-Specific-Application-Id ] ++ [ Result-Code ] ++ [ Experimental-Result ] ++ { Auth-Session-State } ++ { Origin-Host } ++ { Origin-Realm } ++ [ Equipment-Status ] ++ *[ AVP ] ++ *[ Failed-AVP ] ++ *[ Proxy-Info ] ++ *[ Route-Record ] ++ */ ++ struct dict_object * cmd; ++ struct dict_cmd_data data = { ++ 324, /* Code */ ++ "ME-Identity-Check-Answer", /* Name */ ++ CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_ERROR, /* Fixed flags */ ++ CMD_FLAG_PROXIABLE /* Fixed flag values */ ++ }; ++ ++ struct local_rules_definition rules[] = ++ { ++ { "Session-Id", RULE_FIXED_HEAD, -1, 1 } ++ ,{ "Vendor-Specific-Application-Id", RULE_OPTIONAL, -1, 1 } ++ ,{ "Result-Code", RULE_OPTIONAL, -1, 1 } ++ ,{ "Experimental-Result", RULE_OPTIONAL, -1, 1 } ++ ,{ "Auth-Session-State", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } ++ ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } ++ ,{ "Equipment-Status", RULE_OPTIONAL, -1, 1 } ++ ,{ "User-Name", RULE_OPTIONAL, -1, 1 } ++ ,{ "Failed-AVP", RULE_OPTIONAL, -1, -1 } ++ ,{ "Proxy-Info", RULE_OPTIONAL, -1, -1 } ++ ,{ "Route-Record", RULE_OPTIONAL, -1, -1 } ++ }; ++ ++ CHECK_dict_new( DICT_COMMAND, &data, s6a_dict, &cmd); ++ PARSE_loc_rules( rules, cmd ); ++ } ++ } ++ ++ TRACE_DEBUG(INFO, "Dictionary Extension 'S6A from 3GPP standard v.10.5' initialized"); ++ return 0; ++} ++EXTENSION_ENTRY("dict_s6a", dict_s6a_init, "dict_nas_mipv6"); +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/include/freeDiameter/freeDiameter-host.h.in freeDiameter-1.1.5/include/freeDiameter/freeDiameter-host.h.in +--- freeDiameter-1.1.5-unmodified/include/freeDiameter/freeDiameter-host.h.in 2012-11-03 18:45:41.000000000 +0100 ++++ freeDiameter-1.1.5/include/freeDiameter/freeDiameter-host.h.in 2013-02-12 10:56:29.411429498 +0100 +@@ -37,6 +37,9 @@ + #ifndef FD_IS_CONFIG + #define FD_IS_CONFIG + ++#if HAVE_CONFIG_H ++# include "config.h" ++#else + #cmakedefine HAVE_NTOHLL + #cmakedefine HAVE_MALLOC_H + #cmakedefine HAVE_SIGNALENT_H +@@ -57,6 +60,7 @@ + #cmakedefine GNUTLS_VERSION_210 + #cmakedefine GNUTLS_VERSION_300 + #cmakedefine GNUTLS_VERSION_310 ++#endif /* !HAVE_CONFIG_H */ + + #cmakedefine ERRORS_ON_TODO + #cmakedefine DEBUG +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/include/freeDiameter/libfdproto.h freeDiameter-1.1.5/include/freeDiameter/libfdproto.h +--- freeDiameter-1.1.5-unmodified/include/freeDiameter/libfdproto.h 2012-11-03 18:45:41.000000000 +0100 ++++ freeDiameter-1.1.5/include/freeDiameter/libfdproto.h 2013-02-05 13:46:06.683419353 +0100 +@@ -499,7 +499,7 @@ + TRACE_DEBUG_ALL( "Check FCT: " #__call__ ); \ + __ret__ = (__call__); \ + if (__ret__ != 0) { \ +- TRACE_DEBUG_ERROR("ERROR: in '" #__call__ "':\t%s", strerror(__ret__)); \ ++ TRACE_DEBUG_ERROR("ERROR: in %s:%d'" #__call__ "':\t%s", __FILE__, __LINE__, strerror(__ret__)); \ + __fallback__; \ + } \ + } + +diff -NaurB -x '*~' -x build freeDiameter-1.1.5-unmodified/libfdproto/messages.c freeDiameter-1.1.5/libfdproto/messages.c +--- freeDiameter-1.1.5-unmodified/libfdproto/messages.c 2012-11-03 18:45:41.000000000 +0100 ++++ freeDiameter-1.1.5/libfdproto/messages.c 2013-02-14 14:41:42.281217289 +0100 +@@ -967,8 +967,12 @@ + + /* Check the parameters */ + CHECK_PARAMS( CHECK_MSG(msg) ); +- CHECK_PARAMS( msg->msg_public.msg_flags & CMD_FLAG_REQUEST ); /* we associate with requests only */ ++// CHECK_PARAMS( msg->msg_public.msg_flags & CMD_FLAG_REQUEST ); /* we associate with requests only */ + CHECK_PARAMS( (anscb == NULL) || (msg->msg_cb.fct == NULL) ); /* We are not overwritting a cb */ ++ /* No need to associate a callback with an answer. */ ++ if ((msg->msg_public.msg_flags & CMD_FLAG_REQUEST) == 0) { ++ return 0; ++ } + + /* Associate callback and data with the message, if any */ + msg->msg_cb.fct = anscb; diff --git a/openair-cn/S6A/freediameter/install_freediameter.sh b/openair-cn/S6A/freediameter/install_freediameter.sh new file mode 100755 index 0000000000..99e1911739 --- /dev/null +++ b/openair-cn/S6A/freediameter/install_freediameter.sh @@ -0,0 +1,116 @@ +# !/bin/sh + +CURRENT_PATH=`pwd` + +sudo apt-get install autoconf automake gawk cmake make gcc flex bison libsctp1 libsctp-dev libidn2-0-dev \ +libidn11-dev libmysqlclient-dev libxml2-dev swig python-dev cmake-curses-gui \ +valgrind guile-2.0-dev libgmp-dev libgcrypt11-dev gdb unzip libtasn1-3-dev g++ \ +linux-headers-`uname -r` build-essential -y + +source ../../SCRIPTS/utils.bash + +if [ -f install_log.txt ] + then + rm -f install_log.txt +fi + +if [ ! -d /usr/local/src/ ] + then + echo "/usr/local/src/ doesn't exist please create one" + exit -1 +fi + +if [ ! -w /usr/local/src/ ] + then + echo "You don't have permissions to write to /usr/local/src/" + exit -1 +fi + +cd /usr/local/src/ +echo "Downloading nettle archive" + +if [ -f nettle-2.5.tar.gz ] + then + rm -f nettle-2.5.tar.gz +fi +if [ -f nettle-2.5.tar ] + then + rm -f nettle-2.5.tar +fi +if [ -d nettle-2.5 ] + then + rm -rf nettle-2.5/ +fi + +wget ftp://ftp.lysator.liu.se/pub/security/lsh/nettle-2.5.tar.gz > install_log.txt +gunzip nettle-2.5.tar.gz > install_log.txt +echo "Uncompressing nettle archive" +tar -xf nettle-2.5.tar +cd nettle-2.5/ +./configure --disable-openssl --enable-shared --prefix=/usr > install_log.txt +if [ $? -ne 0 ] +then + exit -1 +fi +echo "Compiling nettle" +make -j2 > install_log.txt 2>&1 +make check > install_log.txt +sudo make install > install_log.txt +cd ../ + +echo "Downloading gnutls archive" + +if [ -f gnutls-3.1.0.tar.xz ] + then + rm -f gnutls-3.1.0.tar.xz +fi +if [ -d gnutls-3.1.0/ ] + then + rm -rf gnutls-3.1.0/ +fi + +wget ftp://ftp.gnutls.org/gcrypt/gnutls/v3.1/gnutls-3.1.0.tar.xz > install_log.txt +tar -xf gnutls-3.1.0.tar.xz +echo "Uncompressing gnutls archive" +cd gnutls-3.1.0/ +./configure --prefix=/usr +if [ $? -ne 0 ] +then + exit -1 +fi +echo "Compiling gnutls" +make -j2 > install_log.txt 2>&1 +sudo make install > install_log.txt +cd ../ + +echo "Downloading freeDiameter archive" + +if [ -f 1.1.5.tar.gz ] + then + rm -f 1.1.5.tar.gz +fi +if [ -d freeDiameter-1.1.5/ ] + then + rm -rf freeDiameter-1.1.5/ +fi + +wget http://www.freediameter.net/hg/freeDiameter/archive/1.1.5.tar.gz > install_log.txt +tar -xf 1.1.5.tar.gz > install_log.txt +echo "Uncompressing freeDiameter archive" +cd freeDiameter-1.1.5 +patch -p1 < $CURRENT_PATH/freediameter-1.1.5.patch > install_log.txt +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ > install_log.txt +if [ $? -ne 0 ] +then + exit -1 +fi +echo "Compiling freeDiameter" +make -j2 > install_log.txt 2>&1 +#make help +make test > install_log.txt +sudo make install > install_log.txt + +cd $CURRENT_PATH +./make_certs.sh diff --git a/openair-cn/S6A/freediameter/make_certs.sh b/openair-cn/S6A/freediameter/make_certs.sh new file mode 100755 index 0000000000..2391dd0a9d --- /dev/null +++ b/openair-cn/S6A/freediameter/make_certs.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +rm -rf demoCA +mkdir demoCA +echo 01 > demoCA/serial +touch demoCA/index.txt + +user=$(whoami) +HOSTNAME=$(hostname -f) + +echo "Creating certificate for user '$HOSTNAME'" + +# CA self certificate +openssl req -new -batch -x509 -days 3650 -nodes -newkey rsa:1024 -out cacert.pem -keyout cakey.pem -subj /CN=eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM + +openssl genrsa -out user.key.pem 1024 +openssl req -new -batch -out user.csr.pem -key user.key.pem -subj /CN=$HOSTNAME.eur/C=FR/ST=PACA/L=Aix/O=Eurecom/OU=CM +openssl ca -cert cacert.pem -keyfile cakey.pem -in user.csr.pem -out user.cert.pem -outdir . -batch + +if [ ! -d /usr/local/etc/freeDiameter ] +then + echo "Creating non existing directory: /usr/local/etc/freeDiameter/" + sudo mkdir /usr/local/etc/freeDiameter/ +fi + +echo "Copying cakey.pem user.key.pem cacert.pem to /usr/local/etc/freeDiameter/" +sudo cp user.key.pem user.cert.pem cacert.pem /usr/local/etc/freeDiameter/ + +# openssl genrsa -out ubuntu.key.pem 1024 +# openssl req -new -batch -x509 -out ubuntu.csr.pem -key ubuntu.key.pem -subj /CN=ubuntu.localdomain/C=FR/ST=BdR/L=Aix/O=fD/OU=Tests +# openssl ca -cert cacert.pem -keyfile cakey.pem -in ubuntu.csr.pem -out ubuntu.cert.pem -outdir . -batch diff --git a/openair-cn/S6A/freediameter/s6a.conf b/openair-cn/S6A/freediameter/s6a.conf new file mode 100644 index 0000000000..fbf1fdf345 --- /dev/null +++ b/openair-cn/S6A/freediameter/s6a.conf @@ -0,0 +1,61 @@ +# -------- Local --------- + +# Uncomment if the framework cannot resolv it. +Identity = "roux.test.fr"; +Realm = "test.fr"; + +# TLS configuration (see previous section) +TLS_Cred = "/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/roux.cert.pem", +"/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/roux.key.pem"; +TLS_CA = "/homes/roux/lte-epc/openair3/OPENAIRHSS/conf/cacert.pem"; + +# Disable use of TCP protocol (only listen and connect in SCTP) +# Default : TCP enabled +No_TCP; +#No_SCTP; + +# Limit the number of SCTP streams +SCTP_streams = 15; + +NoRelay; +TLS_old_method; +AppServThreads = 1; + +# -------- Extensions --------- + +# Uncomment (and create rtd.conf) to specify routing table for this peer. +#LoadExtension = "rt_default.fdx" : "rtd.conf"; + +# Uncomment (and create acl.conf) to allow incoming connections from other peers. +#LoadExtension = "acl_wl.fdx" : "acl.conf"; + +# Uncomment to display periodic state information +#LoadExtension = "dbg_monitor.fdx"; + +# Uncomment to enable an interactive Python interpreter session. +# (see doc/dbg_interactive.py.sample for more information) +#LoadExtension = "dbg_interactive.fdx"; + +# Load the RFC4005 dictionary objects +#LoadExtension = "dict_nasreq.fdx"; + +LoadExtension = "dict_nas_mipv6.fdx"; +LoadExtension = "dict_s6a.fdx"; + +# Load RFC4072 dictionary objects +#LoadExtension = "dict_eap.fdx"; + +# Load the Diameter EAP server extension (requires diameap.conf) +#LoadExtension = "app_diameap.fdx" : "diameap.conf"; + +# Load the Accounting Server extension (requires app_acct.conf) +#LoadExtension = "app_acct.fdx" : "app_acct.conf"; + +# -------- Peers --------- + +# The framework will actively attempt to establish and maintain a connection +# with the peers listed here. +# For only accepting incoming connections, see the acl_wl.fx extension. + +# ConnectPeer = "hss.test.fr" { ConnectTo = "192.168.56.101"; No_IPv6; No_TCP; Port = 3868; Realm = "test.fr"; }; +# ConnectPeer = "hss.test.fr" { ConnectTo = "192.168.56.1"; No_TLS; }; diff --git a/openair-cn/S6A/s6a_apn_conf.c b/openair-cn/S6A/s6a_apn_conf.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/openair-cn/S6A/s6a_auth_info.c b/openair-cn/S6A/s6a_auth_info.c new file mode 100644 index 0000000000..cbcefbee7e --- /dev/null +++ b/openair-cn/S6A/s6a_auth_info.c @@ -0,0 +1,380 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdint.h> + +#include "mme_config.h" + +#include "assertions.h" +#include "conversions.h" + +#include "intertask_interface.h" +#include "security_types.h" +#include "s6a_defs.h" +#include "s6a_messages.h" + +static +int s6a_parse_rand(struct avp_hdr *hdr, uint8_t *rand_p) +{ + int ret = 0; + DevCheck(hdr->avp_value->os.len == RAND_LENGTH_OCTETS, RAND_LENGTH_OCTETS, + hdr->avp_value->os.len, 0); + DevAssert(rand_p != NULL); + + STRING_TO_RAND(hdr->avp_value->os.data, rand_p, ret); + return ret; +} + +static +int s6a_parse_xres(struct avp_hdr *hdr, res_t *xres) +{ + int ret = 0; + DevCheck(hdr->avp_value->os.len >= XRES_LENGTH_MIN && + hdr->avp_value->os.len <= XRES_LENGTH_MAX, XRES_LENGTH_MIN, + XRES_LENGTH_MAX, hdr->avp_value->os.len); + DevAssert(xres != NULL); + + STRING_TO_XRES(hdr->avp_value->os.data, hdr->avp_value->os.len, xres, ret); + return ret; +} + +static +int s6a_parse_autn(struct avp_hdr *hdr, uint8_t *autn) +{ + int ret = 0; + DevCheck(hdr->avp_value->os.len == AUTN_LENGTH_OCTETS, AUTN_LENGTH_OCTETS, + hdr->avp_value->os.len, 0); + DevAssert(autn != NULL); + + STRING_TO_AUTN(hdr->avp_value->os.data, autn, ret); + return ret; +} + +static +int s6a_parse_kasme(struct avp_hdr *hdr, uint8_t *kasme) +{ + int ret = 0; + DevCheck(hdr->avp_value->os.len == KASME_LENGTH_OCTETS, KASME_LENGTH_OCTETS, + hdr->avp_value->os.len, 0); + DevAssert(kasme != NULL); + + STRING_TO_KASME(hdr->avp_value->os.data, kasme, ret); + return ret; +} + +static inline +int s6a_parse_e_utran_vector(struct avp *avp_vector, eutran_vector_t *vector) +{ + int ret = 0x0f; + struct avp *avp; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_avp_hdr(avp_vector, &hdr)); + + DevCheck(hdr->avp_code == AVP_CODE_E_UTRAN_VECTOR, + hdr->avp_code, AVP_CODE_E_UTRAN_VECTOR, 0); + + CHECK_FCT(fd_msg_browse(avp_vector, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + + switch(hdr->avp_code) { + case AVP_CODE_RAND: + CHECK_FCT(s6a_parse_rand(hdr, vector->rand)); + ret &= ~0x01; + break; + case AVP_CODE_XRES: + CHECK_FCT(s6a_parse_xres(hdr, &vector->xres)); + ret &= ~0x02; + break; + case AVP_CODE_AUTN: + CHECK_FCT(s6a_parse_autn(hdr, vector->autn)); + ret &= ~0x04; + break; + case AVP_CODE_KASME: + CHECK_FCT(s6a_parse_kasme(hdr, vector->kasme)); + ret &= ~0x08; + break; + default: + /* Unexpected AVP */ + S6A_ERROR("Unexpected AVP with code %d\n", hdr->avp_code); + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + if (ret) { + S6A_ERROR("Missing AVP for E-UTRAN vector: %c%c%c%c\n", + ret & 0x01 ? 'R':'-', ret & 0x02 ? 'X':'-', + ret & 0x04 ? 'A':'-', ret & 0x08 ? 'K':'-'); + return -1; + } + return 0; +} + +static inline +int s6a_parse_authentication_info_avp(struct avp *avp_auth_info, + authentication_info_t *authentication_info) +{ + struct avp *avp; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_avp_hdr(avp_auth_info, &hdr)); + + DevCheck(hdr->avp_code == AVP_CODE_AUTHENTICATION_INFO, + hdr->avp_code, AVP_CODE_AUTHENTICATION_INFO, 0); + + /* Init the list of vectors */ + STAILQ_INIT(&authentication_info->e_utran_vectors); + authentication_info->nb_of_vectors = 0; + + CHECK_FCT(fd_msg_browse(avp_auth_info, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + + switch(hdr->avp_code) { + case AVP_CODE_E_UTRAN_VECTOR: { + struct eutran_vector_s *vector; + vector = calloc(1, sizeof(struct eutran_vector_s)); + CHECK_FCT(s6a_parse_e_utran_vector(avp, vector)); + STAILQ_INSERT_TAIL(&authentication_info->e_utran_vectors, + vector, entries); + authentication_info->nb_of_vectors ++; + } break; + default: + /* We should only receive E-UTRAN-Vectors */ + S6A_ERROR("Unexpected AVP with code %d\n", hdr->avp_code); + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +int s6a_aia_cb(struct msg **msg, struct avp *paramavp, + struct session *sess, void *opaque, + enum disp_action *act) +{ + struct msg *ans; + struct msg *qry; + struct avp *avp; + struct avp_hdr *hdr; + + MessageDef *message_p; + s6a_auth_info_ans_t *s6a_auth_info_ans_p; + + DevAssert(msg != NULL); + + ans = *msg; + /* Retrieve the original query associated with the asnwer */ + CHECK_FCT(fd_msg_answ_getq(ans, &qry)); + + DevAssert(qry != NULL); + + message_p = alloc_new_message(TASK_S6A, S6A_AUTH_INFO_ANS); + s6a_auth_info_ans_p = &message_p->msg.s6a_auth_info_ans; + + S6A_DEBUG("Received S6A Authentication Information Answer (AIA)\n"); + + CHECK_FCT(fd_msg_search_avp(qry, s6a_fd_cnf.dataobj_s6a_user_name, &avp)); + if (avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + sprintf(s6a_auth_info_ans_p->imsi, "%*s", (int)hdr->avp_value->os.len, + hdr->avp_value->os.data); + } else { + DevMessage("Query has been freed before we received the answer\n"); + } + + /* Retrieve the result-code */ + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_result_code, &avp)); + if (avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + + s6a_auth_info_ans_p->result.present = S6A_RESULT_BASE; + s6a_auth_info_ans_p->result.choice.base = hdr->avp_value->u32; + + if (hdr->avp_value->u32 != ER_DIAMETER_SUCCESS) { + S6A_ERROR("Got error %u:%s\n", hdr->avp_value->u32, + retcode_2_string(hdr->avp_value->u32)); + goto err; + } + } else { + /* The result-code is not present, may be it is an experimental result + * avp indicating a 3GPP specific failure. + */ + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_experimental_result, &avp)); + if (avp) { + /* The procedure has failed within the HSS. + * NOTE: contrary to result-code, the experimental-result is a grouped + * AVP and requires parsing its childs to get the code back. + */ + s6a_auth_info_ans_p->result.present = S6A_RESULT_EXPERIMENTAL; + s6a_parse_experimental_result(avp, &s6a_auth_info_ans_p->result.choice.experimental); + + goto err; + } else { + /* Neither result-code nor experimental-result is present -> + * totally incorrect behaviour here. + */ + S6A_ERROR("Experimental-Result and Result-Code are absent: " + "This is not a correct behaviour\n"); + goto err; + } + } + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_authentication_info, &avp)); + if (avp) { + CHECK_FCT(s6a_parse_authentication_info_avp(avp, &s6a_auth_info_ans_p->auth_info)); + } else { + DevMessage("We requested E-UTRAN vectors with an immediate response...\n"); + } + + send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); +err: + return 0; +} + +int s6a_generate_authentication_info_req(s6a_auth_info_req_t *air_p) +{ + struct avp *avp; + struct msg *msg; + struct session *sess; + + union avp_value value; + + DevAssert(air_p != NULL); + + /* Create the new update location request message */ + CHECK_FCT(fd_msg_new(s6a_fd_cnf.dataobj_s6a_air, 0, &msg)); + + /* Create a new session */ + CHECK_FCT(fd_sess_new(&sess, fd_g_config->cnf_diamid, + fd_g_config->cnf_diamid_len, (os0_t)"apps6a", 6)); + { + os0_t sid; + size_t sidlen; + CHECK_FCT(fd_sess_getsid(sess, &sid, &sidlen)); + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_session_id, 0, &avp)); + value.os.data = sid; + value.os.len = sidlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_FIRST_CHILD, avp)); + } + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_auth_session_state, 0, &avp)); + /* No State maintained */ + value.i32 = 1; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + /* Add Origin_Host & Origin_Realm */ + CHECK_FCT(fd_msg_add_origin(msg, 0)); + + config_read_lock(&mme_config); + + /* Destination Host */ + { + char host[40] = "hss."; + size_t hostlen; + + strcat(host, mme_config.realm); + + hostlen = strlen(host); + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_destination_host, 0, &avp)); + value.os.data = (unsigned char *)host; + value.os.len = hostlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + /* Destination_Realm */ + { + char *realm = mme_config.realm; + size_t realmlen = strlen(realm); + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_destination_realm, 0, &avp)); + value.os.data = (unsigned char *)realm; + value.os.len = realmlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + + config_unlock(&mme_config); + + /* Adding the User-Name (IMSI) */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_user_name, 0, &avp)); + value.os.data = (unsigned char *)air_p->imsi; + value.os.len = strlen(air_p->imsi); + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + /* Adding the visited plmn id */ + { + uint8_t plmn[3] = { 0, 0, 0 }; + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_visited_plmn_id, 0, &avp)); + + PLMN_T_TO_TBCD(air_p->visited_plmn, plmn); + + value.os.data = plmn; + value.os.len = 3; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + /* Adding the requested E-UTRAN authentication info AVP */ + { + struct avp *child_avp; + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_req_eutran_auth_info, 0, &avp)); + + /* Add the number of requested vectors */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_number_of_requested_vectors, 0, &child_avp)); + value.u32 = air_p->nb_of_vectors; + CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value)); + CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp)); + + /* We want to use the vectors immediately in HSS so we have to add + * the Immediate-Response-Preferred AVP. + * Value of this AVP is not significant. + */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_immediate_response_pref, 0, &child_avp)); + value.u32 = 0; + CHECK_FCT(fd_msg_avp_setvalue(child_avp, &value)); + CHECK_FCT(fd_msg_avp_add(avp, MSG_BRW_LAST_CHILD, child_avp)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + CHECK_FCT(fd_msg_send(&msg, NULL, NULL)); + + return 0; +} diff --git a/openair-cn/S6A/s6a_defs.h b/openair-cn/S6A/s6a_defs.h new file mode 100644 index 0000000000..db4c0da782 --- /dev/null +++ b/openair-cn/S6A/s6a_defs.h @@ -0,0 +1,201 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> + +#include "mme_config.h" +#include "queue.h" + +#ifndef S6A_DEFS_H_ +#define S6A_DEFS_H_ + +#ifndef S6A_DEBUG +# define S6A_DEBUG(x, args...) do { fprintf(stdout, "[S6A] [D]"x, ##args); } while(0) +#endif +#ifndef S6A_ERROR +# define S6A_ERROR(x, args...) do { fprintf(stderr, "[S6A] [E]"x, ##args); } while(0) +#endif + +#define VENDOR_3GPP (10415) +#define APP_S6A (16777251) + +/* Errors that fall within the Permanent Failures category shall be used to + * inform the peer that the request has failed, and should not be attempted + * again. The Result-Code AVP values defined in Diameter Base Protocol RFC 3588 + * shall be applied. When one of the result codes defined here is included in a + * response, it shall be inside an Experimental-Result AVP and the Result-Code + * AVP shall be absent. + */ +#define DIAMETER_ERROR_USER_UNKNOWN (5001) +#define DIAMETER_ERROR_ROAMING_NOT_ALLOWED (5004) +#define DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION (5420) +#define DIAMETER_ERROR_RAT_NOT_ALLOWED (5421) +#define DIAMETER_ERROR_EQUIPMENT_UNKNOWN (5422) +#define DIAMETER_ERROR_UNKOWN_SERVING_NODE (5423) + +/* Result codes that fall within the transient failures category shall be used + * to inform a peer that the request could not be satisfied at the time it was + * received, but may be able to satisfy the request in the future. The + * Result-Code AVP values defined in Diameter Base Protocol RFC 3588 shall be + * applied. When one of the result codes defined here is included in a response, + * it shall be inside an Experimental-Result AVP and the Result-Code AVP shall + * be absent. + */ +#define DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE (4181) + +#define DIAMETER_ERROR_IS_VENDOR(x) \ + ((x == DIAMETER_ERROR_USER_UNKNOWN) || \ + (x == DIAMETER_ERROR_ROAMING_NOT_ALLOWED) || \ + (x == DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION) || \ + (x == DIAMETER_ERROR_RAT_NOT_ALLOWED) || \ + (x == DIAMETER_ERROR_EQUIPMENT_UNKNOWN) || \ + (x == DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE) || \ + (x == DIAMETER_ERROR_UNKOWN_SERVING_NODE)) + +typedef struct { + struct dict_object *dataobj_s6a_vendor; /* s6a vendor object */ + struct dict_object *dataobj_s6a_app; /* s6a application object */ + + /* Commands */ + struct dict_object *dataobj_s6a_air; /* s6a authentication request */ + struct dict_object *dataobj_s6a_aia; /* s6a authentication answer */ + struct dict_object *dataobj_s6a_ulr; /* s6a update location request */ + struct dict_object *dataobj_s6a_ula; /* s6a update location asnwer */ + struct dict_object *dataobj_s6a_pur; /* s6a purge ue request */ + struct dict_object *dataobj_s6a_pua; /* s6a purge ue answer */ + struct dict_object *dataobj_s6a_clr; /* s6a Cancel Location req */ + struct dict_object *dataobj_s6a_cla; /* s6a Cancel Location ans */ + + /* Some standard basic AVPs */ + struct dict_object *dataobj_s6a_destination_host; + struct dict_object *dataobj_s6a_destination_realm; + struct dict_object *dataobj_s6a_user_name; + struct dict_object *dataobj_s6a_session_id; + struct dict_object *dataobj_s6a_auth_session_state; + struct dict_object *dataobj_s6a_result_code; + struct dict_object *dataobj_s6a_experimental_result; + + /* S6A specific AVPs */ + struct dict_object *dataobj_s6a_visited_plmn_id; + struct dict_object *dataobj_s6a_rat_type; + struct dict_object *dataobj_s6a_ulr_flags; + struct dict_object *dataobj_s6a_ula_flags; + struct dict_object *dataobj_s6a_subscription_data; + struct dict_object *dataobj_s6a_req_eutran_auth_info; + struct dict_object *dataobj_s6a_number_of_requested_vectors; + struct dict_object *dataobj_s6a_immediate_response_pref; + struct dict_object *dataobj_s6a_authentication_info; + struct dict_object *dataobj_s6a_ue_srvcc_cap; + + /* Handlers */ + struct disp_hdl *aia_hdl; /* Authentication Information Answer Handle */ + struct disp_hdl *ula_hdl; /* Update Location Answer Handle */ + struct disp_hdl *pua_hdl; /* Purge UE Answer Handle */ + struct disp_hdl *clr_hdl; /* Cancel Location Request Handle */ +} s6a_fd_cnf_t; + +extern s6a_fd_cnf_t s6a_fd_cnf; + +#define ULR_SINGLE_REGISTRATION_IND (1U) +#define ULR_S6A_S6D_INDICATOR (1U << 1) +#define ULR_SKIP_SUBSCRIBER_DATA (1U << 2) +#define ULR_GPRS_SUBSCRIPTION_DATA_IND (1U << 3) +#define ULR_NODE_TYPE_IND (1U << 4) +#define ULR_INITIAL_ATTACH_IND (1U << 5) +#define ULR_PS_LCS_SUPPORTED_BY_UE (1U << 6) + +#define ULA_SEPARATION_IND (1U) + +#define FLAG_IS_SET(x, flag) \ + ((x) & (flag)) + +#define FLAGS_SET(x, flags) \ + ((x) |= (flags)) + +#define FLAGS_CLEAR(x, flags) \ + ((x) = (x) & ~(flags)) + +/* IANA defined IP address type */ +#define IANA_IPV4 (0x1) +#define IANA_IPV6 (0x2) + +#define AVP_CODE_VENDOR_ID (266) +#define AVP_CODE_EXPERIMENTAL_RESULT (297) +#define AVP_CODE_EXPERIMENTAL_RESULT_CODE (298) +#define AVP_CODE_SERVICE_SELECTION (493) +#define AVP_CODE_BANDWIDTH_UL (516) +#define AVP_CODE_BANDWIDTH_DL (515) +#define AVP_CODE_MSISDN (701) +#define AVP_CODE_SERVED_PARTY_IP_ADDRESS (848) +#define AVP_CODE_QCI (1028) +#define AVP_CODE_ALLOCATION_RETENTION_PRIORITY (1034) +#define AVP_CODE_PRIORITY_LEVEL (1046) +#define AVP_CODE_PRE_EMPTION_CAPABILITY (1047) +#define AVP_CODE_PRE_EMPTION_VULNERABILITY (1048) +#define AVP_CODE_SUBSCRIPTION_DATA (1400) +#define AVP_CODE_AUTHENTICATION_INFO (1413) +#define AVP_CODE_E_UTRAN_VECTOR (1414) +#define AVP_CODE_NETWORK_ACCESS_MODE (1417) +#define AVP_CODE_CONTEXT_IDENTIFIER (1423) +#define AVP_CODE_SUBSCRIBER_STATUS (1424) +#define AVP_CODE_ACCESS_RESTRICTION_DATA (1426) +#define AVP_CODE_ALL_APN_CONFIG_INC_IND (1428) +#define AVP_CODE_APN_CONFIGURATION_PROFILE (1429) +#define AVP_CODE_APN_CONFIGURATION (1430) +#define AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE (1431) +#define AVP_CODE_AMBR (1435) +#define AVP_CODE_RAND (1447) +#define AVP_CODE_XRES (1448) +#define AVP_CODE_AUTN (1449) +#define AVP_CODE_KASME (1450) +#define AVP_CODE_PDN_TYPE (1456) +#define AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER (1619) + +int s6a_init(const mme_config_t *mme_config); + +int s6a_fd_new_peer(void); + +void s6a_peer_connected_cb(struct peer_info *info, void *arg); + +int s6a_fd_init_dict_objs(void); + +int s6a_parse_subscription_data(struct avp *avp_subscription_data, + subscription_data_t *subscription_data); + +int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr); +inline char *experimental_retcode_2_string(uint32_t ret_code); +inline char *retcode_2_string(uint32_t ret_code); + +#endif /* S6A_DEFS_H_ */ diff --git a/openair-cn/S6A/s6a_dict.c b/openair-cn/S6A/s6a_dict.c new file mode 100644 index 0000000000..3f7c286c01 --- /dev/null +++ b/openair-cn/S6A/s6a_dict.c @@ -0,0 +1,177 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "intertask_interface.h" +#include "s6a_defs.h" +#include "s6a_messages.h" +#include "assertions.h" + +#define CHECK_FD_FCT(fCT) DevAssert(fCT == 0); + +/*! \file s6a_dict.c + * \brief Initialize s6a dictionnary and setup callbacks for procedures + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +int s6a_fd_init_dict_objs(void) +{ + struct disp_when when; + + vendor_id_t vendor_3gpp = VENDOR_3GPP; + application_id_t app_s6a = APP_S6A; + + /* Pre-loading vendor object */ + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, + DICT_VENDOR, + VENDOR_BY_ID, + (void *)&vendor_3gpp, + &s6a_fd_cnf.dataobj_s6a_vendor, + ENOENT)); + + /* Pre-loading application object */ + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_APPLICATION, + APPLICATION_BY_ID, (void *)&app_s6a, + &s6a_fd_cnf.dataobj_s6a_app, ENOENT)); + + /* Pre-loading commands objects */ + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Authentication-Information-Request", + &s6a_fd_cnf.dataobj_s6a_air, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Authentication-Information-Answer", + &s6a_fd_cnf.dataobj_s6a_aia, ENOENT)); + + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Update-Location-Request", + &s6a_fd_cnf.dataobj_s6a_ulr, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Update-Location-Answer", + &s6a_fd_cnf.dataobj_s6a_ula, ENOENT)); + + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Purge-UE-Request", + &s6a_fd_cnf.dataobj_s6a_pur, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Purge-UE-Answer", + &s6a_fd_cnf.dataobj_s6a_pua, ENOENT)); + + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Cancel-Location-Request", + &s6a_fd_cnf.dataobj_s6a_clr, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_COMMAND, + CMD_BY_NAME, "Cancel-Location-Answer", + &s6a_fd_cnf.dataobj_s6a_cla, ENOENT)); + + /* Pre-loading base avps */ + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Destination-Host", + &s6a_fd_cnf.dataobj_s6a_destination_host, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Destination-Realm", + &s6a_fd_cnf.dataobj_s6a_destination_realm, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "User-Name", + &s6a_fd_cnf.dataobj_s6a_user_name, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Session-Id", + &s6a_fd_cnf.dataobj_s6a_session_id, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Auth-Session-State", + &s6a_fd_cnf.dataobj_s6a_auth_session_state, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Result-Code", + &s6a_fd_cnf.dataobj_s6a_result_code, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME, "Experimental-Result", + &s6a_fd_cnf.dataobj_s6a_experimental_result, ENOENT)); + + /* Pre-loading S6A specifics AVPs */ + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Visited-PLMN-Id", + &s6a_fd_cnf.dataobj_s6a_visited_plmn_id, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "RAT-Type", + &s6a_fd_cnf.dataobj_s6a_rat_type, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "ULR-Flags", + &s6a_fd_cnf.dataobj_s6a_ulr_flags, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "ULA-Flags", + &s6a_fd_cnf.dataobj_s6a_ula_flags, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Subscription-Data", + &s6a_fd_cnf.dataobj_s6a_subscription_data, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Requested-EUTRAN-Authentication-Info", + &s6a_fd_cnf.dataobj_s6a_req_eutran_auth_info, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Number-Of-Requested-Vectors", + &s6a_fd_cnf.dataobj_s6a_number_of_requested_vectors, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Immediate-Response-Preferred", + &s6a_fd_cnf.dataobj_s6a_immediate_response_pref, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "Authentication-Info", + &s6a_fd_cnf.dataobj_s6a_authentication_info, ENOENT)); + CHECK_FD_FCT(fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, + AVP_BY_NAME_ALL_VENDORS, "UE-SRVCC-Capability", + &s6a_fd_cnf.dataobj_s6a_ue_srvcc_cap, ENOENT)); + + /* Register callbacks */ + memset(&when, 0, sizeof(when)); + + when.command = s6a_fd_cnf.dataobj_s6a_ula; + when.app = s6a_fd_cnf.dataobj_s6a_app; + + /* Register the callback for Update Location Answer S6A Application */ + CHECK_FD_FCT(fd_disp_register(s6a_ula_cb, DISP_HOW_CC, &when, NULL, + &s6a_fd_cnf.ula_hdl)); + DevAssert(s6a_fd_cnf.ula_hdl != NULL); + + when.command = s6a_fd_cnf.dataobj_s6a_aia; + when.app = s6a_fd_cnf.dataobj_s6a_app; + + /* Register the callback for Authentication Information Answer S6A Application */ + CHECK_FD_FCT(fd_disp_register(s6a_aia_cb, DISP_HOW_CC, &when, NULL, + &s6a_fd_cnf.aia_hdl)); + DevAssert(s6a_fd_cnf.aia_hdl != NULL); + + /* Advertise the support for the test application in the peer */ + CHECK_FD_FCT(fd_disp_app_support(s6a_fd_cnf.dataobj_s6a_app, + s6a_fd_cnf.dataobj_s6a_vendor, 1, 0)); + + return 0; +} diff --git a/openair-cn/S6A/s6a_error.c b/openair-cn/S6A/s6a_error.c new file mode 100644 index 0000000000..2f9ee7d78a --- /dev/null +++ b/openair-cn/S6A/s6a_error.c @@ -0,0 +1,111 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "common_types.h" +#include "s6a_defs.h" + +#include "assertions.h" + +int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr) +{ + struct avp_hdr *hdr; + struct avp *child_avp = NULL; + + if (!avp) { + return EINVAL; + } + + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + DevAssert(hdr->avp_code == AVP_CODE_EXPERIMENTAL_RESULT); + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL)); + while(child_avp) { + CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_EXPERIMENTAL_RESULT_CODE: + S6A_ERROR("Got experimental error %u:%s\n", hdr->avp_value->u32, + experimental_retcode_2_string(hdr->avp_value->u32)); + if (ptr) { + *ptr = (s6a_experimental_result_t)hdr->avp_value->u32; + } + break; + case AVP_CODE_VENDOR_ID: + DevCheck(hdr->avp_value->u32 == 10415, hdr->avp_value->u32, + AVP_CODE_VENDOR_ID, 10415); + break; + default: + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL)); + } + return 0; +} + +inline char *experimental_retcode_2_string(uint32_t ret_code) +{ + switch(ret_code) { + /* Experimental-Result-Codes */ + case DIAMETER_ERROR_USER_UNKNOWN: + return "DIAMETER_ERROR_USER_UNKNOWN"; + case DIAMETER_ERROR_ROAMING_NOT_ALLOWED: + return "DIAMETER_ERROR_ROAMING_NOT_ALLOWED"; + case DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION: + return "DIAMETER_ERROR_UNKNOWN_EPS_SUBSCRIPTION"; + case DIAMETER_ERROR_RAT_NOT_ALLOWED: + return "DIAMETER_ERROR_RAT_NOT_ALLOWED"; + case DIAMETER_ERROR_EQUIPMENT_UNKNOWN: + return "DIAMETER_ERROR_EQUIPMENT_UNKNOWN"; + case DIAMETER_ERROR_UNKOWN_SERVING_NODE: + return "DIAMETER_ERROR_UNKOWN_SERVING_NODE"; + case DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE: + return "DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE"; + default: + break; + } + return "DIAMETER_AVP_UNSUPPORTED"; +} + +inline char *retcode_2_string(uint32_t ret_code) +{ + switch(ret_code) { + case ER_DIAMETER_SUCCESS: + return "DIAMETER_SUCCESS"; + case ER_DIAMETER_MISSING_AVP: + return "DIAMETER_MISSING_AVP"; + case ER_DIAMETER_INVALID_AVP_VALUE: + return "DIAMETER_INVALID_AVP_VALUE"; + default: + break; + } + return "DIAMETER_AVP_UNSUPPORTED"; +} + diff --git a/openair-cn/S6A/s6a_messages.h b/openair-cn/S6A/s6a_messages.h new file mode 100644 index 0000000000..79dde4fb93 --- /dev/null +++ b/openair-cn/S6A/s6a_messages.h @@ -0,0 +1,47 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S6A_MESSAGES_H_ +#define S6A_MESSAGES_H_ + +int s6a_generate_update_location(s6a_update_location_req_t *ulr_p); +int s6a_generate_authentication_info_req(s6a_auth_info_req_t *uar_p); + +int s6a_ula_cb(struct msg **msg, struct avp *paramavp, + struct session *sess, void *opaque, + enum disp_action *act); +int s6a_aia_cb(struct msg **msg, struct avp *paramavp, + struct session *sess, void *opaque, + enum disp_action *act); + +int s6a_parse_subscription_data(struct avp *avp_subscription_data, + subscription_data_t *subscription_data); + +#endif /* S6A_MESSAGES_H_ */ diff --git a/openair-cn/S6A/s6a_peer.c b/openair-cn/S6A/s6a_peer.c new file mode 100644 index 0000000000..52243ea391 --- /dev/null +++ b/openair-cn/S6A/s6a_peer.c @@ -0,0 +1,140 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file s6a_peers.c + * \brief Add a new entity to the list of peers to connect + * \author Sebastien ROUX <sebastien.roux@eurecom.fr> + * \date 2013 + * \version 0.1 + */ + +#include <stdint.h> +#include <unistd.h> + +#include "common_types.h" +#include "intertask_interface.h" +#include "s6a_defs.h" +#include "s6a_messages.h" + +#include "assertions.h" + +void s6a_peer_connected_cb(struct peer_info *info, void *arg) +{ + if (info == NULL) { + S6A_ERROR("Failed to connect to HSS entity\n"); + } else { + S6A_DEBUG("Peer %*s is now connected...\n", + (int)info->pi_diamidlen, info->pi_diamid); + } + + /* For test */ +#if 0 + s6a_auth_info_req_t s6a_air; + + memset(&s6a_air, 0, sizeof(s6a_auth_info_req_t)); + sprintf(s6a_air.imsi, "%14llu", 20834123456789ULL); + + s6a_air.nb_of_vectors = 1; + s6a_air.visited_plmn.MCCdigit2 = 0, + s6a_air.visited_plmn.MCCdigit1 = 8, + s6a_air.visited_plmn.MCCdigit3 = 2, + s6a_air.visited_plmn.MNCdigit1 = 0, + s6a_air.visited_plmn.MNCdigit2 = 3, + s6a_air.visited_plmn.MNCdigit3 = 4, + + s6a_generate_authentication_info_req(&s6a_air); +// #else +// s6a_update_location_req_t s6a_ulr; +// +// memset(&s6a_ulr, 0, sizeof(s6a_update_location_req_t)); +// +// sprintf(s6a_ulr.imsi, "%14llu", 20834123456789ULL); +// s6a_ulr.initial_attach = INITIAL_ATTACH; +// s6a_ulr.rat_type = RAT_EUTRAN; +// s6a_generate_update_location(&s6a_ulr); +#endif +} + +int s6a_fd_new_peer(void) +{ + char host_name[100]; + size_t host_name_len; + char *hss_name; + + int ret = 0; + struct peer_info info; + + memset(&info, 0, sizeof(struct peer_info)); + + if (config_read_lock(&mme_config) != 0) { + S6A_ERROR("Failed to lock configuration for reading\n"); + return -1; + } + + if(fd_g_config->cnf_diamid != NULL) { + free(fd_g_config->cnf_diamid); + fd_g_config->cnf_diamid_len = 0; + } + + DevAssert(gethostname(host_name, 100) == 0); + + host_name_len = strlen(host_name); + host_name[host_name_len] = '.'; + host_name[host_name_len+1] = '\0'; + + strcat(host_name, mme_config.realm); + fd_g_config->cnf_diamid = strdup(host_name); + fd_g_config->cnf_diamid_len = strlen(fd_g_config->cnf_diamid); + + S6A_DEBUG("Diameter identity of MME: %s with length: %zd\n", + fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len); + + hss_name = strdup("hss."); + strcat(hss_name, mme_config.realm); + info.pi_diamid = hss_name; + info.pi_diamidlen = strlen(info.pi_diamid); + + S6A_DEBUG("Diameter identity of HSS: %s with length: %zd\n", + info.pi_diamid, info.pi_diamidlen); + + info.config.pic_flags.sec = PI_SEC_NONE; + info.config.pic_flags.pro4 = PI_P4_SCTP; + + info.config.pic_flags.persist = PI_PRST_NONE; + + CHECK_FCT(fd_peer_add(&info, "", s6a_peer_connected_cb, NULL)); + + if (config_unlock(&mme_config) != 0) { + S6A_ERROR("Failed to unlock configuration\n"); + return -1; + } + + return ret; +} diff --git a/openair-cn/S6A/s6a_subscription_data.c b/openair-cn/S6A/s6a_subscription_data.c new file mode 100644 index 0000000000..5fd0b43d96 --- /dev/null +++ b/openair-cn/S6A/s6a_subscription_data.c @@ -0,0 +1,392 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "common_types.h" +#include "s6a_defs.h" + +#include "assertions.h" + +static inline +int s6a_parse_subscriber_status(struct avp_hdr *hdr_sub_status, + subscriber_status_t *sub_status) +{ + DevCheck(hdr_sub_status->avp_value->u32 < SS_MAX, + hdr_sub_status->avp_value->u32, SS_MAX, 0); + + *sub_status = hdr_sub_status->avp_value->u32; + + return 0; +} + +static inline +int s6a_parse_msisdn(struct avp_hdr *hdr_msisdn, char *msisdn, int *length) +{ + DevCheck(hdr_msisdn->avp_value->os.len <= MSISDN_LENGTH, + hdr_msisdn->avp_value->os.len, MSISDN_LENGTH, 0); + if (hdr_msisdn->avp_value->os.len == 0) + return 0; + *length = sprintf(msisdn, "%*s", (int)hdr_msisdn->avp_value->os.len, + hdr_msisdn->avp_value->os.data); + return 0; +} + +static inline +int s6a_parse_network_access_mode(struct avp_hdr *hdr_network_am, + network_access_mode_t *access_mode) +{ + DevCheck(hdr_network_am->avp_value->u32 < NAM_MAX && + hdr_network_am->avp_value->u32 != NAM_RESERVED, + hdr_network_am->avp_value->u32, NAM_MAX, NAM_RESERVED); + + *access_mode = hdr_network_am->avp_value->u32; + + return 0; +} + +static inline +int s6a_parse_access_restriction_data(struct avp_hdr *hdr_access_restriction, + access_restriction_t *access_restriction) +{ + DevCheck(hdr_access_restriction->avp_value->u32 < ARD_MAX, + hdr_access_restriction->avp_value->u32, ARD_MAX, 0); + *access_restriction = hdr_access_restriction->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_bitrate(struct avp_hdr *hdr_bitrate, bitrate_t *bitrate) +{ + *bitrate = hdr_bitrate->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_ambr(struct avp *avp_ambr, ambr_t *ambr) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_browse(avp_ambr, MSG_BRW_FIRST_CHILD, &avp, NULL)); + if (!avp) { + /* Child avps for ambr are mandatory */ + return -1; + } + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_BANDWIDTH_UL: + CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_ul)); + break; + case AVP_CODE_BANDWIDTH_DL: + CHECK_FCT(s6a_parse_bitrate(hdr, &ambr->br_dl)); + break; + default: + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +static inline +int s6a_parse_all_apn_conf_inc_ind(struct avp_hdr *hdr, all_apn_conf_ind_t *ptr) +{ + DevCheck(hdr->avp_value->u32 < ALL_APN_MAX, + hdr->avp_value->u32, ALL_APN_MAX, 0); + *ptr = hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_pdn_type(struct avp_hdr *hdr, pdn_type_t *pdn_type) +{ + DevCheck(hdr->avp_value->u32 < IP_MAX, + hdr->avp_value->u32, IP_MAX, 0); + *pdn_type = hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_service_selection(struct avp_hdr *hdr_service_selection, + char *service_selection, int *length) +{ + DevCheck(hdr_service_selection->avp_value->os.len <= APN_MAX_LENGTH, + hdr_service_selection->avp_value->os.len, APN_MAX_LENGTH, 0); + *length = sprintf(service_selection, "%*s", + (int)hdr_service_selection->avp_value->os.len, + hdr_service_selection->avp_value->os.data); + return 0; +} + +static inline +int s6a_parse_qci(struct avp_hdr *hdr, qci_t *qci) +{ + DevCheck(hdr->avp_value->u32 < QCI_MAX, + hdr->avp_value->u32, QCI_MAX, 0); + *qci = hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_priority_level(struct avp_hdr *hdr, priority_level_t *priority_level) +{ + DevCheck(hdr->avp_value->u32 <= PRIORITY_LEVEL_MAX && + hdr->avp_value->u32 >= PRIORITY_LEVEL_MIN, hdr->avp_value->u32, + PRIORITY_LEVEL_MAX, PRIORITY_LEVEL_MIN); + *priority_level = (priority_level_t)hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_pre_emp_capability(struct avp_hdr *hdr, pre_emp_capability_t *pre_emp_capability) +{ + DevCheck(hdr->avp_value->u32 < PRE_EMPTION_CAPABILITY_MAX, hdr->avp_value->u32, + PRE_EMPTION_CAPABILITY_MAX, 0); + *pre_emp_capability = hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_pre_emp_vulnerability(struct avp_hdr *hdr, pre_emp_vulnerability_t *pre_emp_vulnerability) +{ + DevCheck(hdr->avp_value->u32 < PRE_EMPTION_VULNERABILITY_MAX, hdr->avp_value->u32, + PRE_EMPTION_VULNERABILITY_MAX, 0); + *pre_emp_vulnerability = hdr->avp_value->u32; + return 0; +} + +static inline +int s6a_parse_allocation_retention_priority(struct avp *avp_arp, + allocation_retention_priority_t *ptr) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + /* If the Pre-emption-Capability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_CAPABILITY_DISABLED (1). + */ + ptr->pre_emp_capability = PRE_EMPTION_CAPABILITY_DISABLED; + + /* If the Pre-emption-Vulnerability AVP is not present in the + * Allocation-Retention-Priority AVP, the default value shall be + * PRE-EMPTION_VULNERABILITY_ENABLED (0). + */ + ptr->pre_emp_vulnerability = PRE_EMPTION_VULNERABILITY_ENABLED; + + CHECK_FCT(fd_msg_browse(avp_arp, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_PRIORITY_LEVEL: + CHECK_FCT(s6a_parse_priority_level(hdr, &ptr->priority_level)); + break; + case AVP_CODE_PRE_EMPTION_CAPABILITY: + CHECK_FCT(s6a_parse_pre_emp_capability(hdr, &ptr->pre_emp_capability)); + break; + case AVP_CODE_PRE_EMPTION_VULNERABILITY: + CHECK_FCT(s6a_parse_pre_emp_vulnerability(hdr, &ptr->pre_emp_vulnerability)); + break; + default: + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +static inline +int s6a_parse_eps_subscribed_qos_profile(struct avp *avp_qos, + eps_subscribed_qos_profile_t *ptr) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_browse(avp_qos, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_QCI: + CHECK_FCT(s6a_parse_qci(hdr, &ptr->qci)); + break; + case AVP_CODE_ALLOCATION_RETENTION_PRIORITY: + CHECK_FCT(s6a_parse_allocation_retention_priority(avp, &ptr->allocation_retention_priority)); + break; + default: + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +static inline +int s6a_parse_ip_address(struct avp_hdr *hdr, ip_address_t *ip_address) +{ + uint16_t ip_type; + + DevCheck(hdr->avp_value->os.len >= 2, hdr->avp_value->os.len, 2, 0); + + ip_type = (hdr->avp_value->os.data[0] << 8) | (hdr->avp_value->os.data[1]); + + if (ip_type == IANA_IPV4) { + /* This is an IPv4 address */ + ip_address->pdn_type = IPv4; + DevCheck(hdr->avp_value->os.len == 6, hdr->avp_value->os.len, 6, ip_type); + memcpy(ip_address->address.ipv4_address, &hdr->avp_value->os.data[2], 4); + } else if (ip_type == IANA_IPV6) { + /* This is an IPv6 address */ + ip_address->pdn_type = IPv6; + DevCheck(hdr->avp_value->os.len == 18, hdr->avp_value->os.len, 18, ip_type); + memcpy(ip_address->address.ipv6_address, &hdr->avp_value->os.data[2], 16); + } else { + /* unhandled case... */ + return -1; + } + return 0; +} + +static inline +int s6a_parse_apn_configuration(struct avp *avp_apn_conf_prof, apn_configuration_t *apn_config) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_CONTEXT_IDENTIFIER: + apn_config->context_identifier = hdr->avp_value->u32; + break; + case AVP_CODE_SERVED_PARTY_IP_ADDRESS: + if (apn_config->nb_ip_address == 2) { + DevMessage("Only two IP addresses can be provided"); + } + CHECK_FCT(s6a_parse_ip_address(hdr, &apn_config->ip_address[apn_config->nb_ip_address])); + apn_config->nb_ip_address++; + break; + case AVP_CODE_PDN_TYPE: + CHECK_FCT(s6a_parse_pdn_type(hdr, &apn_config->pdn_type)); + break; + case AVP_CODE_SERVICE_SELECTION: + CHECK_FCT(s6a_parse_service_selection(hdr, apn_config->service_selection, + &apn_config->service_selection_length)); + break; + case AVP_CODE_EPS_SUBSCRIBED_QOS_PROFILE: + CHECK_FCT(s6a_parse_eps_subscribed_qos_profile(avp, &apn_config->subscribed_qos)); + break; + case AVP_CODE_AMBR: + CHECK_FCT(s6a_parse_ambr(avp, &apn_config->ambr)); + break; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +static inline +int s6a_parse_apn_configuration_profile(struct avp *avp_apn_conf_prof, + apn_config_profile_t *apn_config_profile) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + switch(hdr->avp_code) { + case AVP_CODE_CONTEXT_IDENTIFIER: + apn_config_profile->context_identifier = hdr->avp_value->u32; + break; + case AVP_CODE_ALL_APN_CONFIG_INC_IND: + CHECK_FCT(s6a_parse_all_apn_conf_inc_ind(hdr, &apn_config_profile->all_apn_conf_ind)); + break; + case AVP_CODE_APN_CONFIGURATION: { + DevCheck(apn_config_profile->nb_apns < MAX_APN_PER_UE, + apn_config_profile->nb_apns, MAX_APN_PER_UE, 0); + CHECK_FCT(s6a_parse_apn_configuration( + avp, &apn_config_profile->apn_configuration[apn_config_profile->nb_apns])); + apn_config_profile->nb_apns++; + } break; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} + +int s6a_parse_subscription_data(struct avp *avp_subscription_data, + subscription_data_t *subscription_data) +{ + struct avp *avp = NULL; + struct avp_hdr *hdr; + + CHECK_FCT(fd_msg_browse(avp_subscription_data, MSG_BRW_FIRST_CHILD, &avp, NULL)); + while(avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + + switch(hdr->avp_code) { + case AVP_CODE_SUBSCRIBER_STATUS: + CHECK_FCT(s6a_parse_subscriber_status(hdr, &subscription_data->subscriber_status)); + break; + case AVP_CODE_MSISDN: + CHECK_FCT(s6a_parse_msisdn(hdr, subscription_data->msisdn, + &subscription_data->msisdn_length)); + break; + case AVP_CODE_NETWORK_ACCESS_MODE: + CHECK_FCT(s6a_parse_network_access_mode(hdr, &subscription_data->access_mode)); + break; + case AVP_CODE_ACCESS_RESTRICTION_DATA: + CHECK_FCT(s6a_parse_access_restriction_data(hdr, &subscription_data->access_restriction)); + break; + case AVP_CODE_AMBR: + CHECK_FCT(s6a_parse_ambr(avp, &subscription_data->subscribed_ambr)); + break; + case AVP_CODE_APN_CONFIGURATION_PROFILE: + CHECK_FCT(s6a_parse_apn_configuration_profile(avp, &subscription_data->apn_config_profile)); + break; + case AVP_CODE_SUBSCRIBED_PERIODIC_RAU_TAU_TIMER: + subscription_data->rau_tau_timer = hdr->avp_value->u32; + break; + default: + return -1; + } + /* Go to next AVP in the grouped AVP */ + CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL)); + } + return 0; +} diff --git a/openair-cn/S6A/s6a_task.c b/openair-cn/S6A/s6a_task.c new file mode 100644 index 0000000000..36fc768e7b --- /dev/null +++ b/openair-cn/S6A/s6a_task.c @@ -0,0 +1,166 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <freeDiameter/freeDiameter-host.h> +#include <freeDiameter/libfdcore.h> + +#include "intertask_interface.h" +#include "s6a_defs.h" +#include "s6a_messages.h" + +#include "assertions.h" + +#if defined(DISABLE_USE_HSS) +# error "Disabling HSS support is currently not supported \ + Reconfigure with --enable-hss option to disable this error" +#endif + +static int gnutls_debug = 0; +struct session_handler *ts_sess_hdl; + +s6a_fd_cnf_t s6a_fd_cnf; + +void *s6a_thread(void *args); +static void fd_gnutls_debug(int level, const char *str); + +static void fd_gnutls_debug(int level, const char *str) +{ + S6A_DEBUG("[GTLS] %s", str); +} + +void *s6a_thread(void *args) +{ + intertask_interface_mark_task_ready(TASK_S6A); + + while(1) { + MessageDef *received_message_p = NULL; + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + receive_msg(TASK_S6A, &received_message_p); + DevAssert(received_message_p != NULL); + switch(received_message_p->header.messageId) { + case S6A_UPDATE_LOCATION_REQ: { + s6a_generate_update_location(&received_message_p->msg.s6a_update_location_req); + } break; + case S6A_AUTH_INFO_REQ: { + s6a_generate_authentication_info_req(&received_message_p->msg.s6a_auth_info_req); + } break; + default: { + S6A_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int s6a_init(const mme_config_t *mme_config_p) +{ + int ret; + + S6A_DEBUG("Initializing S6a interface\n"); + + memset(&s6a_fd_cnf, 0, sizeof(s6a_fd_cnf_t)); + + if (strcmp(fd_core_version(), FREE_DIAMETER_MINIMUM_VERSION) != 0) { + S6A_ERROR("Freediameter version %s fount, expecting %s\n", fd_core_version(), + FREE_DIAMETER_MINIMUM_VERSION); + return -1; + } else { + S6A_DEBUG("Freediameter version %s\n", fd_core_version()); + } + + /* Initializing freeDiameter core */ + ret = fd_core_initialize(); + if (ret != 0) { + S6A_ERROR("An error occurred during freeDiameter core library initialization\n"); + return ret; + } + + /* Set gnutls debug level ? */ + if (gnutls_debug) { + gnutls_global_set_log_function((gnutls_log_func)fd_gnutls_debug); + gnutls_global_set_log_level (gnutls_debug); + S6A_DEBUG("Enabled GNUTLS debug at level %d", gnutls_debug); + } + + /* Starting freeDiameter core */ + ret = fd_core_start(); + if (ret != 0) { + S6A_ERROR("An error occurred during freeDiameter core library start\n"); + return ret; + } + + S6A_DEBUG("Default ext path: %s\n", DEFAULT_EXTENSIONS_PATH); + + ret = fd_core_parseconf(mme_config_p->s6a_config.conf_file); + if (ret != 0) { + S6A_ERROR("An error occurred during fd_core_parseconf.\n"); + return ret; + } + + ret = fd_core_waitstartcomplete(); + if (ret != 0) { + S6A_ERROR("An error occurred during fd_core_waitstartcomplete.\n"); + return ret; + } + + ret = s6a_fd_init_dict_objs(); + if (ret != 0) { + S6A_ERROR("An error occurred during s6a_fd_init_dict_objs.\n"); + return ret; + } + + /* Trying to connect to peers */ + CHECK_FCT(s6a_fd_new_peer()); + + if (intertask_interface_create_task(TASK_S6A, &s6a_thread, NULL) < 0) { + S6A_ERROR("s6a create task\n"); + return -1; + } + S6A_DEBUG("Initializing S6a interface: DONE\n"); + + return 0; +} diff --git a/openair-cn/S6A/s6a_up_loc.c b/openair-cn/S6A/s6a_up_loc.c new file mode 100644 index 0000000000..d5023d5865 --- /dev/null +++ b/openair-cn/S6A/s6a_up_loc.c @@ -0,0 +1,284 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdint.h> + +#include "mme_config.h" + +#include "assertions.h" +#include "conversions.h" + +#include "intertask_interface.h" +#include "s6a_defs.h" +#include "s6a_messages.h" + +int s6a_ula_cb(struct msg **msg, struct avp *paramavp, + struct session *sess, void *opaque, + enum disp_action *act) +{ + struct msg *ans; + struct msg *qry; + struct avp *avp; + struct avp_hdr *hdr; + + MessageDef *message_p; + s6a_update_location_ans_t *s6a_update_location_ans_p; + + DevAssert(msg != NULL); + + ans = *msg; + /* Retrieve the original query associated with the asnwer */ + CHECK_FCT(fd_msg_answ_getq(ans, &qry)); + + DevAssert(qry != NULL); + + message_p = alloc_new_message(TASK_S6A, S6A_UPDATE_LOCATION_ANS); + + s6a_update_location_ans_p = &message_p->msg.s6a_update_location_ans; + + CHECK_FCT(fd_msg_search_avp(qry, s6a_fd_cnf.dataobj_s6a_user_name, &avp)); + if (avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + memcpy(s6a_update_location_ans_p->imsi, hdr->avp_value->os.data, hdr->avp_value->os.len); + s6a_update_location_ans_p->imsi[hdr->avp_value->os.len] = '\0'; + s6a_update_location_ans_p->imsi_length = hdr->avp_value->os.len; + S6A_DEBUG("Received s6a ula for imsi=%*s\n", + (int)hdr->avp_value->os.len, + hdr->avp_value->os.data); + } else { + DevMessage("Query has been freed before we received the answer\n"); + } + + /* Retrieve the result-code */ + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_result_code, &avp)); + if (avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + + s6a_update_location_ans_p->result.present = S6A_RESULT_BASE; + s6a_update_location_ans_p->result.choice.base = hdr->avp_value->u32; + + if (hdr->avp_value->u32 != ER_DIAMETER_SUCCESS) { + S6A_ERROR("Got error %u:%s\n", hdr->avp_value->u32, + retcode_2_string(hdr->avp_value->u32)); + goto err; + } + } else { + /* The result-code is not present, may be it is an experimental result + * avp indicating a 3GPP specific failure. + */ + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_experimental_result, &avp)); + if (avp) { + /* The procedure has failed within the HSS. + * NOTE: contrary to result-code, the experimental-result is a grouped + * AVP and requires parsing its childs to get the code back. + */ + s6a_update_location_ans_p->result.present = S6A_RESULT_EXPERIMENTAL; + s6a_parse_experimental_result(avp, &s6a_update_location_ans_p->result.choice.experimental); + + goto err; + } else { + /* Neither result-code nor experimental-result is present -> + * totally incorrect behaviour here. + */ + S6A_ERROR("Experimental-Result and Result-Code are absent: " + "This is not a correct behaviour\n"); + goto err; + } + } + + /* Retrieving the ULA flags */ + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_ula_flags, &avp)); + if (avp) { + CHECK_FCT(fd_msg_avp_hdr(avp, &hdr)); + /* This bit, when set, indicates that the HSS stores SGSN number + * and MME number in separate memory. A Rel-8 HSS shall set + * the bit. + */ + if (!FLAG_IS_SET(hdr->avp_value->u32, ULA_SEPARATION_IND)) { + S6A_ERROR("ULA-Flags does not indicate the HSS is post Rel.8: " + "This behaviour is not compliant\n"); + goto err; + } + } else { + /* ULA-Flags is absent while the error code indicates DIAMETER_SUCCESS: + * this is not a compliant behaviour... + * TODO: handle this case. + */ + S6A_ERROR("ULA-Flags AVP is absent while result code indicates " + "DIAMETER_SUCCESS\n"); + goto err; + } + + CHECK_FCT(fd_msg_search_avp(ans, s6a_fd_cnf.dataobj_s6a_subscription_data, &avp)); + if (avp) { + CHECK_FCT(s6a_parse_subscription_data(avp, &s6a_update_location_ans_p->subscription_data)); + +#if defined(DISABLE_USE_NAS) + +#else + DevParam(0, 0, 0); +#endif + } + +err: + + ans = NULL; + + send_msg_to_task(TASK_MME_APP, INSTANCE_DEFAULT, message_p); + + S6A_DEBUG("Sending S6A_UPDATE_LOCATION_ANS to task MME_APP\n"); + + return 0; +} + +int s6a_generate_update_location(s6a_update_location_req_t *ulr_p) +{ + struct avp *avp; + struct msg *msg; + struct session *sess; + + union avp_value value; + + DevAssert(ulr_p != NULL); + + /* Create the new update location request message */ + CHECK_FCT(fd_msg_new(s6a_fd_cnf.dataobj_s6a_ulr, 0, &msg)); + + /* Create a new session */ + CHECK_FCT(fd_sess_new(&sess, fd_g_config->cnf_diamid, + fd_g_config->cnf_diamid_len, (os0_t)"apps6a", 6)); + { + os0_t sid; + size_t sidlen; + CHECK_FCT(fd_sess_getsid(sess, &sid, &sidlen)); + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_session_id, 0, &avp)); + value.os.data = sid; + value.os.len = sidlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_FIRST_CHILD, avp)); + } + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_auth_session_state, 0, &avp)); + /* No State maintained */ + value.i32 = 1; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + /* Add Origin_Host & Origin_Realm */ + CHECK_FCT(fd_msg_add_origin(msg, 0)); + + config_read_lock(&mme_config); + + /* Destination Host */ + { + char host[40] = "hss."; + size_t hostlen; + + strcat(host, mme_config.realm); + + hostlen = strlen(host); + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_destination_host, 0, &avp)); + value.os.data = (unsigned char *)host; + value.os.len = hostlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + /* Destination_Realm */ + { + char *realm = mme_config.realm; + size_t realmlen = strlen(realm); + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_destination_realm, 0, &avp)); + value.os.data = (unsigned char *)realm; + value.os.len = realmlen; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + + config_unlock(&mme_config); + + /* Adding the User-Name (IMSI) */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_user_name, 0, &avp)); + value.os.data = (unsigned char *)ulr_p->imsi; + value.os.len = strlen(ulr_p->imsi); + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + /* Adding the visited plmn id */ + { + uint8_t plmn[3]; + + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_visited_plmn_id, 0, &avp)); + + PLMN_T_TO_TBCD(ulr_p->visited_plmn, plmn); + + printf("PLMN: %3s\n", plmn); + + value.os.data = plmn; + value.os.len = 3; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + } + + /* Adding the RAT-Type */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_rat_type, 0, &avp)); + DevCheck(ulr_p->rat_type == RAT_EUTRAN, ulr_p->rat_type, 0, 0); + value.u32 = ulr_p->rat_type; + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + /* Adding ULR-Flags */ + CHECK_FCT(fd_msg_avp_new(s6a_fd_cnf.dataobj_s6a_ulr_flags, 0, &avp)); + value.u32 = 0; + + /* Identify the ULR as coming from S6A interface (i.e. from MME) */ + FLAGS_SET(value.u32, ULR_S6A_S6D_INDICATOR); + + /* Set the ulr-flags as indicated by upper layer */ + if (ulr_p->skip_subsriber_data) { + FLAGS_SET(value.u32, ULR_SKIP_SUBSCRIBER_DATA); + } + if (ulr_p->initial_attach) { + FLAGS_SET(value.u32, ULR_INITIAL_ATTACH_IND); + } + CHECK_FCT(fd_msg_avp_setvalue(avp, &value)); + CHECK_FCT(fd_msg_avp_add(msg, MSG_BRW_LAST_CHILD, avp)); + + CHECK_FCT(fd_msg_send(&msg, NULL, NULL)); + + S6A_DEBUG("Sending s6a ulr for imsi=%s\n", ulr_p->imsi); + + return 0; +} diff --git a/openair-cn/SCRIPTS/install_openvswitch1.9.0.bash b/openair-cn/SCRIPTS/install_openvswitch1.9.0.bash new file mode 100755 index 0000000000..cf9fb8bf22 --- /dev/null +++ b/openair-cn/SCRIPTS/install_openvswitch1.9.0.bash @@ -0,0 +1,55 @@ +#!/bin/bash +# Tested on ubuntu 12.04 with updates on 05 april 2013 + +# Make sure only root can run our script +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit 1 +fi + +apt-get install iproute pkg-config python-twisted-conch python-anyjson \ +python-pyside python3-pyside python-zope python-qt4 libssl-dev uml-utilities \ +linux-headers-`uname -r` vlan -y + +rmmod bridge +cd /usr/local/src/ +wget http://openvswitch.org/releases/openvswitch-1.9.0.tar.gz +tar -xzf openvswitch-1.9.0.tar.gz +cd openvswitch-1.9.0 +./boot.sh +./configure --with-linux=/lib/modules/`uname -r`/build --disable-ssl +make +make install +make modules_install + +insmod /lib/modules/`uname -r`/kernel/net/openvswitch/openvswitch.ko + +# Initialize the configuration database using ovsdb-tool, e.g.: + +mkdir -p /usr/local/etc/openvswitch +ovsdb-tool create /usr/local/etc/openvswitch/conf.db vswitchd/vswitch.ovsschema + +#======= +# Startup +#======= +# Before starting ovs-vswitchd itself, you need to start its +# configuration database, ovsdb-server. Each machine on which Open +# vSwitch is installed should run its own copy of ovsdb-server. +# Configure it to use the database you created during step 7 of +# installation, above, to listen on a Unix domain socket, to connect to +# any managers specified in the database itself, and to use the SSL +# configuration in the database: + +ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,manager_options --pidfile --detach + +# Then initialize the database using ovs-vsctl. This is only +# necessary the first time after you create the database with +# ovsdb-tool (but running it at any time is harmless): + +ovs-vsctl --no-wait init + +# Then start the main Open vSwitch daemon, telling it to +# connect to the same Unix domain socket: + +ovs-vswitchd --pidfile --detach + diff --git a/openair-cn/SCRIPTS/start_enb.bash b/openair-cn/SCRIPTS/start_enb.bash new file mode 100755 index 0000000000..b39b3a9252 --- /dev/null +++ b/openair-cn/SCRIPTS/start_enb.bash @@ -0,0 +1,320 @@ +#!/bin/bash +# start MME+S/P-GW with openvswitch setting + + +# +-----------+ +------+ +-----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME | +# | |cpenb0+------------------+cpmme0| | +# | +------+ |bridge| +------+ | +# | |upenb0+-------+ | | | +# +-----------+------+ | | | +-----------+ +# +---|--+ | +# | +-----------+ +# | | S+P-GW | +# | VLAN2 +------+ +-------+ +# +----------+upsgw0| |eth0 +---Internet access +# +------+ +-------+ +# | | +# +-----------+ +# + + +BRIDGE="vswitch" + +########################################################### +IPTABLES=/sbin/iptables +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +declare -x OPENAIR_DIR="" +declare -x OPENAIR1_DIR="" +declare -x OPENAIR2_DIR="" +declare -x OPENAIR3_DIR="" +declare -x OPENAIR_TARGETS="" +########################################################### +cidr2mask() { + local i mask="" + local full_octets=$(($1/8)) + local partial_octet=$(($1%8)) + + for ((i=0;i<4;i+=1)); do + if [ $i -lt $full_octets ]; then + mask+=255 + elif [ $i -eq $full_octets ]; then + mask+=$((256 - 2**(8-$partial_octet))) + else + mask+=0 + fi + test $i -lt 3 && mask+=. + done + + echo $mask +} + + +black='\E[30m' +red='\E[31m' +green='\E[32m' +yellow='\E[33m' +blue='\E[34m' +magenta='\E[35m' +cyan='\E[36m' +white='\E[37m' + +ROOT_UID=0 +E_NOTROOT=67 + +trim () +{ + echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' +} + + +cecho() # Color-echo +# arg1 = message +# arg2 = color +{ + local default_msg="No Message." + message=${1:-$default_msg} + color=${2:-$black} + echo -e "$color" + echo -n "$message" + tput sgr0 + echo + return +} + +echo_error() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $red +} + +echo_warning() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $yellow +} + +echo_success() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $green +} + +bash_exec() { + output=$($1 2>&1) + result=$? + if [ $result -eq 0 ] + then + echo_success "$1" + else + echo_error "$1: $output" + fi +} + +set_openair() { + path=`pwd` + declare -i length_path + declare -i index + length_path=${#path} + + index=`echo $path | grep -b -o 'targets' | cut -d: -f1` + #echo ${path%$token*} + if [[ $index -lt $length_path && index -gt 0 ]] + then + declare -x OPENAIR_DIR + index=`expr $index - 1` + openair_path=`echo $path | cut -c1-$index` + #openair_path=`echo ${path:0:$index}` + export OPENAIR_DIR=$openair_path + export OPENAIR1_DIR=$openair_path/openair1 + export OPENAIR2_DIR=$openair_path/openair2 + export OPENAIR3_DIR=$openair_path/openair3 + export OPENAIR_TARGETS=$openair_path/targets + return 0 + fi + index=`echo $path | grep -b -o 'openair3' | cut -d: -f1` + if [[ $index -lt $length_path && index -gt 0 ]] + then + declare -x OPENAIR_DIR + index=`expr $index - 1` + openair_path=`echo $path | cut -c1-$index` + #openair_path=`echo ${path:0:$index}` + export OPENAIR_DIR=$openair_path + export OPENAIR1_DIR=$openair_path/openair1 + export OPENAIR2_DIR=$openair_path/openair2 + export OPENAIR3_DIR=$openair_path/openair3 + export OPENAIR_TARGETS=$openair_path/targets + return 0 + fi + return -1 +} + +wait_process_started () { + if [ -z "$1" ] + then + echo_error "WAITING FOR PROCESS START: NO PROCESS" + return 1 + fi + ps -C $1 > /dev/null 2>&1 + while [ $? -ne 0 ]; do + echo_warning "WAITING FOR $1 START" + sleep 2 + ps -C $1 > /dev/null 2>&1 + done + echo_success "PROCESS $1 STARTED" + return 0 +} + +is_process_started () { + if [ -z "$1" ] + then + echo_error "WAITING FOR PROCESS START: NO PROCESS" + return 1 + fi + ps -C $1 > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo_success "PROCESS $1 NOT STARTED" + return 1 + fi + echo_success "PROCESS $1 STARTED" + return 0 +} + +assert() { + # If condition false + # exit from script with error message + E_PARAM_ERR=98 + E_PARAM_FAILED=99 + + if [ -z "$2" ] # Not enought parameters passed. + then + return $E_PARAM_ERR + fi + + lineno=$2 + if [ ! $1 ] + then + echo "Assertion failed: \"$1\"" + echo "File \"$0\", line $lineno" + exit $E_ASSERT_FAILED + fi +} + +start_openswitch_daemon() { + rmmod -s bridge + is_process_started "ovsdb-server" + if [ $? -ne 0 ] + then + ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,manager_options --pidfile --detach + wait_process_started "ovsdb-server" + fi + # To be done after installation + # ovs-vsctl --no-wait init + is_process_started "ovs-vswitchd" + if [ $? -ne 0 ] + then + ovs-vswitchd --pidfile --detach + wait_process_started "ovs-vswitchd" + fi +} + +set_openair +cecho "OPENAIR_DIR = $OPENAIR_DIR" $green +cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green +cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green +cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green +cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green + + + + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_default.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + + +################################################## +# LAUNCH eNB + UE executable +################################################## +# ONLY oai interface for UE +declare MAKE_IP_DRIVER_TARGET="ue_ip.ko" +declare MAKE_LTE_ACCESS_STRATUM_TARGET="oaisim USE_MME=R10" +declare IP_DRIVER_NAME="ue_ip" +declare LTEIF="oip1" +UE_IPv4="10.0.0.8" +UE_IPv6="2001:1::8" +UE_IPv6_CIDR=$UE_IPv6"/64" +UE_IPv4_CIDR=$UE_IPv4"/24" +#------------------------------------------------ +declare -a NAS_IMEI=( 3 9 1 8 3 6 6 2 0 0 0 0 0 0 ) + + + +echo "Bringup UE interface" +bash_exec "rmmod $IP_DRIVER_NAME" +cecho "make $MAKE_IP_DRIVER_TARGET $MAKE_LTE_ACCESS_STRATUM_TARGET ....." $green +# bash_exec "make --directory=$OPENAIR_TARGETS/SIMU/EXAMPLES/VIRT_EMUL_1eNB $MAKE_LTE_ACCESS_STRATUM_TARGET " +bash_exec "make --directory=$OPENAIR2_DIR $MAKE_IP_DRIVER_TARGET " +#bash_exec "make --directory=$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL " + +#bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/LITE/$IP_DRIVER_NAME.ko oai_nw_drv_IMEI=${NAS_IMEI[0]},${NAS_IMEI[1]},${NAS_IMEI[2]},${NAS_IMEI[3]},${NAS_IMEI[4]},${NAS_IMEI[5]},${NAS_IMEI[6]},${NAS_IMEI[7]},${NAS_IMEI[8]},${NAS_IMEI[9]},${NAS_IMEI[10]},${NAS_IMEI[11]},${NAS_IMEI[12]},${NAS_IMEI[13]}" +bash_exec "insmod $OPENAIR2_DIR/NAS/DRIVER/UE_LTE/$IP_DRIVER_NAME.ko" + +bash_exec "ip route flush cache" + +#bash_exec "ip link set $LTEIF broadcast ff:ff:ff:ff:ff:ff" +bash_exec "ip link set $LTEIF up" +sleep 1 +bash_exec "ip addr add dev $LTEIF $UE_IPv4_CIDR" +bash_exec "ip addr add dev $LTEIF $UE_IPv6_CIDR" + +# -a -> Add RB +# -d -> Delete RB +# -cxx -> lcr +# -ixx -> instance +# -zxx -> dscp +# -fxxx -> classref (uid of a classifier entry) if fn is used , fn is used for send classifier and n+1 for receive classifier +# -sxxx -> source ipv4 address +# -txxx -> destination ipv4 address +# -x -> source ipv6 address +# -y -> destination ipv6 address +# -r -> radio bearer id +#bash_exec "$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/rb_tool -a -c0 -f0 -i1 -z0 -x 0::0/128 -y 0::0/128 -r 5" +#bash_exec "$OPENAIR2_DIR/NAS/DRIVER/LITE/RB_TOOL/rb_tool -a -c0 -f2 -i1 -z64 -s 0.0.0.0/32 -t 0.0.0.0/32 -r 5" +sleep 1 + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO + + +bash_exec "ip route flush cache" + +# please add table 200 lte in/etc/iproute2/rt_tables +ip rule add fwmark 5 table lte +ip route add default dev $LTEIF table lte + +#gdb --args $OPENAIR_TARGETS/SIMU/USER/oaisim -a -u1 -l7 --mme_ip_address $MME_IP_ADDRESS_FOR_S1_MME --s1c_ip_address $ENB_IP_ADDRESS_FOR_S1_MME --s1u_ip_address $ENB_IP_ADDRESS_FOR_S1U +echo $OPENAIR_TARGETS/SIMU/USER/oaisim -a -u1 -l7 --mme_ip_address $MME_IP_ADDRESS_FOR_S1_MME --s1c_ip_address $ENB_IP_ADDRESS_FOR_S1_MME --s1u_ip_address $ENB_IP_ADDRESS_FOR_S1U + + diff --git a/openair-cn/SCRIPTS/start_lte-epc-ovs.bash b/openair-cn/SCRIPTS/start_lte-epc-ovs.bash new file mode 100755 index 0000000000..cd069b060f --- /dev/null +++ b/openair-cn/SCRIPTS/start_lte-epc-ovs.bash @@ -0,0 +1,297 @@ +#!/bin/bash +# start MME+S/P-GW with openvswitch setting + + hss.eur +# +-----------+ +------+ +-----------+ v +----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME +----+ +---+ HSS | +# | |cpenb0+------------------+cpmme0| | +------+ | | +# | +------+ |bridge| +------+ +----+ +---+ | +# | |upenb0+-------+ | | | +----------+ +# +-----------+------+ | | | +-----------+ +# +---|--+ | router.eur +# | +-----------+ | +--------------+ +# | | S+P-GW | v | ROUTER | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |sgi +-...-+ | | +---...Internet +# +------+ +-------+ +----+ +----+ +# | | 11 VLANS | | +# +-----------+ ids=[5..15] +--------------+ +# + + +BRIDGE="vswitch" + +########################################################### +IPTABLES=/sbin/iptables +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +declare -x OPENAIR_DIR="" +declare -x OPENAIR1_DIR="" +declare -x OPENAIR2_DIR="" +declare -x OPENAIR3_DIR="" +declare -x OPENAIR_TARGETS="" +########################################################### + +set_openair +cecho "OPENAIR_DIR = $OPENAIR_DIR" $green +cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green +cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green +cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green +cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green + +cat $OPENAIR3_DIR/OPENAIRMME/objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_NETFILTER_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_NETFILTER_FOR_SGI=0 +else + export ENABLE_USE_NETFILTER_FOR_SGI=1 +fi + +cat $OPENAIR3_DIR/OPENAIRMME/objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_RAW_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_RAW_FOR_SGI=0 +else + export ENABLE_USE_RAW_FOR_SGI=1 +fi + +pkill oaisim_mme + + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +ping -c 1 hss.eur || { echo "hss.eur does not respond to ping" >&2 ; exit ; } +ping -c 1 router.eur || { echo "router.eur does not respond to ping" >&2 ; exit ; } +IP_ROUTER=`python -c 'import socket; print socket.gethostbyname("router.eur")'` +export MAC_ROUTER=`ip neigh show | grep $IP_ROUTER | cut -d ' ' -f5 | tr -d ':'` + +echo_success "ROUTER MAC ADDRESS= $MAC_ROUTER" +bash_exec "modprobe tun" +bash_exec "modprobe ip_tables" +bash_exec "modprobe iptable_nat" +bash_exec "modprobe x_tables" + +bash_exec "$IPTABLES -P INPUT ACCEPT" +bash_exec "$IPTABLES -F INPUT" +bash_exec "$IPTABLES -P OUTPUT ACCEPT" +bash_exec "$IPTABLES -F OUTPUT" +bash_exec "$IPTABLES -P FORWARD ACCEPT" +bash_exec "$IPTABLES -F FORWARD" +bash_exec "$IPTABLES -t raw -F" +bash_exec "$IPTABLES -t nat -F" +bash_exec "$IPTABLES -t mangle -F" +bash_exec "$IPTABLES -t filter -F" + +bash_exec "ip route flush cache" + +echo " Disabling forwarding" +bash_exec "sysctl -w net.ipv4.ip_forward=0" +assert " `sysctl -n net.ipv4.ip_forward` -eq 0" $LINENO + +echo " Enabling DynamicAddr.." +bash_exec "sysctl -w net.ipv4.ip_dynaddr=1" +assert " `sysctl -n net.ipv4.ip_dynaddr` -eq 1" $LINENO + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO + + +start_openswitch_daemon +# REMINDER: +# +-----------+ +------+ +-----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME | +# | |cpenb0+------------------+cpmme0| | +# | +------+ |bridge| +------+ | +# | |upenb0+-------+ | | | +# +-----------+------+ | | | +-----------+ +# +---|--+ | +# | +-----------+ +# | | S+P-GW | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |pgwsgi0+---+br2 +----+eth0| +# +------+ +-------+ +----+ +----+ +# | | +# +-----------+ +# +################################################## +# del bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -d $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" +bash_exec "ovs-vsctl del-br $BRIDGE" + +################################################## +# build bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -t $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" + +bash_exec "ovs-vsctl add-br $BRIDGE" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $MME_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1U tag=2" +bash_exec "ovs-vsctl add-port $BRIDGE $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP tag=2" + +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME $MME_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $MME_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP $SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP netmask `cidr2mask $SGW_IP_NETMASK_FOR_S1U_S12_S4_UP` promisc up" + +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME $ENB_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U $ENB_IP_ADDRESS_FOR_S1U netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1U` promisc up" + +################################################## +# del bridge between SPGW and Internet +################################################## +#bash_exec "tunctl -d $PGW_INTERFACE_NAME_FOR_SGI" +#bash_exec "ovs-vsctl del-br $SGI_BRIDGE" + +################################################## +# build bridge between SPGW and Internet +################################################## + +# # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` +# if [ $IP_ADDR ]; then +# bash_exec "ip -4 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# +# # remove all ipv6 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR="not empty" +# until [ "$IP_ADDR"x == "x" ]; do +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | grep 'inet6' | head -1 | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' | cut -d ' ' -f3` +# if [ $IP_ADDR ]; then +# bash_exec "ip -6 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# done + +if [ $ENABLE_USE_NETFILTER_FOR_SGI -eq 1 ]; then + + bash_exec "modprobe nf_conntrack" + bash_exec "modprobe nf_conntrack_ftp" + + ###################################################### + # PREROUTING + ###################################################### + # We restore the mark following the CONNMARK mark. In fact, it does a simple MARK=CONNMARK + # where MARK is the standard mark (usable by tc) + # In French: Cette option de cible restaure le paquet marqué dans la marque de connexion + # comme défini par CONNMARK. Un masque peut aussi être défini par l'option --mask. + # Si une option mask est placée, seules les options masquées seront placées. + # Notez que cette option de cible n'est valide que dans la table mangle. + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --restore-mark" + + # TEST bash_exec "$IPTABLES -t mangle -A PREROUTING -m mark --mark 0 -i $PGW_INTERFACE_NAME_FOR_SGI -j MARK --set-mark 15" + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of POSTROUTING --restore-mark). + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --save-mark" + + + ###################################################### + # POSTROUTING + ###################################################### + + # MARK=CONNMARK + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -j CONNMARK --restore-mark" + # If we’ve got a mark no need to get further[ + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -m mark ! --mark 0 -j ACCEPT" + + #bash_exec "iptables -A POSTROUTING -p tcp --dport 21 -t mangle -j MARK --set-mark 1" + #bash_exec "iptables -A POSTROUTING -p tcp --dport 80 -t mangle -j MARK --set-mark 2" + + # We set the mark of the initial packet as value of the conntrack mark for all the packets + # of the connection. This mark will be restore for the other packets by the first rule + # of POSTROUTING (–restore-mark). + bash_exec "iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark" + + bash_exec "iptables -A PREROUTING -t mangle -j CONNMARK --restore-mark" + + # We restore the mark following the CONNMARK mark. + # In fact, it does a simple MARK=CONNMARK where MARK is the standard mark (usable by tc) + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j CONNMARK --restore-mark" + + # If we’ve got a mark no need to get further[1] + #TEST bash_exec "$IPTABLES -A OUTPUT -t mangle -p icmp -j MARK --set-mark 14" + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j ACCEPT" + + + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of OUTPUT (–restore-mark). + #bash_exec "$IPTABLES -A OUTPUT -t mangle -j CONNMARK --save-mark" + + + + + ###################################################### + # NETFILTER QUEUE + ###################################################### + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 5 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 6 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 7 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 8 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 9 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 10 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 11 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 12 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 13 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 14 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 15 -j NFQUEUE --queue-num 1" + + #echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables #To disable Iptables in the bridge. + #Raw table: Some years ago appeared a new tables in Iptables. + #This table can be used to avoid packets (connection really) to enter the NAT table: + # iptables -t raw -I PREROUTING -i BRIDGE -s x.x.x.x -j NOTRACK. + + + + + #bash_exec "$IPTABLES -t nat -A POSTROUTING -o $PGW_INTERFACE_NAME_FOR_SGI -j SNAT --to-source $PGW_IP_ADDR_FOR_SGI" +else + # # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI + #IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` + + #NETWORK=`echo $IP_ADDR | cut -d . -f 1,2,3` + + bash_exec "modprobe 8021q" + + for i in 5 6 7 8 9 10 11 12 13 14 15 + do + # create vlan interface + bash_exec "vconfig rem $PGW_INTERFACE_NAME_FOR_SGI.$i" + sync + bash_exec "vconfig add $PGW_INTERFACE_NAME_FOR_SGI $i" + sync + # configure vlan interface + #CIDR=$NETWORK'.'$i'/24' + base=200 + NET=$(( $i + $base )) + CIDR='10.0.'$NET'.2/8' + bash_exec "ip -4 addr add $CIDR dev $PGW_INTERFACE_NAME_FOR_SGI.$i" + done +fi + + +bash_exec "ip link set $PGW_INTERFACE_NAME_FOR_SGI promisc on" +##################################################.. + +# LAUNCH MME + S+P-GW executable +################################################## + +gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf +wait_process_started "oai_epc" diff --git a/openair-cn/SCRIPTS/start_lte-epc.bash b/openair-cn/SCRIPTS/start_lte-epc.bash new file mode 100755 index 0000000000..3c4e6518a1 --- /dev/null +++ b/openair-cn/SCRIPTS/start_lte-epc.bash @@ -0,0 +1,324 @@ +#!/bin/bash +# start MME+S/P-GW with openvswitch setting + +# hss.eur +# +-----------+ +------+ +-----------+ v +----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME +----+ +---+ HSS | +# | |cpenb0+------------------+cpmme0| | +------+ | | +# | +------+ |bridge| +------+ +----+ +---+ | +# | |upenb0+-------+ | | | +----------+ +# +-----------+------+ | | | +-----------+ +# +---|--+ | router.eur +# | +-----------+ | +--------------+ +# | | S+P-GW | v | ROUTER | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |sgi +-...-+ | | +---...Internet +# +------+ +-------+ +----+ +----+ +# | | 11 VLANS | | +# +-----------+ ids=[5..15] +--------------+ +# + + +BRIDGE="vswitch" +IPTABLES=/sbin/iptables + +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash + +cleanvlan() { + echo "Caught a signal -> Exiting" + + bash_exec "ovs-vsctl del-br $BRIDGE" + for i in 5 6 7 8 9 10 11 12 13 14 15 + do + # create vlan interface + bash_exec "vconfig rem $PGW_INTERFACE_NAME_FOR_SGI.$i" + sync + done + + pkill oai_epc + exit 0 +} + +########################################################### + +declare -x OPENAIR_DIR="" +declare -x OPENAIR1_DIR="" +declare -x OPENAIR2_DIR="" +declare -x OPENAIR3_DIR="" +declare -x OPENAIR_TARGETS="" +########################################################### + +set_openair +cecho "OPENAIR_DIR = $OPENAIR_DIR" $green +cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green +cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green +cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green +cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green + +check_for_root_rights +check_for_epc_executable +check_enb_config +check_epc_config + +cat $OPENAIR3_DIR/OPENAIRMME/objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_NETFILTER_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_NETFILTER_FOR_SGI=0 +else + export ENABLE_USE_NETFILTER_FOR_SGI=1 +fi + +cat $OPENAIR3_DIR/OPENAIRMME/objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_RAW_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_RAW_FOR_SGI=0 +else + export ENABLE_USE_RAW_FOR_SGI=1 +fi + +pkill oaisim_mme +pkill oai_epc +pkill oai_sgw + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +ping -c 1 hss.eur || { echo "hss.eur does not respond to ping" >&2 ; exit ; } +ping -c 1 router.eur || { echo "router.eur does not respond to ping" >&2 ; exit ; } + +IP_ROUTER=`python -c 'import socket; print socket.gethostbyname("router.eur")'` +export MAC_ROUTER=`ip neigh show | grep $IP_ROUTER | cut -d ' ' -f5 | tr -d ':'` + +trap cleanvlan SIGINT SIGKILL SIGTERM + +echo_success "ROUTER MAC ADDRESS= $MAC_ROUTER" +bash_exec "modprobe tun" +bash_exec "modprobe ip_tables" +bash_exec "modprobe iptable_nat" +bash_exec "modprobe x_tables" + +bash_exec "$IPTABLES -P INPUT ACCEPT" +bash_exec "$IPTABLES -F INPUT" +bash_exec "$IPTABLES -P OUTPUT ACCEPT" +bash_exec "$IPTABLES -F OUTPUT" +bash_exec "$IPTABLES -P FORWARD ACCEPT" +bash_exec "$IPTABLES -F FORWARD" +bash_exec "$IPTABLES -t raw -F" +bash_exec "$IPTABLES -t nat -F" +bash_exec "$IPTABLES -t mangle -F" +bash_exec "$IPTABLES -t filter -F" + +bash_exec "ip route flush cache" + + +echo " Disabling forwarding" +bash_exec "sysctl -w net.ipv4.ip_forward=0" +assert " `sysctl -n net.ipv4.ip_forward` -eq 0" $LINENO + +echo " Enabling DynamicAddr.." +bash_exec "sysctl -w net.ipv4.ip_dynaddr=1" +assert " `sysctl -n net.ipv4.ip_dynaddr` -eq 1" $LINENO + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO + + +start_openswitch_daemon +# REMINDER: +# +-----------+ +------+ +-----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME | +# | |cpenb0+------------------+cpmme0| | +# | +------+ |bridge| +------+ | +# | |upenb0+-------+ | | | +# +-----------+------+ | | | +-----------+ +# +---|--+ | +# | +-----------+ +# | | S+P-GW | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |pgwsgi0+---+br2 +----+eth0| +# +------+ +-------+ +----+ +----+ +# | | +# +-----------+ +# +################################################## +# del bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -d $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" +bash_exec "ovs-vsctl del-br $BRIDGE" + +################################################## +# build bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -t $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" + +bash_exec "ovs-vsctl add-br $BRIDGE" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $MME_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1U tag=2" +bash_exec "ovs-vsctl add-port $BRIDGE $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP tag=2" + +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME $MME_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $MME_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP $SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP netmask `cidr2mask $SGW_IP_NETMASK_FOR_S1U_S12_S4_UP` promisc up" + +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME $ENB_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U $ENB_IP_ADDRESS_FOR_S1U netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1U` promisc up" + +################################################## +# del bridge between SPGW and Internet +################################################## +#bash_exec "tunctl -d $PGW_INTERFACE_NAME_FOR_SGI" +#bash_exec "ovs-vsctl del-br $SGI_BRIDGE" + +################################################## +# build bridge between SPGW and Internet +################################################## + +# # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` +# if [ $IP_ADDR ]; then +# bash_exec "ip -4 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# +# # remove all ipv6 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR="not empty" +# until [ "$IP_ADDR"x == "x" ]; do +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | grep 'inet6' | head -1 | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' | cut -d ' ' -f3` +# if [ $IP_ADDR ]; then +# bash_exec "ip -6 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# done + +if [ $ENABLE_USE_NETFILTER_FOR_SGI -eq 1 ]; then + + bash_exec "modprobe nf_conntrack" + bash_exec "modprobe nf_conntrack_ftp" + + ###################################################### + # PREROUTING + ###################################################### + # We restore the mark following the CONNMARK mark. In fact, it does a simple MARK=CONNMARK + # where MARK is the standard mark (usable by tc) + # In French: Cette option de cible restaure le paquet marqué dans la marque de connexion + # comme défini par CONNMARK. Un masque peut aussi être défini par l'option --mask. + # Si une option mask est placée, seules les options masquées seront placées. + # Notez que cette option de cible n'est valide que dans la table mangle. + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --restore-mark" + + # TEST bash_exec "$IPTABLES -t mangle -A PREROUTING -m mark --mark 0 -i $PGW_INTERFACE_NAME_FOR_SGI -j MARK --set-mark 15" + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of POSTROUTING --restore-mark). + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --save-mark" + + + ###################################################### + # POSTROUTING + ###################################################### + + # MARK=CONNMARK + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -j CONNMARK --restore-mark" + # If we’ve got a mark no need to get further[ + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -m mark ! --mark 0 -j ACCEPT" + + #bash_exec "iptables -A POSTROUTING -p tcp --dport 21 -t mangle -j MARK --set-mark 1" + #bash_exec "iptables -A POSTROUTING -p tcp --dport 80 -t mangle -j MARK --set-mark 2" + + # We set the mark of the initial packet as value of the conntrack mark for all the packets + # of the connection. This mark will be restore for the other packets by the first rule + # of POSTROUTING (–restore-mark). + bash_exec "iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark" + + bash_exec "iptables -A PREROUTING -t mangle -j CONNMARK --restore-mark" + + # We restore the mark following the CONNMARK mark. + # In fact, it does a simple MARK=CONNMARK where MARK is the standard mark (usable by tc) + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j CONNMARK --restore-mark" + + # If we’ve got a mark no need to get further[1] + #TEST bash_exec "$IPTABLES -A OUTPUT -t mangle -p icmp -j MARK --set-mark 14" + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j ACCEPT" + + + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of OUTPUT (–restore-mark). + #bash_exec "$IPTABLES -A OUTPUT -t mangle -j CONNMARK --save-mark" + + ###################################################### + # NETFILTER QUEUE + ###################################################### + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 5 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 6 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 7 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 8 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 9 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 10 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 11 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 12 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 13 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 14 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 15 -j NFQUEUE --queue-num 1" + + #echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables #To disable Iptables in the bridge. + #Raw table: Some years ago appeared a new tables in Iptables. + #This table can be used to avoid packets (connection really) to enter the NAT table: + # iptables -t raw -I PREROUTING -i BRIDGE -s x.x.x.x -j NOTRACK. + + #bash_exec "$IPTABLES -t nat -A POSTROUTING -o $PGW_INTERFACE_NAME_FOR_SGI -j SNAT --to-source $PGW_IP_ADDR_FOR_SGI" +else + # # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI + #IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` + + #NETWORK=`echo $IP_ADDR | cut -d . -f 1,2,3` + + bash_exec "modprobe 8021q" + + for i in 5 6 7 8 9 10 11 12 13 14 15 + do + # create vlan interface + bash_exec "vconfig rem $PGW_INTERFACE_NAME_FOR_SGI.$i" + sync + bash_exec "vconfig add $PGW_INTERFACE_NAME_FOR_SGI $i" + sync + # configure vlan interface + #CIDR=$NETWORK'.'$i'/24' + base=200 + NET=$(( $i + $base )) + CIDR='10.0.'$NET'.2/8' + bash_exec "ip -4 addr add $CIDR dev $PGW_INTERFACE_NAME_FOR_SGI.$i" + done +fi + + +bash_exec "ip link set $PGW_INTERFACE_NAME_FOR_SGI promisc on" +##################################################.. + +# LAUNCH MME + S+P-GW executable +################################################## +#$OPENAIR3_DIR/OPENAIRMME/objs/OAISIM_MME/oaisim_mme -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf +#wait_process_started "oaisim_mme" + +gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf +wait_process_started "oai_epc" + +#gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf + diff --git a/openair-cn/SCRIPTS/start_lte-sgw.bash b/openair-cn/SCRIPTS/start_lte-sgw.bash new file mode 100644 index 0000000000..20df4259c4 --- /dev/null +++ b/openair-cn/SCRIPTS/start_lte-sgw.bash @@ -0,0 +1,310 @@ +#!/bin/bash +# start MME+S/P-GW with openvswitch setting + + hss.eur +# +-----------+ +------+ +-----------+ v +----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME +----+ +---+ HSS | +# | |cpenb0+------------------+cpmme0| | +------+ | | +# | +------+ |bridge| +------+ +----+ +---+ | +# | |upenb0+-------+ | | | +----------+ +# +-----------+------+ | | | +-----------+ +# +---|--+ | router.eur +# | +-----------+ | +--------------+ +# | | S+P-GW | v | ROUTER | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |sgi +-...-+ | | +---...Internet +# +------+ +-------+ +----+ +----+ +# | | 11 VLANS | | +# +-----------+ ids=[5..15] +--------------+ +# + + +BRIDGE="vswitch" + +########################################################### +IPTABLES=/sbin/iptables + +########################################################### + +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash + +########################################################### +declare -x OPENAIR_DIR="" +declare -x OPENAIR1_DIR="" +declare -x OPENAIR2_DIR="" +declare -x OPENAIR3_DIR="" +declare -x OPENAIR_TARGETS="" +########################################################### + +set_openair +cecho "OPENAIR_DIR = $OPENAIR_DIR" $green +cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green +cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green +cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green +cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green + +cat ./objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_NETFILTER_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_NETFILTER_FOR_SGI=0 +else + export ENABLE_USE_NETFILTER_FOR_SGI=1 +fi + +cat ./objs/Makefile | grep CFLAGS\ \=\ | grep DENABLE_USE_RAW_FOR_SGI +if [ $? -ne 0 ] +then + export ENABLE_USE_RAW_FOR_SGI=0 +else + export ENABLE_USE_RAW_FOR_SGI=1 +fi + +pkill oaisim_mme + + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_default.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +ping -c 1 hss.eur || { echo "hss.eur does not respond to ping" >&2 ; exit ; } +ping -c 1 router.eur || { echo "router.eur does not respond to ping" >&2 ; exit ; } +export IP_ROUTER=`python -c 'import socket; print socket.gethostbyname("router.eur")'` +export MAC_ROUTER=`ip neigh show | grep $IP_ROUTER | cut -d ' ' -f5 | tr -d ':'` +echo_success "ROUTER MAC ADDRESS= $MAC_ROUTER" +bash_exec "modprobe tun" +bash_exec "modprobe ip_tables" +bash_exec "modprobe iptable_nat" +bash_exec "modprobe x_tables" + +bash_exec "$IPTABLES -P INPUT ACCEPT" +bash_exec "$IPTABLES -F INPUT" +bash_exec "$IPTABLES -P OUTPUT ACCEPT" +bash_exec "$IPTABLES -F OUTPUT" +bash_exec "$IPTABLES -P FORWARD ACCEPT" +bash_exec "$IPTABLES -F FORWARD" +bash_exec "$IPTABLES -t raw -F" +bash_exec "$IPTABLES -t nat -F" +bash_exec "$IPTABLES -t mangle -F" +bash_exec "$IPTABLES -t filter -F" + + + +bash_exec "ip route flush cache" + + +echo " Disabling forwarding" +bash_exec "sysctl -w net.ipv4.ip_forward=0" +assert " `sysctl -n net.ipv4.ip_forward` -eq 0" $LINENO + +echo " Enabling DynamicAddr.." +bash_exec "sysctl -w net.ipv4.ip_dynaddr=1" +assert " `sysctl -n net.ipv4.ip_dynaddr` -eq 1" $LINENO + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO + + +start_openswitch_daemon +# REMINDER: +# +-----------+ +------+ +-----------+ +# | eNB +------+ | ovs | VLAN 1+------+ MME | +# | |cpenb0+------------------+cpmme0| | +# | +------+ |bridge| +------+ | +# | |upenb0+-------+ | | | +# +-----------+------+ | | | +-----------+ +# +---|--+ | +# | +-----------+ +# | | S+P-GW | +# | VLAN2 +------+ +-------+ +----+ +----+ +# +----------+upsgw0| |pgwsgi0+---+br2 +----+eth0| +# +------+ +-------+ +----+ +----+ +# | | +# +-----------+ +# +################################################## +# del bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -d $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -d $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" +bash_exec "ovs-vsctl del-br $BRIDGE" + +################################################## +# build bridge between eNB and MME/SPGW +################################################## +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $ENB_INTERFACE_NAME_FOR_S1U" +bash_exec "tunctl -t $MME_INTERFACE_NAME_FOR_S1_MME" +bash_exec "tunctl -t $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP" + +bash_exec "ovs-vsctl add-br $BRIDGE" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $MME_INTERFACE_NAME_FOR_S1_MME tag=1" +bash_exec "ovs-vsctl add-port $BRIDGE $ENB_INTERFACE_NAME_FOR_S1U tag=2" +bash_exec "ovs-vsctl add-port $BRIDGE $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP tag=2" + +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $MME_INTERFACE_NAME_FOR_S1_MME $MME_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $MME_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP promisc up" +bash_exec "ifconfig $SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP $SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP netmask `cidr2mask $SGW_IP_NETMASK_FOR_S1U_S12_S4_UP` promisc up" + +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1_MME $ENB_IP_ADDRESS_FOR_S1_MME netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1_MME` promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U promisc up" +bash_exec "ifconfig $ENB_INTERFACE_NAME_FOR_S1U $ENB_IP_ADDRESS_FOR_S1U netmask `cidr2mask $ENB_IP_NETMASK_FOR_S1U` promisc up" + +################################################## +# del bridge between SPGW and Internet +################################################## +#bash_exec "tunctl -d $PGW_INTERFACE_NAME_FOR_SGI" +#bash_exec "ovs-vsctl del-br $SGI_BRIDGE" + +################################################## +# build bridge between SPGW and Internet +################################################## + +# # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` +# if [ $IP_ADDR ]; then +# bash_exec "ip -4 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# +# # remove all ipv6 address from PGW_INTERFACE_NAME_FOR_SGI +# IP_ADDR="not empty" +# until [ "$IP_ADDR"x == "x" ]; do +# IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | grep 'inet6' | head -1 | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' | cut -d ' ' -f3` +# if [ $IP_ADDR ]; then +# bash_exec "ip -6 addr del $IP_ADDR dev $PGW_INTERFACE_NAME_FOR_SGI" +# fi +# done + +if [ $ENABLE_USE_NETFILTER_FOR_SGI -eq 1 ]; then + + bash_exec "modprobe nf_conntrack" + bash_exec "modprobe nf_conntrack_ftp" + + ###################################################### + # PREROUTING + ###################################################### + # We restore the mark following the CONNMARK mark. In fact, it does a simple MARK=CONNMARK + # where MARK is the standard mark (usable by tc) + # In French: Cette option de cible restaure le paquet marqué dans la marque de connexion + # comme défini par CONNMARK. Un masque peut aussi être défini par l'option --mask. + # Si une option mask est placée, seules les options masquées seront placées. + # Notez que cette option de cible n'est valide que dans la table mangle. + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --restore-mark" + + # TEST bash_exec "$IPTABLES -t mangle -A PREROUTING -m mark --mark 0 -i $PGW_INTERFACE_NAME_FOR_SGI -j MARK --set-mark 15" + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of POSTROUTING --restore-mark). + bash_exec "$IPTABLES -t mangle -A PREROUTING -j CONNMARK --save-mark" + + + ###################################################### + # POSTROUTING + ###################################################### + + # MARK=CONNMARK + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -j CONNMARK --restore-mark" + # If we’ve got a mark no need to get further[ + bash_exec "iptables -A POSTROUTING -t mangle -o tap0 -m mark ! --mark 0 -j ACCEPT" + + #bash_exec "iptables -A POSTROUTING -p tcp --dport 21 -t mangle -j MARK --set-mark 1" + #bash_exec "iptables -A POSTROUTING -p tcp --dport 80 -t mangle -j MARK --set-mark 2" + + # We set the mark of the initial packet as value of the conntrack mark for all the packets + # of the connection. This mark will be restore for the other packets by the first rule + # of POSTROUTING (–restore-mark). + bash_exec "iptables -A POSTROUTING -t mangle -j CONNMARK --save-mark" + + bash_exec "iptables -A PREROUTING -t mangle -j CONNMARK --restore-mark" + + # We restore the mark following the CONNMARK mark. + # In fact, it does a simple MARK=CONNMARK where MARK is the standard mark (usable by tc) + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j CONNMARK --restore-mark" + + # If we’ve got a mark no need to get further[1] + #TEST bash_exec "$IPTABLES -A OUTPUT -t mangle -p icmp -j MARK --set-mark 14" + #bash_exec "$IPTABLES -A OUTPUT -t mangle -m mark ! --mark 0 -j ACCEPT" + + + # We set the mark of the initial packet as value of the conntrack mark for all the packets of the connection. + # This mark will be restore for the other packets by the first rule of OUTPUT (–restore-mark). + #bash_exec "$IPTABLES -A OUTPUT -t mangle -j CONNMARK --save-mark" + + + + + ###################################################### + # NETFILTER QUEUE + ###################################################### + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 5 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 6 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 7 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 8 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 9 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 10 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 11 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 12 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 13 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 14 -j NFQUEUE --queue-num 1" + bash_exec "$IPTABLES -t mangle -A PREROUTING -i $PGW_INTERFACE_NAME_FOR_SGI -m connmark --mark 15 -j NFQUEUE --queue-num 1" + + #echo 0 > /proc/sys/net/bridge/bridge-nf-call-iptables #To disable Iptables in the bridge. + #Raw table: Some years ago appeared a new tables in Iptables. + #This table can be used to avoid packets (connection really) to enter the NAT table: + # iptables -t raw -I PREROUTING -i BRIDGE -s x.x.x.x -j NOTRACK. + + + + + #bash_exec "$IPTABLES -t nat -A POSTROUTING -o $PGW_INTERFACE_NAME_FOR_SGI -j SNAT --to-source $PGW_IP_ADDR_FOR_SGI" +else + # # get ipv4 address from PGW_INTERFACE_NAME_FOR_SGI + #IP_ADDR=`ifconfig $PGW_INTERFACE_NAME_FOR_SGI | awk '/inet addr/ {split ($2,A,":"); print A[2]}' | tr '\n' ' ' | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}'` + + #NETWORK=`echo $IP_ADDR | cut -d . -f 1,2,3` + + bash_exec "modprobe 8021q" + + for i in 5 6 7 8 9 10 11 12 13 14 15 + do + # create vlan interface + bash_exec "vconfig rem $PGW_INTERFACE_NAME_FOR_SGI.$i" + sync + bash_exec "vconfig add $PGW_INTERFACE_NAME_FOR_SGI $i" + sync + # configure vlan interface + #CIDR=$NETWORK'.'$i'/24' + base=200 + NET=$(( $i + $base )) + CIDR='10.0.'$NET'.2/8' + bash_exec "ip -4 addr add $CIDR dev $PGW_INTERFACE_NAME_FOR_SGI.$i" + done +fi + + +bash_exec "ip link set $PGW_INTERFACE_NAME_FOR_SGI promisc on" +##################################################.. + +# LAUNCH MME + S+P-GW executable +################################################## +#$OPENAIR3_DIR/OPENAIRMME/objs/OAISIM_MME/oaisim_mme -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf +#wait_process_started "oaisim_mme" + +gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf +wait_process_started "oai_epc" + +#gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/mme_default.conf + diff --git a/openair-cn/SCRIPTS/start_mme.bash b/openair-cn/SCRIPTS/start_mme.bash new file mode 100755 index 0000000000..ff5508fd74 --- /dev/null +++ b/openair-cn/SCRIPTS/start_mme.bash @@ -0,0 +1,35 @@ +#!/bin/bash +# start MME without configuring anything in networking + +############################### +# Include misc functions +############################### +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash + +# check_for_root_rights +check_for_mme_executable +check_epc_config + +############################### +# Test reachability of HSS +############################### +ping -c 1 hss.eur || { echo "hss.eur does not respond to ping" >&2 ; exit ; } + +############################### +# Test reachability of MME +############################### +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +ping -c 1 $MME_IP_ADDRESS_FOR_S1_MME || { echo "MME_IP_ADDRESS_FOR_S1_MME=$MME_IP_ADDRESS_FOR_S1_MME does not respond to ping" >&2 ; exit ; } +ping -c 1 $SGW_IP_ADDRESS_FOR_S11 || { echo "SGW_IP_ADDRESS_FOR_S11=$SGW_IP_ADDRESS_FOR_S11 does not respond to ping" >&2 ; exit ; } + + +############################### +cecho "Starting MME on host $HOSTNAME" $blue +############################### +$OPENAIR3_DIR/OPENAIRMME/objs/OAISIM_MME/oaisim_mme -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf + + diff --git a/openair-cn/SCRIPTS/start_router.eur.bash b/openair-cn/SCRIPTS/start_router.eur.bash new file mode 100755 index 0000000000..1757b27ae4 --- /dev/null +++ b/openair-cn/SCRIPTS/start_router.eur.bash @@ -0,0 +1,221 @@ +#!/bin/bash +# +# The location of the iptables and kernel module programs +# +# If your Linux distribution came with a copy of iptables, +# most likely all the programs will be located in /sbin. If +# you manually compiled iptables, the default location will +# be in /usr/local/sbin +# +# ** Please use the "whereis iptables" command to figure out +# ** where your copy is and change the path below to reflect +# ** your setup +# +IPTABLES=/sbin/iptables +DEPMOD=/sbin/depmod +MODPROBE=/sbin/modprobe + +########################################################### +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash +########################################################### + +#Setting the EXTERNAL and INTERNAL interfaces for the network +# + +EXTIF="eth0" +INTIF="eth2" +echo " External Interface: $EXTIF" +echo " Internal Interface: $INTIF" + +echo -en " loading modules: " + +# Need to verify that all modules have all required dependencies +# +echo " - Verifying that all kernel modules are ok" +$DEPMOD -a + +echo "----------------------------------------------------------------------" + +#Load the main body of the IPTABLES module - "iptable" +# - Loaded automatically when the "iptables" command is invoked +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "ip_tables, " +$MODPROBE ip_tables + + +#Load the IPTABLES filtering module - "iptable_filter" +# - Loaded automatically when filter policies are activated + + +#Load the stateful connection tracking framework - "ip_conntrack" +# +# The conntrack module in itself does nothing without other specific +# conntrack modules being loaded afterwards such as the "ip_conntrack_ftp" +# module +# +# - This module is loaded automatically when MASQ functionality is +# enabled +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "ip_conntrack, " +$MODPROBE ip_conntrack + + +#Load the FTP tracking mechanism for full FTP tracking +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_conntrack_ftp, " +$MODPROBE ip_conntrack_ftp + + +#Load the IRC tracking mechanism for full IRC tracking +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_conntrack_irc, " +$MODPROBE ip_conntrack_irc + + +#Load the general IPTABLES NAT code - "iptable_nat" +# - Loaded automatically when MASQ functionality is turned on +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "iptable_nat, " +$MODPROBE iptable_nat + + +#Loads the FTP NAT functionality into the core IPTABLES code +# Required to support non-PASV FTP. +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_nat_ftp, " +$MODPROBE ip_nat_ftp + +#Clearing any previous configuration +# +# Unless specified, the defaults for INPUT and OUTPUT is ACCEPT +# The default for FORWARD is DROP (REJECT is not a valid policy) +# +# Isn't ACCEPT insecure? To some degree, YES, but this is our testing +# phase. Once we know that IPMASQ is working well, I recommend you run +# the rc.firewall-*-stronger rulesets which set the defaults to DROP but +# also include the critical additional rulesets to still let you connect to +# the IPMASQ server, etc. +# +echo " Clearing any existing rules and setting default policy.." +bash_exec "iptables -P INPUT ACCEPT" +bash_exec "iptables -F INPUT" +bash_exec "iptables -P OUTPUT ACCEPT" +bash_exec "iptables -F OUTPUT" +bash_exec "iptables -P FORWARD ACCEPT" +bash_exec "iptables -F FORWARD" +bash_exec "iptables -t nat -F" +bash_exec "iptables -t mangle -F" +bash_exec "iptables -t filter -F" +bash_exec "iptables -t raw -F" + +bash_exec "ip route flush cache" + + +echo " Enabling forwarding" +bash_exec "sysctl -w net.ipv4.ip_forward=1" +assert " `sysctl -n net.ipv4.ip_forward` -eq 1" $LINENO + +# Dynamic IP users: +# +# If you get your IP address dynamically from SLIP, PPP, or DHCP, +# enable this following option. This enables dynamic-address hacking +# which makes the life with Diald and similar programs much easier. +# +echo " Enabling DynamicAddr.." +bash_exec "sysctl -w net.ipv4.ip_dynaddr=1" +assert " `sysctl -n net.ipv4.ip_dynaddr` -eq 1" $LINENO + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +bash_exec "sysctl -w net.ipv4.conf.all.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$EXTIF.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.$EXTIF.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$INTIF.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.$INTIF.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$EXTIF.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.$EXTIF.rp_forward` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$INTIF.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.$INTIF.rp_forward` -eq 0" $LINENO + + +echo "0" > /proc/sys/net/ipv4/conf/all/proxy_arp +echo "1" > /proc/sys/net/ipv4/conf/$EXTIF/proxy_arp +echo "1" > /proc/sys/net/ipv4/conf/$INTIF/proxy_arp + +echo " FWD: Allow all connections OUT and only existing and related ones IN" +bash_exec "iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT" +bash_exec "iptables -A FORWARD -i $INTIF -o $EXTIF -m state --state NEW,ESTABLISHED,RELATED,INVALID -j ACCEPT" + +bash_exec "modprobe 8021q" + +for i in 5 6 7 8 9 10 11 12 13 14 15 +do + bash_exec "vconfig rem $INTIF.$i" + sync + bash_exec "vconfig add $INTIF $i" + sync + NET=$(( $i + 200 )) + CIDR='10.0.'$NET'.1/8' + bash_exec "ip -4 addr add $CIDR broadcast 192.174.$NET.255 dev $INTIF.$i" + bash_exec "iptables -A FORWARD -i $EXTIF -o $INTIF.$i -m state --state ESTABLISHED,RELATED -j ACCEPT" + bash_exec "iptables -A FORWARD -i $INTIF.$i -o $EXTIF -m state --state NEW,ESTABLISHED,RELATED,INVALID -j ACCEPT" + bash_exec "echo 1 > /proc/sys/net/ipv4/conf/$INTIF.$i/proxy_arp" + bash_exec "echo 0 > /proc/sys/net/ipv4/conf/$INTIF.$i/rp_forward" + bash_exec "echo 0 > /proc/sys/net/ipv4/conf/$INTIF.$i/rp_filter" + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.proxy_arp` -eq 1" $LINENO + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.rp_forward` -eq 0" $LINENO + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.rp_filter` -eq 0" $LINENO +done +for i in 5 6 7 8 9 10 11 12 13 14 15 +do + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -j CONNMARK --restore-mark" + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -m mark --mark 0 -j MARK --set-mark $i" + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -j CONNMARK --save-mark" + + + fgrep vlan$i /etc/iproute2/rt_tables + if [ $? -ne 0 ] + then + base=200 + num=$(( $i + $base )) + echo "$num vlan$i" >> /etc/iproute2/rt_tables + echo "Updating /etc/iproute2/rt_tables with table vlan$i id $num" + fi + ip rule del from all iif $EXTIF fwmark $i table vlan$i > /dev/null + bash_exec "ip rule add iif $EXTIF fwmark $i table vlan$i" + bash_exec "ip route add default dev $INTIF.$i table vlan$i" +done +#bash_exec "iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark" +#iptables -I INPUT -i $INTIF.5 -j LOG --log-ip-options --log-prefix "INPUT CHAIN:" +#iptables -I FORWARD -t mangle -i $INTIF.5 -j LOG --log-ip-options --log-prefix "FORWARD CHAIN(mangle):" +#iptables -I FORWARD -t filter -i $INTIF.5 -j LOG --log-ip-options --log-prefix "FORWARD CHAIN(filter):" +#iptables -I PREROUTING -t raw -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (raw):" +#iptables -I PREROUTING -t mangle -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (mangle):" +#iptables -I PREROUTING -t nat -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (nat):" + + +echo " Enabling SNAT (MASQUERADE) functionality on $EXTIF" +bash_exec "iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE" + +echo -e "\nrc.firewall-iptables v$FWVER done.\n" +iptables -t mangle -nvL +iptables -t filter -nvL + diff --git a/openair-cn/SCRIPTS/start_router.nord.eur.bash b/openair-cn/SCRIPTS/start_router.nord.eur.bash new file mode 100644 index 0000000000..1757b27ae4 --- /dev/null +++ b/openair-cn/SCRIPTS/start_router.nord.eur.bash @@ -0,0 +1,221 @@ +#!/bin/bash +# +# The location of the iptables and kernel module programs +# +# If your Linux distribution came with a copy of iptables, +# most likely all the programs will be located in /sbin. If +# you manually compiled iptables, the default location will +# be in /usr/local/sbin +# +# ** Please use the "whereis iptables" command to figure out +# ** where your copy is and change the path below to reflect +# ** your setup +# +IPTABLES=/sbin/iptables +DEPMOD=/sbin/depmod +MODPROBE=/sbin/modprobe + +########################################################### +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash +########################################################### + +#Setting the EXTERNAL and INTERNAL interfaces for the network +# + +EXTIF="eth0" +INTIF="eth2" +echo " External Interface: $EXTIF" +echo " Internal Interface: $INTIF" + +echo -en " loading modules: " + +# Need to verify that all modules have all required dependencies +# +echo " - Verifying that all kernel modules are ok" +$DEPMOD -a + +echo "----------------------------------------------------------------------" + +#Load the main body of the IPTABLES module - "iptable" +# - Loaded automatically when the "iptables" command is invoked +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "ip_tables, " +$MODPROBE ip_tables + + +#Load the IPTABLES filtering module - "iptable_filter" +# - Loaded automatically when filter policies are activated + + +#Load the stateful connection tracking framework - "ip_conntrack" +# +# The conntrack module in itself does nothing without other specific +# conntrack modules being loaded afterwards such as the "ip_conntrack_ftp" +# module +# +# - This module is loaded automatically when MASQ functionality is +# enabled +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "ip_conntrack, " +$MODPROBE ip_conntrack + + +#Load the FTP tracking mechanism for full FTP tracking +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_conntrack_ftp, " +$MODPROBE ip_conntrack_ftp + + +#Load the IRC tracking mechanism for full IRC tracking +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_conntrack_irc, " +$MODPROBE ip_conntrack_irc + + +#Load the general IPTABLES NAT code - "iptable_nat" +# - Loaded automatically when MASQ functionality is turned on +# +# - Loaded manually to clean up kernel auto-loading timing issues +# +echo -en "iptable_nat, " +$MODPROBE iptable_nat + + +#Loads the FTP NAT functionality into the core IPTABLES code +# Required to support non-PASV FTP. +# +# Enabled by default -- insert a "#" on the next line to deactivate +# +echo -en "ip_nat_ftp, " +$MODPROBE ip_nat_ftp + +#Clearing any previous configuration +# +# Unless specified, the defaults for INPUT and OUTPUT is ACCEPT +# The default for FORWARD is DROP (REJECT is not a valid policy) +# +# Isn't ACCEPT insecure? To some degree, YES, but this is our testing +# phase. Once we know that IPMASQ is working well, I recommend you run +# the rc.firewall-*-stronger rulesets which set the defaults to DROP but +# also include the critical additional rulesets to still let you connect to +# the IPMASQ server, etc. +# +echo " Clearing any existing rules and setting default policy.." +bash_exec "iptables -P INPUT ACCEPT" +bash_exec "iptables -F INPUT" +bash_exec "iptables -P OUTPUT ACCEPT" +bash_exec "iptables -F OUTPUT" +bash_exec "iptables -P FORWARD ACCEPT" +bash_exec "iptables -F FORWARD" +bash_exec "iptables -t nat -F" +bash_exec "iptables -t mangle -F" +bash_exec "iptables -t filter -F" +bash_exec "iptables -t raw -F" + +bash_exec "ip route flush cache" + + +echo " Enabling forwarding" +bash_exec "sysctl -w net.ipv4.ip_forward=1" +assert " `sysctl -n net.ipv4.ip_forward` -eq 1" $LINENO + +# Dynamic IP users: +# +# If you get your IP address dynamically from SLIP, PPP, or DHCP, +# enable this following option. This enables dynamic-address hacking +# which makes the life with Diald and similar programs much easier. +# +echo " Enabling DynamicAddr.." +bash_exec "sysctl -w net.ipv4.ip_dynaddr=1" +assert " `sysctl -n net.ipv4.ip_dynaddr` -eq 1" $LINENO + +bash_exec "sysctl -w net.ipv4.conf.all.log_martians=1" +assert " `sysctl -n net.ipv4.conf.all.log_martians` -eq 1" $LINENO + + +echo " Disabling reverse path filtering" +bash_exec "sysctl -w net.ipv4.conf.all.rp_filter=0" +bash_exec "sysctl -w net.ipv4.conf.all.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.all.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$EXTIF.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.$EXTIF.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$INTIF.rp_filter=0" +assert " `sysctl -n net.ipv4.conf.$INTIF.rp_filter` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$EXTIF.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.$EXTIF.rp_forward` -eq 0" $LINENO +bash_exec "sysctl -w net.ipv4.conf.$INTIF.rp_forward=0" +assert " `sysctl -n net.ipv4.conf.$INTIF.rp_forward` -eq 0" $LINENO + + +echo "0" > /proc/sys/net/ipv4/conf/all/proxy_arp +echo "1" > /proc/sys/net/ipv4/conf/$EXTIF/proxy_arp +echo "1" > /proc/sys/net/ipv4/conf/$INTIF/proxy_arp + +echo " FWD: Allow all connections OUT and only existing and related ones IN" +bash_exec "iptables -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED -j ACCEPT" +bash_exec "iptables -A FORWARD -i $INTIF -o $EXTIF -m state --state NEW,ESTABLISHED,RELATED,INVALID -j ACCEPT" + +bash_exec "modprobe 8021q" + +for i in 5 6 7 8 9 10 11 12 13 14 15 +do + bash_exec "vconfig rem $INTIF.$i" + sync + bash_exec "vconfig add $INTIF $i" + sync + NET=$(( $i + 200 )) + CIDR='10.0.'$NET'.1/8' + bash_exec "ip -4 addr add $CIDR broadcast 192.174.$NET.255 dev $INTIF.$i" + bash_exec "iptables -A FORWARD -i $EXTIF -o $INTIF.$i -m state --state ESTABLISHED,RELATED -j ACCEPT" + bash_exec "iptables -A FORWARD -i $INTIF.$i -o $EXTIF -m state --state NEW,ESTABLISHED,RELATED,INVALID -j ACCEPT" + bash_exec "echo 1 > /proc/sys/net/ipv4/conf/$INTIF.$i/proxy_arp" + bash_exec "echo 0 > /proc/sys/net/ipv4/conf/$INTIF.$i/rp_forward" + bash_exec "echo 0 > /proc/sys/net/ipv4/conf/$INTIF.$i/rp_filter" + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.proxy_arp` -eq 1" $LINENO + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.rp_forward` -eq 0" $LINENO + assert " `sysctl -n net.ipv4.conf.$INTIF.$i.rp_filter` -eq 0" $LINENO +done +for i in 5 6 7 8 9 10 11 12 13 14 15 +do + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -j CONNMARK --restore-mark" + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -m mark --mark 0 -j MARK --set-mark $i" + bash_exec "iptables -t mangle -A PREROUTING -i $INTIF.$i -j CONNMARK --save-mark" + + + fgrep vlan$i /etc/iproute2/rt_tables + if [ $? -ne 0 ] + then + base=200 + num=$(( $i + $base )) + echo "$num vlan$i" >> /etc/iproute2/rt_tables + echo "Updating /etc/iproute2/rt_tables with table vlan$i id $num" + fi + ip rule del from all iif $EXTIF fwmark $i table vlan$i > /dev/null + bash_exec "ip rule add iif $EXTIF fwmark $i table vlan$i" + bash_exec "ip route add default dev $INTIF.$i table vlan$i" +done +#bash_exec "iptables -t mangle -A OUTPUT -m mark ! --mark 0 -j CONNMARK --save-mark" +#iptables -I INPUT -i $INTIF.5 -j LOG --log-ip-options --log-prefix "INPUT CHAIN:" +#iptables -I FORWARD -t mangle -i $INTIF.5 -j LOG --log-ip-options --log-prefix "FORWARD CHAIN(mangle):" +#iptables -I FORWARD -t filter -i $INTIF.5 -j LOG --log-ip-options --log-prefix "FORWARD CHAIN(filter):" +#iptables -I PREROUTING -t raw -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (raw):" +#iptables -I PREROUTING -t mangle -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (mangle):" +#iptables -I PREROUTING -t nat -i $INTIF.5 -j LOG --log-ip-options --log-prefix "PREROUTING (nat):" + + +echo " Enabling SNAT (MASQUERADE) functionality on $EXTIF" +bash_exec "iptables -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE" + +echo -e "\nrc.firewall-iptables v$FWVER done.\n" +iptables -t mangle -nvL +iptables -t filter -nvL + diff --git a/openair-cn/SCRIPTS/start_spgw.bash b/openair-cn/SCRIPTS/start_spgw.bash new file mode 100755 index 0000000000..631d92c5ac --- /dev/null +++ b/openair-cn/SCRIPTS/start_spgw.bash @@ -0,0 +1,70 @@ +#!/bin/bash +# start S+P-GW without configuring anything in networking + +############################### +# Include misc functions +############################### +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +source $THIS_SCRIPT_PATH/utils.bash + +echo "Starting S+P-GW on host $HOSTNAME" + +# Some file and executable checks +check_for_root_rights +check_epc_config +check_for_sgw_executable + +############################### +# Test reachability of MME +############################### +rm -f /tmp/source.txt +cat $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf | tr -d " " > /tmp/source.txt +source /tmp/source.txt + +# echo 'Testing reachability of S11 MME' +# ping -c 1 $MME_IP_ADDRESS_FOR_S11_MME || { echo "MME_IP_ADDRESS_FOR_S11_MME=$MME_IP_ADDRESS_FOR_S11_MME does not respond to ping" >&2 ; exit ; } + +############################### +# Test reachability of MME +############################### + +#IP_ROUTER=`python -c 'import socket; print socket.gethostbyname("router.eur")'` +#export MAC_ROUTER=`ip neigh show | grep $IP_ROUTER | cut -d ' ' -f5 | tr -d ':'` +#echo_success "ROUTER MAC ADDRESS= $MAC_ROUTER" + +export MAC_ROUTER="000000000000" + + +############################### +# CREATE SGI VLANs +############################### +bash_exec "modprobe 8021q" + +for i in 5 6 7 8 9 10 11 12 13 14 15 +do + # create vlan interface + bash_exec "vconfig rem $PGW_INTERFACE_NAME_FOR_SGI.$i" + sync + bash_exec "vconfig add $PGW_INTERFACE_NAME_FOR_SGI $i" + sync + # configure vlan interface + #CIDR=$NETWORK'.'$i'/24' + base=200 + NET=$(( $i + $base )) + CIDR='10.0.'$NET'.2/8' + bash_exec "ip -4 addr add $CIDR dev $PGW_INTERFACE_NAME_FOR_SGI.$i" + bash_exec "ip link set dev $PGW_INTERFACE_NAME_FOR_SGI.$i up" +done + +bash_exec "ip link set $PGW_INTERFACE_NAME_FOR_SGI promisc on" + +# custom for hades +ip r d default via 192.168.21.1 dev wlan0 +ip r d default via 192.168.21.1 dev wlan0 +pkill synergyc +synergyc 192.168.12.17 + +############################### +echo 'starting SGW' +############################### +gdb --args $OPENAIR3_DIR/OPENAIRMME/objs/OAI_SGW/oai_sgw -c $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf diff --git a/openair-cn/SCRIPTS/utils.bash b/openair-cn/SCRIPTS/utils.bash new file mode 100755 index 0000000000..ee871ce9c2 --- /dev/null +++ b/openair-cn/SCRIPTS/utils.bash @@ -0,0 +1,276 @@ +cidr2mask() { + local i mask="" + local full_octets=$(($1/8)) + local partial_octet=$(($1%8)) + + for ((i=0;i<4;i+=1)); do + if [ $i -lt $full_octets ]; then + mask+=255 + elif [ $i -eq $full_octets ]; then + mask+=$((256 - 2**(8-$partial_octet))) + else + mask+=0 + fi + test $i -lt 3 && mask+=. + done + + echo $mask +} + + +black='\E[30m' +red='\E[31m' +green='\E[32m' +yellow='\E[33m' +blue='\E[34m' +magenta='\E[35m' +cyan='\E[36m' +white='\E[37m' +reset_color='\E[00m' + +ROOT_UID=0 +E_NOTROOT=67 + +HOSTNAME=$(hostname -f) + +trim () +{ + echo "$1" | sed -n '1h;1!H;${;g;s/^[ \t]*//g;s/[ \t]*$//g;p;}' +} + + +cecho() # Color-echo +# arg1 = message +# arg2 = color +{ + local default_msg="No Message." + message=${1:-$default_msg} + color=${2:-$green} + echo -e -n "$color$message$reset_color" + echo + return +} + +echo_error() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $red +} + +echo_warning() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $yellow +} + +echo_success() { + local my_string="" + until [ -z "$1" ] + do + my_string="$my_string$1" + shift + done + cecho "$my_string" $green +} + +bash_exec() { + output=$($1 2>&1) + result=$? + if [ $result -eq 0 ] + then + echo_success "$1" + else + echo_error "$1: $output" + fi +} + +set_openair() { + path=`pwd` + declare -i length_path + declare -i index + length_path=${#path} + + index=`echo $path | grep -b -o 'targets' | cut -d: -f1` + #echo ${path%$token*} + if [[ $index -lt $length_path && index -gt 0 ]] + then + declare -x OPENAIR_DIR + index=`expr $index - 1` + openair_path=`echo $path | cut -c1-$index` + #openair_path=`echo ${path:0:$index}` + export OPENAIR_DIR=$openair_path + export OPENAIR1_DIR=$openair_path/openair1 + export OPENAIR2_DIR=$openair_path/openair2 + export OPENAIR3_DIR=$openair_path/openair3 + export OPENAIR_TARGETS=$openair_path/targets + return 0 + fi + index=`echo $path | grep -b -o 'openair3' | cut -d: -f1` + if [[ $index -lt $length_path && index -gt 0 ]] + then + declare -x OPENAIR_DIR + index=`expr $index - 1` + openair_path=`echo $path | cut -c1-$index` + #openair_path=`echo ${path:0:$index}` + export OPENAIR_DIR=$openair_path + export OPENAIR1_DIR=$openair_path/openair1 + export OPENAIR2_DIR=$openair_path/openair2 + export OPENAIR3_DIR=$openair_path/openair3 + export OPENAIR_TARGETS=$openair_path/targets + return 0 + fi + return -1 +} + +wait_process_started () { + if [ -z "$1" ] + then + echo_error "WAITING FOR PROCESS START: NO PROCESS" + return 1 + fi + ps -C $1 > /dev/null 2>&1 + while [ $? -ne 0 ]; do + echo_warning "WAITING FOR $1 START" + sleep 2 + ps -C $1 > /dev/null 2>&1 + done + echo_success "PROCESS $1 STARTED" + return 0 +} + +is_process_started () { + if [ -z "$1" ] + then + echo_error "WAITING FOR PROCESS START: NO PROCESS" + return 1 + fi + ps -C $1 > /dev/null 2>&1 + if [ $? -ne 0 ] + then + echo_success "PROCESS $1 NOT STARTED" + return 1 + fi + echo_success "PROCESS $1 STARTED" + return 0 +} + +assert() { + # If condition false + # exit from script with error message + E_PARAM_ERR=98 + E_PARAM_FAILED=99 + + if [ -z "$2" ] # Not enought parameters passed. + then + return $E_PARAM_ERR + fi + + lineno=$2 + if [ ! $1 ] + then + echo "Assertion failed: \"$1\"" + echo "File \"$0\", line $lineno" + exit $E_ASSERT_FAILED + fi +} + +start_openswitch_daemon() { + rmmod -s bridge + if [[ -e "/lib/modules/`uname -r`/extra/openvswitch.ko" ]] ; then + bash_exec "insmod /lib/modules/`uname -r`/extra/openvswitch.ko" + else + echo_error "/lib/modules/`uname -r`/extra/openvswitch.ko not found, exiting" + exit -1 + fi + is_process_started "ovsdb-server" + if [ $? -ne 0 ] + then + ovsdb-server --remote=punix:/usr/local/var/run/openvswitch/db.sock --remote=db:Open_vSwitch,manager_options --pidfile --detach + wait_process_started "ovsdb-server" + fi + # To be done after installation + # ovs-vsctl --no-wait init + is_process_started "ovs-vswitchd" + if [ $? -ne 0 ] + then + ovs-vswitchd --pidfile --detach + wait_process_started "ovs-vswitchd" + fi +} + +check_epc_config() { + if [ ! -f $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf ] + then + echo "Cannot find file $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/epc_$HOSTNAME.conf" + echo "Please make sure to create one that fits your use (you can use mme_default.conf file as template)" + exit -1 + fi +} + +check_enb_config() { + if [ ! -f $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf ] + then + echo "Cannot find file $OPENAIR3_DIR/OPENAIRMME/UTILS/CONF/enb_$HOSTNAME.conf" + echo "Please make sure to create one that fits your use (you can use mme_default.conf file as template)" + exit -1 + fi +} + +check_for_epc_executable() { + if [ ! -f $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/oai_epc ] + then + echo "Cannot find oai_epc executable object in directory $OPENAIR3_DIR/OPENAIRMME/objs/OAI_EPC/" + echo "Please make sure you have compiled OAI EPC with --enable-standalone-epc option" + exit -1 + fi +} + +check_for_sgw_executable() { + if [ ! -f $OPENAIR3_DIR/OPENAIRMME/objs/OAI_SGW/oai_sgw ] + then + echo "Cannot find oai_sgw executable object in directory $OPENAIR3_DIR/OPENAIRMME/objs/OAI_SGW/" + echo "Please make sure you have compiled OAI EPC without --enable-standalone-epc option" + exit -1 + fi +} + +check_for_mme_executable() { + if [ ! -f $OPENAIR3_DIR/OPENAIRMME/objs/OAISIM_MME/oaisim_mme ] + then + echo "Cannot find oai_sgw executable object in directory $OPENAIR3_DIR/OPENAIRMME/objs/OAISIM_MME/" + echo "Please make sure you have compiled OAI EPC without --enable-standalone-epc option" + exit -1 + fi +} + +check_for_root_rights() { + if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" 1>&2 + exit -1 + fi +} + +########################################################### +IPTABLES=/sbin/iptables +THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) +declare -x OPENAIR_DIR="" +declare -x OPENAIR1_DIR="" +declare -x OPENAIR2_DIR="" +declare -x OPENAIR3_DIR="" +declare -x OPENAIR_TARGETS="" +########################################################### + +set_openair +cecho "OPENAIR_DIR = $OPENAIR_DIR" $green +cecho "OPENAIR1_DIR = $OPENAIR1_DIR" $green +cecho "OPENAIR2_DIR = $OPENAIR2_DIR" $green +cecho "OPENAIR3_DIR = $OPENAIR3_DIR" $green +cecho "OPENAIR_TARGETS = $OPENAIR_TARGETS" $green diff --git a/openair-cn/SCTP/Makefile.am b/openair-cn/SCTP/Makefile.am new file mode 100644 index 0000000000..393cd0ed69 --- /dev/null +++ b/openair-cn/SCTP/Makefile.am @@ -0,0 +1,18 @@ +noinst_LTLIBRARIES = libsctpserver.la libsctpclient.la +libsctpclient_la_LDFLAGS = -all-static +libsctpserver_la_LDFLAGS = -all-static + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/UTILS + +libsctpserver_la_SOURCES= \ + sctp_common.c sctp_common.h \ + sctp_itti_messaging.h sctp_itti_messaging.c \ + sctp_primitives_server.h sctp_primitives_server.c + +libsctpclient_la_SOURCES= \ + sctp_common.c sctp_common.h \ + sctp_primitives_client.h sctp_primitives_client.c \ No newline at end of file diff --git a/openair-cn/SCTP/Makefile.eNB b/openair-cn/SCTP/Makefile.eNB new file mode 100644 index 0000000000..0f40c2b8bb --- /dev/null +++ b/openair-cn/SCTP/Makefile.eNB @@ -0,0 +1,47 @@ +libsctp_OBJECTS = \ + sctp_primitives_client.o \ + sctp_common.o + +-include .deps/*.d + +.PHONY = depdir + +CFLAGS = \ + -I../SCTP \ + -I../UTILS \ + -I$(OPENAIR2_DIR) \ + -I$(OPENAIR2_DIR)/COMMON \ + -I$(OPENAIR2_DIR)/S1AP \ + -I$(OPENAIR2_DIR)/GTPV1U \ + -I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/include \ + -I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/shared \ + -I$(OPENAIR2_DIR)/UTIL \ + -I$(OPENAIR2_DIR)/UTIL/UDP \ + -DUPDATE_RELEASE_9 \ + -DENB_MODE \ + -DENABLE_USE_MME \ + -DUSER_MODE \ + -O2 \ + -g \ + -Wall \ + -Werror=implicit-function-declaration + +$(libsctp_OBJECTS): %.o : %.c + @echo "Compiling $<" + @$(CC) -c $(CFLAGS) -o $@ $< + @if ! test -d ".deps/" ; then mkdir -p .deps; fi + @$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d + @mv -f .deps/$*.d .deps/$*.d.tmp + @sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d + @sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d + @rm -f .deps/$*.d.tmp + +libsctp.a: $(libsctp_OBJECTS) + @echo Creating SCTP archive + @$(AR) rcvs $@ $(libsctp_OBJECTS) + +clean: + rm -f $(libsctp_OBJECTS) + rm -rf .deps/ + rm -f libsctp.a \ No newline at end of file diff --git a/openair-cn/SCTP/sctp_common.c b/openair-cn/SCTP/sctp_common.c new file mode 100644 index 0000000000..c2d8656884 --- /dev/null +++ b/openair-cn/SCTP/sctp_common.c @@ -0,0 +1,238 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file sctp_common.c + * \brief eNB/MME SCTP related common procedures + * \author Sebastien ROUX + * \date 2013 + * \version 1.0 + * @ingroup _sctp + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include <sys/socket.h> +#include <arpa/inet.h> + +#include <netinet/in.h> +#include <netinet/sctp.h> + +#include "sctp_common.h" + +/* Pre-bind socket options configuration. + * See http://linux.die.net/man/7/sctp for more informations on these options. + */ +int sctp_set_init_opt(int sd, uint16_t instreams, uint16_t outstreams, + uint16_t max_attempts, uint16_t init_timeout) +{ + int on = 1; + struct sctp_initmsg init; + + memset((void *)&init, 0, sizeof(struct sctp_initmsg)); + + /* Request a number of streams */ + init.sinit_num_ostreams = outstreams; + init.sinit_max_instreams = instreams; + init.sinit_max_attempts = max_attempts; + + if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, &init, sizeof(struct sctp_initmsg)) < 0) + { + SCTP_ERROR("setsockopt: %d:%s\n", errno, strerror(errno)); + close(sd); + return -1; + } + + /* Allow socket reuse */ + if (setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) { + SCTP_ERROR("setsockopt SO_REUSEADDR failed (%d:%s)\n", errno, strerror(errno)); + close(sd); + return -1; + } + + return 0; +} + +int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream, + uint32_t *assoc_id) +{ + socklen_t i; + struct sctp_status status; + + if (socket <= 0) { + return -1; + } + + memset(&status, 0, sizeof(struct sctp_status)); + i = sizeof(struct sctp_status); + + if(getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &i) < 0) { + SCTP_ERROR("Getsockopt SCTP_STATUS failed: %s\n", strerror(errno)); + return -1; + } + + SCTP_DEBUG("----------------------\n"); + SCTP_DEBUG("SCTP Status:\n"); + SCTP_DEBUG("assoc id .....: %u\n", status.sstat_assoc_id); + SCTP_DEBUG("state ........: %d\n", status.sstat_state); + SCTP_DEBUG("instrms ......: %u\n", status.sstat_instrms); + SCTP_DEBUG("outstrms .....: %u\n", status.sstat_outstrms); + SCTP_DEBUG("fragmentation : %u\n", status.sstat_fragmentation_point); + SCTP_DEBUG("pending data .: %u\n", status.sstat_penddata); + SCTP_DEBUG("unack data ...: %u\n", status.sstat_unackdata); + SCTP_DEBUG("rwnd .........: %u\n", status.sstat_rwnd); + SCTP_DEBUG("peer info :\n"); + SCTP_DEBUG(" state ....: %u\n", status.sstat_primary.spinfo_state); + SCTP_DEBUG(" cwnd .....: %u\n", status.sstat_primary.spinfo_cwnd); + SCTP_DEBUG(" srtt .....: %u\n" , status.sstat_primary.spinfo_srtt); + SCTP_DEBUG(" rto ......: %u\n" , status.sstat_primary.spinfo_rto); + SCTP_DEBUG(" mtu ......: %u\n" , status.sstat_primary.spinfo_mtu); + SCTP_DEBUG("----------------------\n"); + + if (instream != NULL) { + *instream = status.sstat_instrms; + } + if (outstream != NULL) { + *outstream = status.sstat_outstrms; + } + if (assoc_id != NULL) { + *assoc_id = status.sstat_assoc_id; + } + + return 0; +} + +int sctp_get_peeraddresses(int sock, struct sockaddr **remote_addr, int *nb_remote_addresses) +{ + int nb, j; + struct sockaddr *temp_addr_p; + + if ((nb = sctp_getpaddrs(sock, -1, &temp_addr_p)) <= 0) + { + SCTP_ERROR("Failed to retrieve peer addresses\n"); + return -1; + } + + SCTP_DEBUG("----------------------\n"); + SCTP_DEBUG("Peer addresses:\n"); + for (j = 0; j < nb; j++) + { + if (temp_addr_p[j].sa_family == AF_INET) { + char address[16]; + struct sockaddr_in *addr; + + memset(&address, 0, sizeof(address)); + + addr = (struct sockaddr_in*)&temp_addr_p[j]; + if (inet_ntop(AF_INET, &addr->sin_addr, address, sizeof(address)) != NULL) + { + SCTP_DEBUG(" - [%s]\n", address); + } + } else { + struct sockaddr_in6 *addr; + char address[40]; + + addr = (struct sockaddr_in6*)&temp_addr_p[j]; + + memset(&address, 0, sizeof(address)); + if (inet_ntop(AF_INET6, &addr->sin6_addr.s6_addr, address, sizeof(address)) != NULL) + { + SCTP_DEBUG(" - [%s]\n", address); + } + } + } + SCTP_DEBUG("----------------------\n"); + + if (remote_addr != NULL && nb_remote_addresses != NULL) { + *nb_remote_addresses = nb; + *remote_addr = temp_addr_p; + } else { + /* We can destroy buffer */ + sctp_freepaddrs((struct sockaddr*)temp_addr_p); + } + + return 0; +} + +int sctp_get_localaddresses(int sock, struct sockaddr **local_addr, int *nb_local_addresses) +{ + int nb, j; + struct sockaddr *temp_addr_p; + + if ((nb = sctp_getladdrs(sock, -1, &temp_addr_p)) <= 0) + { + SCTP_ERROR("Failed to retrieve local addresses\n"); + return -1; + } + + SCTP_DEBUG("----------------------\n"); + SCTP_DEBUG("Local addresses:\n"); + for (j = 0; j < nb; j++) + { + if (temp_addr_p[j].sa_family == AF_INET) { + char address[16]; + struct sockaddr_in *addr; + + memset(address, 0, sizeof(address)); + + addr = (struct sockaddr_in*)&temp_addr_p[j]; + if (inet_ntop(AF_INET, &addr->sin_addr, address, sizeof(address)) != NULL) + { + SCTP_DEBUG(" - [%s]\n", address); + } + } else { + struct sockaddr_in6 *addr; + char address[40]; + + addr = (struct sockaddr_in6*)&temp_addr_p[j]; + + memset(address, 0, sizeof(address)); + + if (inet_ntop(AF_INET6, &addr->sin6_addr.s6_addr, address, sizeof(address)) != NULL) + { + SCTP_DEBUG(" - [%s]\n", address); + } + } + } + SCTP_DEBUG("----------------------\n"); + + if (local_addr != NULL && nb_local_addresses != NULL) { + *nb_local_addresses = nb; + *local_addr = temp_addr_p; + } else { + /* We can destroy buffer */ + sctp_freeladdrs((struct sockaddr*)temp_addr_p); + } + + return 0; +} + diff --git a/openair-cn/SCTP/sctp_common.h b/openair-cn/SCTP/sctp_common.h new file mode 100644 index 0000000000..af861d4c90 --- /dev/null +++ b/openair-cn/SCTP/sctp_common.h @@ -0,0 +1,68 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file sctp_common.h + * \brief eNB/MME SCTP related common procedures + * \author Sebastien ROUX + * \date 2013 + * \version 1.0 + * @ingroup _sctp + */ + +#include <stdio.h> +#include <stdint.h> + +#ifndef SCTP_COMMON_H_ +#define SCTP_COMMON_H_ + +#if defined(ENB_MODE) +# include "UTIL/LOG/log.h" +# define SCTP_ERROR(x, args...) LOG_E(SCTP, x, ##args) +# define SCTP_WARN(x, args...) LOG_W(SCTP, x, ##args) +# define SCTP_DEBUG(x, args...) LOG_D(SCTP, x, ##args) +#else +# define SCTP_ERROR(x, args...) do { fprintf(stderr, "[SCTP][E]"x, ##args); } while(0) +# define SCTP_DEBUG(x, args...) do { fprintf(stdout, "[SCTP][D]"x, ##args); } while(0) +# define SCTP_WARN(x, args...) do { fprintf(stdout, "[SCTP][W]"x, ##args); } while(0) +#endif + +int sctp_set_init_opt(int sd, uint16_t instreams, uint16_t outstreams, + uint16_t max_attempts, uint16_t init_timeout); + +int sctp_get_sockinfo(int sock, uint16_t *instream, uint16_t *outstream, + uint32_t *assoc_id); + +int sctp_get_peeraddresses(int sock, struct sockaddr **remote_addr, + int *nb_remote_addresses); + +int sctp_get_localaddresses(int sock, struct sockaddr **local_addr, + int *nb_local_addresses); + +#endif /* SCTP_COMMON_H_ */ diff --git a/openair-cn/SCTP/sctp_eNB_defs.h b/openair-cn/SCTP/sctp_eNB_defs.h new file mode 100644 index 0000000000..716aa1ed42 --- /dev/null +++ b/openair-cn/SCTP/sctp_eNB_defs.h @@ -0,0 +1,66 @@ +#include "queue.h" + +#ifndef SCTP_ENB_DEFS_H_ +#define SCTP_ENB_DEFS_H_ + +typedef struct sctp_queue_item_s { + /* Pair of stream on which we received this packet */ + uint16_t local_stream; + + /* Remote port */ + uint16_t remote_port; + /* Remote address */ + uint32_t remote_addr; + uint32_t assoc_id; + + /* PPID used for the packet */ + uint32_t ppid; + + /* Buffer and buffer length for the packet */ + uint32_t length; + uint8_t *buffer; + + /* queue.h internal data */ + TAILQ_ENTRY(sctp_queue_item_s) entry; +} sctp_queue_item_t; + +typedef struct { + /* Socket descriptor used to send/recv data on SCTP */ + int sd; + + /* Unique SCTP association ID (Local to host), used to distinguish + * associations between MME and eNB. + */ + uint32_t assoc_id; + + /* Current remote port used for transmission */ + uint16_t remote_port; + /* Remote IP addresses */ + struct sockaddr *remote_ip_addresses; + int nb_remote_addresses; + + /* Local port to use for transmission (dynamically allocated) */ + uint16_t local_port; + /* Local IP address to use for transmission */ + struct sockaddr *local_ip_addr; + int nb_local_addresses; + + /* Number of input/output streams used over this association. + * The number is negotiated between peers at connect and the minimum value + * of both peers is used over the association. + */ + uint16_t instreams; + uint16_t outstreams; + + /* Queue of messages received on SCTP. Messages will be processed later by + * upper layer. This will allow data prioritization and data de-fragmentation + * (if any on interface). + */ + TAILQ_HEAD(sctp_queue_s, sctp_queue_item_s) sctp_queue; + /* Queue size in bytes (may be used to limit eNB processing) */ + uint32_t queue_size; + /* Number of items in the queue */ + uint32_t queue_length; +} sctp_data_t; + +#endif /* SCTP_ENB_DEFS_H_ */ diff --git a/openair-cn/SCTP/sctp_itti_messaging.c b/openair-cn/SCTP/sctp_itti_messaging.c new file mode 100644 index 0000000000..8d88a8940a --- /dev/null +++ b/openair-cn/SCTP/sctp_itti_messaging.c @@ -0,0 +1,60 @@ +#include <string.h> + +#include "intertask_interface.h" + +#include "sctp_itti_messaging.h" + +int sctp_itti_send_new_association(uint32_t assoc_id, uint16_t instreams, + uint16_t outstreams) +{ + MessageDef *message_p; + sctp_new_peer_t *sctp_new_peer_p; + + message_p = alloc_new_message(TASK_SCTP, SCTP_NEW_ASSOCIATION); + + sctp_new_peer_p = &message_p->msg.sctp_new_peer; + + sctp_new_peer_p->assoc_id = assoc_id; + sctp_new_peer_p->instreams = instreams; + sctp_new_peer_p->outstreams = outstreams; + + return send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p); +} + +int sctp_itti_send_new_message_ind(int n, uint8_t *buffer, uint32_t assoc_id, + uint16_t stream, + uint16_t instreams, uint16_t outstreams) +{ + MessageDef *message_p; + s1ap_sctp_new_msg_ind_t *sctp_new_msg_ind_p; + + message_p = alloc_new_message(TASK_SCTP, S1AP_SCTP_NEW_MESSAGE_IND); + + sctp_new_msg_ind_p = &message_p->msg.s1ap_sctp_new_msg_ind; + + sctp_new_msg_ind_p->buffer = malloc(sizeof(uint8_t) * n); + + memcpy((void *)sctp_new_msg_ind_p->buffer, (void *)buffer, n); + + sctp_new_msg_ind_p->stream = stream; + sctp_new_msg_ind_p->buf_length = n; + sctp_new_msg_ind_p->assoc_id = assoc_id; + sctp_new_msg_ind_p->instreams = instreams; + sctp_new_msg_ind_p->outstreams = outstreams; + + return send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p); +} + +int sctp_itti_send_com_down_ind(uint32_t assoc_id) +{ + MessageDef *message_p; + sctp_close_association_t *sctp_close_association_p; + + message_p = alloc_new_message(TASK_SCTP, SCTP_CLOSE_ASSOCIATION); + + sctp_close_association_p = &message_p->msg.sctp_close_association; + + sctp_close_association_p->assoc_id = assoc_id; + + return send_msg_to_task(TASK_S1AP, INSTANCE_DEFAULT, message_p); +} diff --git a/openair-cn/SCTP/sctp_itti_messaging.h b/openair-cn/SCTP/sctp_itti_messaging.h new file mode 100644 index 0000000000..6aea0c4feb --- /dev/null +++ b/openair-cn/SCTP/sctp_itti_messaging.h @@ -0,0 +1,13 @@ +#ifndef SCTP_ITTI_MESSAGING_H_ +#define SCTP_ITTI_MESSAGING_H_ + +int sctp_itti_send_new_association(uint32_t assoc_id, uint16_t instreams, + uint16_t outstreams); + +int sctp_itti_send_new_message_ind(int n, uint8_t *buffer, uint32_t assoc_id, + uint16_t stream, + uint16_t instreams, uint16_t outstreams); + +int sctp_itti_send_com_down_ind(uint32_t assoc_id); + +#endif /* SCTP_ITTI_MESSAGING_H_ */ diff --git a/openair-cn/SCTP/sctp_primitives_client.c b/openair-cn/SCTP/sctp_primitives_client.c new file mode 100644 index 0000000000..ec71df9d70 --- /dev/null +++ b/openair-cn/SCTP/sctp_primitives_client.c @@ -0,0 +1,275 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> +#include <poll.h> + +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +//WARNING: sctp requires libsctp-dev and -lsctp as linker option +#include <netinet/sctp.h> +#include <arpa/inet.h> + +#include "assertions.h" +#include "sctp_eNB_defs.h" +#include "sctp_common.h" + +#include "sctp_primitives_client.h" + +#if defined(ENB_MODE) +# include "eNB_default_values.h" +#else +# include "mme_default_values.h" +#endif + +/* Send buffer to SCTP association */ +int sctp_send_msg(sctp_data_t *sctp_data_p, uint16_t ppid, uint16_t stream, + const uint8_t *buffer, const uint32_t length) +{ + DevAssert(buffer != NULL); + DevAssert(sctp_data_p != NULL); + + /* Send message on specified stream of the sd association + * NOTE: PPID should be defined in network order + */ + if (sctp_sendmsg(sctp_data_p->sd, (const void *)buffer, length, NULL, 0, + htonl(ppid), 0, stream, 0, 0) < 0) { + SCTP_ERROR("Sctp_sendmsg failed: %s\n", strerror(errno)); + return -1; + } + + SCTP_DEBUG("Successfully sent %d bytes to port %d on stream %d\n", + length, sctp_data_p->remote_port, stream); + + return 0; +} + +static +int sctp_handle_notifications(union sctp_notification *snp) +{ + if (SCTP_SHUTDOWN_EVENT == snp->sn_header.sn_type) { + /* Client deconnection */ + SCTP_DEBUG("Notification received: server deconnected\n"); + } else if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) { + /* Association has changed */ + SCTP_DEBUG("Notification received: server association changed\n"); + } + /* TODO: handle more notif here */ + return 0; +} + +int sctp_run(sctp_data_t *sctp_data_p) +{ + int ret, repeat = 1; + int total_size = 0; + int sd; + struct pollfd fds; + + DevAssert(sctp_data_p != NULL); + + sd = sctp_data_p->sd; + + memset(&fds, 0, sizeof(struct pollfd)); + + fds.fd = sd; + fds.events = POLLIN; + + while (repeat == 1) { + ret = poll(&fds, 1, 0); + + if (ret < 0) { + SCTP_ERROR("[SD %d] Poll has failed (%d:%s)\n", + sd, errno, strerror(errno)); + return errno; + } else if (ret == 0) { + /* No data to read, just leave the loop */ + SCTP_DEBUG("[SD %d] Poll: no data available\n", sd); + repeat = 0; + } else { + /* Socket has some data to read */ + uint8_t buffer[SCTP_RECV_BUFFER_SIZE]; + int flags = 0; + int n; + struct sockaddr_in addr; + struct sctp_sndrcvinfo sinfo; + + socklen_t from_len; + memset((void *)&addr, 0, sizeof(struct sockaddr_in)); + from_len = (socklen_t)sizeof(struct sockaddr_in); + memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); + + n = sctp_recvmsg(sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE, + (struct sockaddr *)&addr, &from_len, + &sinfo, &flags); + + if (n < 0) { + /* Other peer is deconnected */ + SCTP_ERROR("[SD %d] An error occured during read (%d:%s)\n", + sd, errno, strerror(errno)); + return 0; + } + if (flags & MSG_NOTIFICATION) { + sctp_handle_notifications((union sctp_notification *)buffer); + } else { + struct sctp_queue_item_s *new_item_p; + + new_item_p = calloc(1, sizeof(struct sctp_queue_item_s)); + /* Normal data received */ + SCTP_DEBUG("[SD %d] Msg of length %d received from %s:%u on " + "stream %d, PPID %d, assoc_id %d\n", + sd, n, inet_ntoa(addr.sin_addr), + ntohs(addr.sin_port), sinfo.sinfo_stream, + sinfo.sinfo_ppid, sinfo.sinfo_assoc_id); + + new_item_p->local_stream = sinfo.sinfo_stream; + new_item_p->remote_port = ntohs(addr.sin_port); + new_item_p->remote_addr = addr.sin_addr.s_addr; + new_item_p->ppid = sinfo.sinfo_ppid; + new_item_p->assoc_id = sinfo.sinfo_assoc_id; + new_item_p->length = n; + new_item_p->buffer = malloc(sizeof(uint8_t) * n); + + memcpy(new_item_p->buffer, buffer, n); + + /* Insert the new packet at the tail of queue. */ + TAILQ_INSERT_TAIL(&sctp_data_p->sctp_queue, new_item_p, entry); + + /* Update queue related data */ + sctp_data_p->queue_size += n; + sctp_data_p->queue_length++; + total_size += n; + } + } + } + return total_size; +} + +int sctp_connect_to_remote_host(char *local_ip_addr[], + int nb_local_addr, + char *remote_ip_addr, + uint16_t port, + int socket_type, + sctp_data_t *sctp_data_p) +{ + int sd = -1; + socklen_t i = 0; + + struct sctp_initmsg init; + struct sctp_event_subscribe events; + struct sockaddr *bindx_add_addr; + + DevAssert(sctp_data_p != NULL); + DevAssert(remote_ip_addr != NULL); + DevAssert(local_ip_addr != NULL); + DevCheck((socket_type == SOCK_STREAM), socket_type, 0, 0); + + SCTP_DEBUG("Creating socket type %d\n", socket_type); + + /* Create new socket */ + if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) { + SCTP_ERROR("Socket creation failed: %s\n", strerror(errno)); + return -1; + } + + /* Bind to provided IP adresses */ + bindx_add_addr = calloc(nb_local_addr, sizeof(struct sockaddr)); + for (i = 0; i < nb_local_addr; i++) + { + if (inet_pton(AF_INET, local_ip_addr[i], &((struct sockaddr_in*)&bindx_add_addr[i])->sin_addr.s_addr) != 1) + { + if (inet_pton(AF_INET6, local_ip_addr[i], &((struct sockaddr_in6*)&bindx_add_addr[i])->sin6_addr.s6_addr) != 1) + { + continue; + } else { + ((struct sockaddr_in6*)&bindx_add_addr[i])->sin6_port = 0; + bindx_add_addr[i].sa_family = AF_INET6; + } + } else { + ((struct sockaddr_in*)&bindx_add_addr[i])->sin_port = 0; + bindx_add_addr[i].sa_family = AF_INET; + } + } + + if (sctp_bindx(sd, bindx_add_addr, nb_local_addr, SCTP_BINDX_ADD_ADDR) < 0) + { + SCTP_ERROR("Socket bind failed: %s\n", strerror(errno)); + return -1; + } + + memset((void *)&init, 0, sizeof(struct sctp_initmsg)); + + /* Request a number of in/out streams */ + init.sinit_num_ostreams = SCTP_OUT_STREAMS; + init.sinit_max_instreams = SCTP_IN_STREAMS; + init.sinit_max_attempts = SCTP_MAX_ATTEMPTS; + + SCTP_DEBUG("Requesting (%d %d) (in out) streams\n", init.sinit_num_ostreams, + init.sinit_max_instreams); + + if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG, + &init, (socklen_t)sizeof(struct sctp_initmsg)) < 0) { + SCTP_ERROR("Setsockopt IPPROTO_SCTP_INITMSG failed: %s\n", + strerror(errno)); + return -1; + } + + /* Subscribe to all events */ + memset((void *)&events, 1, sizeof(struct sctp_event_subscribe)); + if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &events, + sizeof(struct sctp_event_subscribe)) < 0) { + SCTP_ERROR("Setsockopt IPPROTO_SCTP_EVENTS failed: %s\n", + strerror(errno)); + return -1; + } + + /* SOCK_STREAM socket type requires an explicit connect to the remote host + * address and port. + * Only use IPv4 for the first connection attempt + */ + { + struct sockaddr_in addr; + + memset(&addr, 0, sizeof(struct sockaddr_in)); + + if (inet_pton(AF_INET, remote_ip_addr, &addr.sin_addr.s_addr) != 1) { + SCTP_ERROR("Failed to convert ip address %s to network type\n", remote_ip_addr); + goto err; + } + + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + + SCTP_DEBUG("[%d] Sending explicit connect to %s:%u\n", sd, remote_ip_addr, + port); + + /* Connect to remote host and port */ + if (sctp_connectx(sd, (struct sockaddr *)&addr, 1, NULL) < 0) { + SCTP_ERROR("Connect to %s:%u failed: %s\n", remote_ip_addr, + port, strerror(errno)); + goto err; + } + } + + /* Get SCTP status */ + sctp_get_sockinfo(sd, &sctp_data_p->instreams, &sctp_data_p->outstreams, + &sctp_data_p->assoc_id); + + sctp_data_p->sd = sd; + + sctp_get_peeraddresses(sd, &sctp_data_p->remote_ip_addresses, &sctp_data_p->nb_remote_addresses); + sctp_get_localaddresses(sd, NULL, NULL); + + TAILQ_INIT(&sctp_data_p->sctp_queue); + + return sd; + +err: + if (sd != 0) { + close(sd); + } + return -1; +} diff --git a/openair-cn/SCTP/sctp_primitives_client.h b/openair-cn/SCTP/sctp_primitives_client.h new file mode 100644 index 0000000000..eb29bc8da2 --- /dev/null +++ b/openair-cn/SCTP/sctp_primitives_client.h @@ -0,0 +1,110 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdint.h> + +#include "sctp_eNB_defs.h" + +#ifndef SCTP_PRIMITIVES_CLIENT_H_ +#define SCTP_PRIMITIVES_CLIENT_H_ + +/** @defgroup _sctp_impl_ SCTP Layer Reference Implementation + * @ingroup _ref_implementation_ + * @{ + */ + +/** \brief SCTP recv callback prototype. Will be called every time a message is + * received on socket. + * \param assocId SCTP association ID + * \param stream SCTP stream on which data had been received + * \param buffer Pointer to data (should be freed by user) + * \param length Length of message received + * @return Execution result + */ +typedef int (*sctp_recv_callback)(uint32_t assocId, + uint32_t stream, + uint8_t *buffer, + uint32_t length); + +/** \brief SCTP connected callback prototype. Will be called once the + * association is ready. + * \param args argument provided by upper layer + * \param assocId SCTP association ID + * \param instreams Number of input streams negotiated with remote peer + * \param outstreams Number of output streams negotiated with remote peer + * @return Execution result + */ +typedef int (*sctp_connected_callback)(void *args, + uint32_t assocId, + uint32_t instreams, + uint32_t outstreams); + +/** \brief Perform association to a remote peer + * \param ip_addr Peer IPv4 address + * \param port Remote port to connect to + * \param args Upper layer args that will be provided to connected callback + * \param connected_callback Connected callback + * \param recv_callback Data received callback + * @return < 0 in case of failure + */ +int sctp_connect_to_remote_host(char *local_ip_addr[], + int nb_local_addr, + char *remote_ip_addr, + uint16_t port, + int socket_type, + sctp_data_t *sctp_data_p); + +/** \brief Send message over SCTP + * \param sctp_data_p Pointer to the SCTP desc + * \param ppid Payload Protocol Identifier + * \param stream SCTP stream on which data will be sent + * \param buffer Pointer to buffer + * \param length Buffer length + * @return < 0 in case of failure + */ +int sctp_send_msg(sctp_data_t *sctp_data_p, uint16_t ppid, uint16_t stream, + const uint8_t *buffer, const uint32_t length); + +/** \brief Flush the FIFO of messages from the socket + * \param sctp_data_p + * @return < 0 in case of failure + */ +int sctp_run(sctp_data_t *sctp_data_p); + +/** \brief Properly disconnect the peer + * \param assoc_id The SCTP association ID + * @return < 0 in case of failure + */ +void sctp_disconnect(uint32_t assoc_id); + +void sctp_terminate(void); + +/* @} */ +#endif /* SCTP_PRIMITIVES_CLIENT_H_ */ diff --git a/openair-cn/SCTP/sctp_primitives_server.c b/openair-cn/SCTP/sctp_primitives_server.c new file mode 100644 index 0000000000..6000e1b755 --- /dev/null +++ b/openair-cn/SCTP/sctp_primitives_server.c @@ -0,0 +1,647 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file sctp_primitives_server.c + * \brief Main server primitives + * \author Sebastien ROUX + * \date 2013 + * \version 1.0 + * @ingroup _sctp + */ + +#include <pthread.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> +#include <netinet/sctp.h> + +#include <arpa/inet.h> + +#include "assertions.h" + +#include "intertask_interface.h" +#include "sctp_primitives_server.h" +#include "mme_config.h" +#include "conversions.h" + +#include "sctp_common.h" +#include "sctp_itti_messaging.h" + +#define SCTP_DUMP_LIST + +#define SCTP_RC_ERROR -1 +#define SCTP_RC_NORMAL_READ 0 +#define SCTP_RC_DISCONNECT 1 + +struct sctp_association_s { + struct sctp_association_s *next_assoc; ///< Next association in the list + struct sctp_association_s *previous_assoc; ///< Previous association in the list + int sd; ///< Socket descriptor + uint32_t ppid; ///< Payload protocol Identifier + uint16_t instreams; ///< Number of input streams negociated for this connection + uint16_t outstreams; ///< Number of output strams negotiated for this connection + int32_t assoc_id; ///< SCTP association id for the connection + uint32_t messages_recv; ///< Number of messages received on this connection + uint32_t messages_sent; ///< Number of messages sent on this connection + + struct sockaddr *peer_addresses; ///< A list of peer addresses + int nb_peer_addresses; +}; + +struct sctp_descriptor_s { + // List of connected peers + struct sctp_association_s *available_connections_head; + struct sctp_association_s *available_connections_tail; + + uint32_t number_of_connections; + uint16_t nb_instreams; + uint16_t nb_outstreams; +}; + +struct sctp_arg_s { + int sd; + uint32_t ppid; +}; + +static struct sctp_descriptor_s sctp_desc; + +// Thread used to handle sctp messages +static pthread_t assoc_thread; + +// LOCAL FUNCTIONS prototypes +void *sctp_receiver_thread(void *args_p); +static int sctp_send_msg(int32_t sctp_assoc_id, uint16_t stream, + const uint8_t *buffer, const uint32_t length); + +// Association list related local functions prototypes +static struct sctp_association_s *sctp_is_assoc_in_list(int32_t assoc_id); +static struct sctp_association_s *sctp_add_new_peer(void); +static int sctp_handle_com_down(uint32_t assoc_id); +static void sctp_dump_list(void); + +static struct sctp_association_s *sctp_add_new_peer(void) +{ + struct sctp_association_s *new_sctp_descriptor = NULL; + + new_sctp_descriptor = calloc(1, sizeof(struct sctp_association_s)); + + if (new_sctp_descriptor == NULL) { + SCTP_ERROR("Failed to allocate memory for new peer (%s:%d)\n", + __FILE__, __LINE__); + return NULL; + } + new_sctp_descriptor->next_assoc = NULL; + new_sctp_descriptor->previous_assoc = NULL; + + if (sctp_desc.available_connections_tail == NULL) { + sctp_desc.available_connections_head = new_sctp_descriptor; + sctp_desc.available_connections_tail = sctp_desc.available_connections_head; + } else { + new_sctp_descriptor->previous_assoc = sctp_desc.available_connections_tail; + sctp_desc.available_connections_tail->next_assoc = new_sctp_descriptor; + sctp_desc.available_connections_tail = new_sctp_descriptor; + } + sctp_desc.number_of_connections++; + + sctp_dump_list(); + + return new_sctp_descriptor; +} + +static struct sctp_association_s *sctp_is_assoc_in_list(int32_t assoc_id) +{ + struct sctp_association_s *assoc_desc; + if (assoc_id < 0) { + return NULL; + } + for (assoc_desc = sctp_desc.available_connections_head; + assoc_desc; + assoc_desc = assoc_desc->next_assoc) { + if (assoc_desc->assoc_id == assoc_id) { + break; + } + } + return assoc_desc; +} + +static int sctp_remove_assoc_from_list(int32_t assoc_id) +{ + struct sctp_association_s *assoc_desc; + /* Association not in the list */ + if ((assoc_desc = sctp_is_assoc_in_list(assoc_id)) == NULL) { + return -1; + } + + if (assoc_desc->next_assoc == NULL) { + if (assoc_desc->previous_assoc == NULL) { + /* Head and tail */ + sctp_desc.available_connections_head = sctp_desc.available_connections_tail = NULL; + } else { + /* Not head but tail */ + sctp_desc.available_connections_tail = assoc_desc->previous_assoc; + assoc_desc->previous_assoc->next_assoc = NULL; + } + } else { + if (assoc_desc->previous_assoc == NULL) { + /* Head but not tail */ + sctp_desc.available_connections_head = assoc_desc->next_assoc; + assoc_desc->next_assoc->previous_assoc = NULL; + } else { + /* Not head and not tail */ + assoc_desc->previous_assoc->next_assoc = assoc_desc->next_assoc; + assoc_desc->next_assoc->previous_assoc = assoc_desc->previous_assoc; + } + } + free(assoc_desc); + sctp_desc.number_of_connections --; + return 0; +} + +static void sctp_dump_assoc(struct sctp_association_s *sctp_assoc_p) +{ +#if defined(SCTP_DUMP_LIST) + int i; + + if (sctp_assoc_p == NULL) { + return; + } + + SCTP_DEBUG("sd : %d\n", sctp_assoc_p->sd); + SCTP_DEBUG("input streams: %d\n", sctp_assoc_p->instreams); + SCTP_DEBUG("out streams : %d\n", sctp_assoc_p->outstreams); + SCTP_DEBUG("assoc_id : %d\n", sctp_assoc_p->assoc_id); + SCTP_DEBUG("peer address :\n"); + for (i = 0; i < sctp_assoc_p->nb_peer_addresses; i++) { + char address[40]; + + memset(address, 0, sizeof(address)); + + if (inet_ntop(sctp_assoc_p->peer_addresses[i].sa_family, + sctp_assoc_p->peer_addresses[i].sa_data, address, sizeof(address)) != NULL) + { + SCTP_DEBUG(" - [%s]\n", address); + } + } + +#else + sctp_assoc_p = sctp_assoc_p; +#endif +} + +static void sctp_dump_list(void) +{ +#if defined(SCTP_DUMP_LIST) + struct sctp_association_s *sctp_assoc_p; + + sctp_assoc_p = sctp_desc.available_connections_head; + + SCTP_DEBUG("SCTP list contains %d associations\n", sctp_desc.number_of_connections); + + while (sctp_assoc_p != NULL) { + sctp_dump_assoc(sctp_assoc_p); + sctp_assoc_p = sctp_assoc_p->next_assoc; + } +#else + sctp_dump_assoc(NULL); +#endif +} + +static int sctp_send_msg(int32_t sctp_assoc_id, uint16_t stream, + const uint8_t *buffer, const uint32_t length) +{ + struct sctp_association_s *assoc_desc = NULL; + + DevAssert(buffer != NULL); + + if ((assoc_desc = sctp_is_assoc_in_list(sctp_assoc_id)) == NULL) { + SCTP_DEBUG("This assoc id has not been fount in list (%d)\n", + sctp_assoc_id); + return -1; + } + if (assoc_desc->sd == -1) { + /* The socket is invalid may be closed. + */ + return -1; + } + + SCTP_DEBUG("[%d][%d] Sending buffer %p of %d bytes on stream %d with ppid %d\n", + assoc_desc->sd, sctp_assoc_id, buffer, + length, stream, assoc_desc->ppid); + + /* Send message_p on specified stream of the sd association */ + if (sctp_sendmsg(assoc_desc->sd, + (const void *)buffer, + length, + NULL, + 0, + assoc_desc->ppid, 0, stream, 0, 0) < 0) { + SCTP_ERROR("send: %s:%d", strerror(errno), errno); + return -1; + } + + assoc_desc->messages_sent++; + + SCTP_DEBUG("Successfully sent %d bytes on stream %d\n", length, stream); + + return 0; +} + +static int sctp_create_new_listener(SctpInit *init_p) +{ + struct sctp_event_subscribe event; + struct sockaddr *addr; + + struct sctp_arg_s *sctp_arg_p; + + uint16_t i = 0, j; + int sd; + int used_addresses = 0; + + DevAssert(init_p != NULL); + + if (init_p->ipv4 == 0 && init_p->ipv6 == 0) { + SCTP_ERROR("Illegal IP configuration upper layer should request at" + "least ipv4 and/or ipv6 config\n"); + return -1; + } + + if ((used_addresses = init_p->nb_ipv4_addr + init_p->nb_ipv6_addr) == 0) { + SCTP_WARN("No address provided...\n"); + return -1; + } + + addr = calloc(used_addresses, sizeof(struct sockaddr)); + + SCTP_DEBUG("Creating new listen socket on port %u with\n", init_p->port); + if (init_p->ipv4 == 1) { + struct sockaddr_in *ip4_addr; + + SCTP_DEBUG("ipv4 addresses:\n"); + for (i = 0; i < init_p->nb_ipv4_addr; i++) { + SCTP_DEBUG("\t- "IPV4_ADDR"\n", + IPV4_ADDR_FORMAT(init_p->ipv4_address[i])); + ip4_addr = (struct sockaddr_in *)&addr[i]; + ip4_addr->sin_family = AF_INET; + ip4_addr->sin_port = htons(init_p->port); + ip4_addr->sin_addr.s_addr = init_p->ipv4_address[i]; + } + } + if (init_p->ipv6 == 1) { + struct sockaddr_in6 *ip6_addr; + + SCTP_DEBUG("ipv6 addresses:\n"); + for (j = 0; j < init_p->nb_ipv6_addr; j++) { + SCTP_DEBUG("\t- %s\n", init_p->ipv6_address[j]); + ip6_addr = (struct sockaddr_in6 *)&addr[i + j]; + ip6_addr->sin6_family = AF_INET6; + ip6_addr->sin6_port = htons(init_p->port); + if (inet_pton(AF_INET6, init_p->ipv6_address[j], + ip6_addr->sin6_addr.s6_addr) <= 0) { + SCTP_WARN("Provided ipv6 address %s is not valid\n", + init_p->ipv6_address[j]); + } + } + } + + if ((sd = socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP)) < 0) { + SCTP_ERROR("socket: %s:%d\n", strerror(errno), errno); + return -1; + } + + memset((void *)&event, 1, sizeof(struct sctp_event_subscribe)); + if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)) < 0) { + SCTP_ERROR("setsockopt: %s:%d\n", strerror(errno), errno); + return -1; + } + + /* Some pre-bind socket configuration */ + if (sctp_set_init_opt(sd, sctp_desc.nb_instreams, sctp_desc.nb_outstreams, + 0, 0) < 0) + { + goto err; + } + + if (sctp_bindx(sd, addr, used_addresses, SCTP_BINDX_ADD_ADDR) != 0) { + SCTP_ERROR("sctp_bindx: %s:%d\n", strerror(errno), errno); + return -1; + } + if (listen(sd, 5) < 0) { + SCTP_ERROR("listen: %s:%d\n", strerror(errno), errno); + return -1; + } + + if ((sctp_arg_p = malloc(sizeof(struct sctp_arg_s))) == NULL) { + return -1; + } + sctp_arg_p->sd = sd; + sctp_arg_p->ppid = init_p->ppid; + + if (pthread_create(&assoc_thread, NULL, &sctp_receiver_thread, + (void *)sctp_arg_p) < 0) { + SCTP_ERROR("pthread_create: %s:%d\n", strerror(errno), errno); + return -1; + } + + return sd; +err: + if (sd != -1) { + close(sd); + sd = -1; + } + return -1; +} + +static +inline int sctp_read_from_socket(int sd, int ppid) +{ + int flags = 0, n; + socklen_t from_len; + struct sctp_sndrcvinfo sinfo; + + struct sockaddr_in addr; + uint8_t buffer[SCTP_RECV_BUFFER_SIZE]; + + if (sd < 0) { + return -1; + } + + memset((void *)&addr, 0, sizeof(struct sockaddr_in)); + from_len = (socklen_t)sizeof(struct sockaddr_in); + memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo)); + n = sctp_recvmsg(sd, (void *)buffer, SCTP_RECV_BUFFER_SIZE, + (struct sockaddr *)&addr, &from_len, + &sinfo, &flags); + if (n < 0) { + SCTP_DEBUG("An error occured during read\n"); + SCTP_ERROR("sctp_recvmsg: %s:%d\n", strerror(errno), errno); + return SCTP_RC_ERROR; + } + if (flags & MSG_NOTIFICATION) { + union sctp_notification *snp; + snp = (union sctp_notification *)buffer; + + /* Client deconnection */ + if (SCTP_SHUTDOWN_EVENT == snp->sn_header.sn_type) { + return sctp_handle_com_down(snp->sn_shutdown_event.sse_assoc_id); + } + /* Association has changed. */ + else if (SCTP_ASSOC_CHANGE == snp->sn_header.sn_type) { + struct sctp_assoc_change *sctp_assoc_changed; + sctp_assoc_changed = &snp->sn_assoc_change; + + SCTP_DEBUG("Client association changed: %d\n", sctp_assoc_changed->sac_state); + /* New physical association requested by a peer */ + switch (sctp_assoc_changed->sac_state) { + case SCTP_COMM_UP: { + struct sctp_association_s *new_association; + + sctp_get_sockinfo(sd, NULL, NULL, NULL); + + SCTP_DEBUG("New connection\n"); + if ((new_association = sctp_add_new_peer()) == NULL) { + // TODO: handle this case + DevMessage("Unexpected error...\n"); + return SCTP_RC_ERROR; + } else { + new_association->sd = sd; + new_association->ppid = ppid; + new_association->instreams = sctp_assoc_changed->sac_inbound_streams; + new_association->outstreams = sctp_assoc_changed->sac_outbound_streams; + new_association->assoc_id = sctp_assoc_changed->sac_assoc_id; + + sctp_get_localaddresses(sd, NULL, NULL); + sctp_get_peeraddresses(sd, &new_association->peer_addresses, + &new_association->nb_peer_addresses); + + if (sctp_itti_send_new_association( + new_association->assoc_id, new_association->instreams, + new_association->outstreams) < 0) + { + SCTP_ERROR("Failed to send message to S1AP\n"); + return SCTP_RC_ERROR; + } + } + } break; + default: + break; + } + } + } else { + /* Data payload received */ + struct sctp_association_s *association; + + if ((association = sctp_is_assoc_in_list(sinfo.sinfo_assoc_id)) == NULL) { + // TODO: handle this case + return SCTP_RC_ERROR; + } + association->messages_recv++; + + if (ntohl(sinfo.sinfo_ppid) != association->ppid) { + /* Mismatch in Payload Protocol Identifier, + * may be we received unsollicited traffic from stack other than S1AP. + */ + SCTP_ERROR("Received data from peer with unsollicited PPID %d, expecting %d\n", + ntohl(sinfo.sinfo_ppid), association->ppid); + return SCTP_RC_ERROR; + } + + SCTP_DEBUG("[%d][%d] Msg of length %d received from port %u, on stream %d, PPID %d\n", + sinfo.sinfo_assoc_id, sd, n, ntohs(addr.sin_port), + sinfo.sinfo_stream, ntohl(sinfo.sinfo_ppid)); + + sctp_itti_send_new_message_ind(n, buffer, sinfo.sinfo_assoc_id, sinfo.sinfo_stream, + association->instreams, association->outstreams); + } + return SCTP_RC_NORMAL_READ; +} + +static int sctp_handle_com_down(uint32_t assoc_id) +{ + SCTP_DEBUG("Sending close connection for assoc_id %u\n", assoc_id); + + if (sctp_itti_send_com_down_ind(assoc_id) < 0) { + SCTP_ERROR("Failed to send message to TASK_S1AP\n"); + } + if (sctp_remove_assoc_from_list(assoc_id) < 0) { + SCTP_ERROR("Failed to find client in list\n"); + } + + return SCTP_RC_DISCONNECT; +} + +void *sctp_receiver_thread(void *args_p) +{ + struct sctp_arg_s *sctp_arg_p; + + /* maximum file descriptor number */ + int fdmax, clientsock, i; + /* master file descriptor list */ + fd_set master; + /* temp file descriptor list for select() */ + fd_set read_fds; + + if ((sctp_arg_p = (struct sctp_arg_s *)args_p) == NULL) { + pthread_exit(NULL); + } + + /* clear the master and temp sets */ + FD_ZERO(&master); + FD_ZERO(&read_fds); + + FD_SET(sctp_arg_p->sd, &master); + fdmax = sctp_arg_p->sd; /* so far, it's this one*/ + + while(1) { + + memcpy(&read_fds, &master, sizeof(master)); + + if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) { + SCTP_ERROR("[%d] Select() error: %s", + sctp_arg_p->sd, strerror(errno)); + free(args_p); + pthread_exit(NULL); + } + + for (i = 0; i <= fdmax; i++) { + if (FD_ISSET(i, &read_fds)) { + if (i == sctp_arg_p->sd) { + /* There is data to read on listener socket. This means we have to accept + * the connection. + */ + if ((clientsock = accept(sctp_arg_p->sd, NULL, NULL)) < 0) { + SCTP_ERROR("[%d] accept: %s:%d\n", sctp_arg_p->sd, strerror(errno), errno); + free(args_p); + pthread_exit(NULL); + } else { + FD_SET(clientsock, &master); /* add to master set */ + if(clientsock > fdmax) + { + /* keep track of the maximum */ + fdmax = clientsock; + } + } + } else { + int ret; + + /* Read from socket */ + ret = sctp_read_from_socket(i, sctp_arg_p->ppid); + + /* When the socket is disconnected we have to update + * the fd_set. + */ + if (ret == SCTP_RC_DISCONNECT) { + /* Remove the socket from the FD set and update the max sd */ + FD_CLR(i, &master); + if (i == fdmax) { + while (FD_ISSET(fdmax, &master) == FALSE) + fdmax -= 1; + } + } + } + } + } + } + free(args_p); + return NULL; +} + +static void *sctp_intertask_interface(void *args_p) +{ + intertask_interface_mark_task_ready(TASK_SCTP); + + while(1) { + MessageDef *received_message_p; + receive_msg(TASK_SCTP, &received_message_p); + switch(received_message_p->header.messageId) { + case SCTP_INIT_MSG: { + SCTP_DEBUG("Received SCTP_INIT_MSG\n"); + /* We received a new connection request */ + if (sctp_create_new_listener(&received_message_p->msg.sctpInit) < 0) { + /* SCTP socket creation or bind failed... */ + SCTP_ERROR("Failed to create new SCTP listener\n"); + } + } break; + case SCTP_CLOSE_ASSOCIATION: { + + } break; + case SCTP_NEW_DATA_REQ: { + SctpNewDataReq *sctpNewS1APDataReq; + sctpNewS1APDataReq = &received_message_p->msg.sctpNewDataReq; + if (sctp_send_msg(sctpNewS1APDataReq->assocId, + sctpNewS1APDataReq->stream, + sctpNewS1APDataReq->buffer, + sctpNewS1APDataReq->bufLen) < 0) { + SCTP_ERROR("Failed to send message over SCTP\n"); + } + } break; + case MESSAGE_TEST: { + int i = 10000; + while(i--); + } break; + default: { + SCTP_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int sctp_init(const mme_config_t *mme_config_p) +{ + SCTP_DEBUG("Initializing SCTP task interface\n"); + + memset(&sctp_desc, 0, sizeof(struct sctp_descriptor_s)); + + /* Number of streams from configuration */ + sctp_desc.nb_instreams = mme_config_p->sctp_config.in_streams; + sctp_desc.nb_outstreams = mme_config_p->sctp_config.out_streams; + + if (intertask_interface_create_task(TASK_SCTP, &sctp_intertask_interface, + NULL) < 0) { + SCTP_ERROR("create task failed"); + SCTP_DEBUG("Initializing SCTP task interface: FAILED\n"); + return -1; + } + SCTP_DEBUG("Initializing SCTP task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/SCTP/sctp_primitives_server.h b/openair-cn/SCTP/sctp_primitives_server.h new file mode 100644 index 0000000000..95e6b0aa50 --- /dev/null +++ b/openair-cn/SCTP/sctp_primitives_server.h @@ -0,0 +1,70 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +/*! \file sctp_primitives_server.c + * \brief Main server primitives + * \author Sebastien ROUX + * \date 2013 + * \version 1.0 + * @ingroup _sctp + * @{ + */ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "mme_config.h" + +#if !defined(HAVE_LIBSCTP) +# error "You must install libsctp-dev" +#endif + +#include <netinet/in.h> +#include <netinet/sctp.h> + +#ifndef SCTP_PRIMITIVES_SERVER_H_ +#define SCTP_PRIMITIVES_SERVER_H_ + +/** \brief SCTP data received callback + \param buffer pointer to buffer received + \param length pointer to the length of buffer + **/ +typedef void (*sctp_recv_callback)(uint8_t *buffer, uint32_t length); + +/** \brief SCTP Init function. Initialize SCTP layer + \param mme_config The global MME configuration structure + @returns -1 on error, 0 otherwise. + **/ +int sctp_init(const mme_config_t *mme_config_p); + +#endif /* SCTP_PRIMITIVES_SERVER_H_ */ + +/* @} */ diff --git a/openair-cn/SECU/Makefile.am b/openair-cn/SECU/Makefile.am new file mode 100644 index 0000000000..173b3f2766 --- /dev/null +++ b/openair-cn/SECU/Makefile.am @@ -0,0 +1,12 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/COMMON + +noinst_LTLIBRARIES = libsecu.la + +libsecu_la_LDFLAGS = -all-static +libsecu_la_SOURCES = \ + kdf.c \ + key_nas_deriver.c \ + nas_stream_eea2.c \ + nas_stream_eia2.c \ No newline at end of file diff --git a/openair-cn/SECU/Makefile.eNB b/openair-cn/SECU/Makefile.eNB new file mode 100644 index 0000000000..902f741909 --- /dev/null +++ b/openair-cn/SECU/Makefile.eNB @@ -0,0 +1,38 @@ +libsecu_OBJECTS = \ + kdf.o \ + key_nas_deriver.o \ + nas_stream_eea2.o \ + nas_stream_eia2.o + +-include .deps/*.d + +.PHONY = depdir + +CFLAGS = \ + -I../COMMON \ + -I../UTILS \ + -DENB_MODE \ + -DENABLE_USE_MME \ + -DUSER_MODE \ + -O2 \ + -g \ + -Wall \ + -Werror=implicit-function-declaration + +$(libsecu_OBJECTS): %.o : %.c + $(CC) -c $(CFLAGS) -o $@ $< + @if ! test -d ".deps/" ; then mkdir -p .deps; fi + @$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d + @mv -f .deps/$*.d .deps/$*.d.tmp + @sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d + @sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d + @rm -f .deps/$*.d.tmp + +libsecu.a: $(libsecu_OBJECTS) + $(AR) rcvs $@ $(libsecu_OBJECTS) + +clean: + rm -f $(libsecu_OBJECTS) + rm -rf .deps/ + rm -f libsecu.a \ No newline at end of file diff --git a/openair-cn/SECU/kdf.c b/openair-cn/SECU/kdf.c new file mode 100644 index 0000000000..8194638064 --- /dev/null +++ b/openair-cn/SECU/kdf.c @@ -0,0 +1,45 @@ +#include <stdlib.h> +#include <stdint.h> + +#include <nettle/hmac.h> + +#include "security_types.h" +#include "secu_defs.h" + +inline +void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key, + const uint32_t key_length, uint8_t **out, uint32_t out_length) +{ + struct hmac_sha256_ctx ctx; + + uint8_t *buffer; + + buffer = malloc(sizeof(uint8_t) * out_length); + + hmac_sha256_set_key(&ctx, key_length, key); + hmac_sha256_update(&ctx, s_length, s); + hmac_sha256_digest(&ctx, out_length, buffer); + + *out = buffer; +} + +int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB) +{ + uint8_t string[7]; + + /* FC */ + string[0] = FC_KENB; + /* P0 = Uplink NAS count */ + string[1] = (nas_count & 0xff000000) >> 24; + string[2] = (nas_count & 0x00ff0000) >> 16; + string[3] = (nas_count & 0x0000ff00) >> 8; + string[4] = (nas_count & 0x000000ff); + + /* Length of NAS count */ + string[5] = 0x00; + string[6] = 0x04; + + kdf(string, 7, kasme, 32, keNB, 32); + + return 0; +} diff --git a/openair-cn/SECU/key_nas_deriver.c b/openair-cn/SECU/key_nas_deriver.c new file mode 100644 index 0000000000..c5c0def424 --- /dev/null +++ b/openair-cn/SECU/key_nas_deriver.c @@ -0,0 +1,58 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "security_types.h" +#include "secu_defs.h" + +/*! + * @brief Derive the kNASenc from kasme and perform truncate on the generated key to + * reduce his size to 128 bits. Definition of the derivation function can + * be found in 3GPP TS.33401 #A.7 + * @param[in] nas_alg_type NAS algorithm distinguisher + * @param[in] nas_enc_alg_id NAS encryption/integrity algorithm identifier. + * Possible values are: + * - 0 for EIA0 algorithm (Null Integrity Protection algorithm) + * - 1 for 128-EIA1 SNOW 3G + * - 2 for 128-EIA2 AES + * @param[in] kasme Key for MME as provided by AUC + * @param[out] knas Pointer to reference where output of KDF will be stored. + * NOTE: knas is dynamically allocated by the KDF function + */ +int derive_key_nas(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id, + const uint8_t kasme[32], uint8_t **knas) +{ + uint8_t s[7]; +#if defined(SECU_DEBUG) + int i; +#endif + + /* FC */ + s[0] = FC_ALG_KEY_DER; + + /* P0 = algorithm type distinguisher */ + s[1] = (uint8_t)(nas_alg_type & 0xFF); + + /* L0 = length(P0) = 1 */ + s[2] = 0x00; + s[3] = 0x01; + + /* P1 */ + s[4] = nas_enc_alg_id; + + /* L1 = length(P1) = 1 */ + s[5] = 0x00; + s[6] = 0x01; + +#if defined(SECU_DEBUG) + for (i = 0; i < 7; i ++) { + printf("0x%02x ", s[i]); + } + printf("\n"); +#endif + + kdf(s, 7, kasme, 32, knas, 32); + + return 0; +} diff --git a/openair-cn/SECU/key_nas_encryption.c b/openair-cn/SECU/key_nas_encryption.c new file mode 100644 index 0000000000..6ce7729c9b --- /dev/null +++ b/openair-cn/SECU/key_nas_encryption.c @@ -0,0 +1,45 @@ +#include "secu_defs.h" + +/*! + * Derive the kNASenc from kasme and perform truncate on the generated key to + * reduce his size to 128 bits. Definition of the derivation function can + * be found in 3GPP TS.33401 #A.7 + * @param[in] nas_alg_type NAS algorithm distinguisher + * @param[in] nas_enc_alg_id NAS encryption/integrity algorithm identifier. + * Possible values are: + * - 0 for EIA0 algorithm (Null Integrity Protection algorithm) + * - 1 for 128-EIA1 SNOW 3G + * - 2 for 128-EIA2 AES + * @param[in] kasme Key for MME as provided by AUC + * @param[out] knas Truncated ouput key as derived by KDF + */ +int derive_key_nas(algorithm_distinguisher_t nas_alg_type, uint8_t nas_enc_alg_id, + uint8_t kasme[32], uint8_t knas[16]) +{ + uint8_t s[7]; + uint8_t knas_temp[32]; + + /* FC */ + s[0] = 0x15; + + /* P0 = algorithm type distinguisher */ + s[1] = nas_alg_type & 0xFF; + + /* L0 = length(P0) = 1 */ + s[2] = 0x00; + s[3] = 0x01; + + /* P1 */ + s[4] = nas_enc_alg_id; + + /* L1 = length(P1) = 1 */ + s[5] = 0x00; + s[6] = 0x01; + + kdf(s, 7, kasme, 32, knas_temp, 32); + + /* Truncate the generate key to 128 bits */ + memcpy(knas, knas_temp, 16); + + return 0; +} diff --git a/openair-cn/SECU/nas_stream_eea2.c b/openair-cn/SECU/nas_stream_eea2.c new file mode 100644 index 0000000000..ed6ed175a8 --- /dev/null +++ b/openair-cn/SECU/nas_stream_eea2.c @@ -0,0 +1,72 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include <nettle/nettle-meta.h> +#include <nettle/aes.h> +#include <nettle/ctr.h> + +#include "assertions.h" +#include "conversions.h" +#include "secu_defs.h" + +// #define SECU_DEBUG + +int nas_stream_encrypt_eea2(nas_stream_cipher_t *stream_cipher, uint8_t **out) +{ + uint8_t m[16]; + uint32_t local_count; + + void *ctx; + uint8_t *data; + + uint32_t zero_bit = 0; + uint32_t byte_length; + + DevAssert(stream_cipher != NULL); + DevAssert(out != NULL); + + zero_bit = stream_cipher->blength & 0x7; + + byte_length = stream_cipher->blength >> 3; + if (zero_bit > 0) + byte_length += 1; + + ctx = malloc(nettle_aes128.context_size); + data = malloc(byte_length); + + local_count = hton_int32(stream_cipher->count); + + memset(m, 0, sizeof(m)); + memcpy(&m[0], &local_count, 4); + m[4] = ((stream_cipher->bearer & 0x1F) << 3) | + ((stream_cipher->direction & 0x01) << 2); + /* Other bits are 0 */ + +#if defined(SECU_DEBUG) + { + int i; + printf("Blength: %u, Zero bits: %u\n", stream_cipher->blength, zero_bit); + for (i = 0; i < sizeof(m); i++) + printf("0x%02x ", m[i]); + printf("\n"); + } +#endif + + nettle_aes128.set_encrypt_key(ctx, stream_cipher->key_length, + stream_cipher->key); + + nettle_ctr_crypt(ctx, nettle_aes128.encrypt, + nettle_aes128.block_size, m, + byte_length, data, stream_cipher->message); + + if (zero_bit > 0) + data[byte_length - 1] = data[byte_length - 1] & (uint8_t)(0xFF << (8 - zero_bit)); + + *out = data; + + free(ctx); + + return 0; +} diff --git a/openair-cn/SECU/nas_stream_eia2.c b/openair-cn/SECU/nas_stream_eia2.c new file mode 100644 index 0000000000..5942498813 --- /dev/null +++ b/openair-cn/SECU/nas_stream_eia2.c @@ -0,0 +1,89 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "secu_defs.h" + +#include <openssl/aes.h> +#include <openssl/cmac.h> +#include <openssl/evp.h> + +#include "assertions.h" +#include "conversions.h" + +// #define SECU_DEBUG + +/*! + * @brief Create integrity cmac t for a given message. + * @param[in] stream_cipher Structure containing various variables to setup encoding + * @param[out] out For EIA2 the output string is 32 bits long + */ +int nas_stream_encrypt_eia2(nas_stream_cipher_t *stream_cipher, uint8_t out[4]) +{ + uint8_t *m; + uint32_t local_count; + size_t size = 4; + + uint8_t data[16]; + + CMAC_CTX *cmac_ctx; + + uint32_t zero_bit = 0; + uint32_t m_length; + + DevAssert(stream_cipher != NULL); + DevAssert(stream_cipher->key != NULL); + DevAssert(out != NULL); + + memset(data, 0, 16); + + zero_bit = stream_cipher->blength & 0x7; + + m_length = stream_cipher->blength >> 3; + if (zero_bit > 0) + m_length += 1; + + local_count = hton_int32(stream_cipher->count); + + m = calloc(m_length + 8, sizeof(uint8_t)); + + memcpy(&m[0], &local_count, 4); + m[4] = ((stream_cipher->bearer & 0x1F) << 3) | ((stream_cipher->direction & 0x01) << 2); + + memcpy(&m[8], stream_cipher->message, m_length); + +#if defined(SECU_DEBUG) + { + int i; + printf("Byte length: %u, Zero bits: %u\nm: ", m_length + 8, zero_bit); + for (i = 0; i < m_length + 8; i++) + printf("%02x", m[i]); + printf("\n"); + } +#endif + + cmac_ctx = CMAC_CTX_new(); + + CMAC_Init(cmac_ctx, stream_cipher->key, stream_cipher->key_length, EVP_aes_128_cbc(), NULL); + CMAC_Update(cmac_ctx, m, m_length + 8); + + CMAC_Final(cmac_ctx, data, &size); + + CMAC_CTX_free(cmac_ctx); + +#if defined(SECU_DEBUG) + { + int i; + printf("out: "); + for (i = 0; i < 16; i++) + printf("%02x", data[i]); + printf("\n"); + } +#endif + + memcpy(out, data, 4); + free(m); + + return 0; +} diff --git a/openair-cn/SECU/secu_defs.h b/openair-cn/SECU/secu_defs.h new file mode 100644 index 0000000000..8987f55edd --- /dev/null +++ b/openair-cn/SECU/secu_defs.h @@ -0,0 +1,57 @@ +#include "security_types.h" + +#ifndef SECU_DEFS_H_ +#define SECU_DEFS_H_ + +#define EIA0_ALG_ID 0x00 +#define EIA1_128_ALG_ID 0x01 +#define EIA2_128_ALG_ID 0x02 + +inline +void kdf(const uint8_t *s, const uint32_t s_length, const uint8_t *key, + const uint32_t key_length, uint8_t **out, uint32_t out_length); + +int derive_keNB(const uint8_t kasme[32], const uint32_t nas_count, uint8_t **keNB); + +int derive_key_nas(algorithm_type_dist_t nas_alg_type, uint8_t nas_enc_alg_id, + const uint8_t kasme[32], uint8_t **knas); + +#define derive_key_nas_enc(aLGiD, kASME, kNAS) \ + derive_key_nas(NAS_ENC_ALG, aLGiD, kASME, kNAS) + +#define derive_key_nas_int(aLGiD, kASME, kNAS) \ + derive_key_nas(NAS_INT_ALG, aLGiD, kASME, kNAS) + +#define derive_key_rrc_enc(aLGiD, kASME, kNAS) \ + derive_key_nas(RRC_ENC_ALG, aLGiD, kASME, kNAS) + +#define derive_key_rrc_int(aLGiD, kASME, kNAS) \ + derive_key_nas(RRC_INT_ALG, aLGiD, kASME, kNAS) + +#define derive_key_up_enc(aLGiD, kASME, kNAS) \ + derive_key_nas(UP_ENC_ALG, aLGiD, kASME, kNAS) + +#define derive_key_up_int(aLGiD, kASME, kNAS) \ + derive_key_nas(UP_INT_ALG, aLGiD, kASME, kNAS) + +#define SECU_DIRECTION_UPLINK 0 +#define SECU_DIRECTION_DOWNLINK 1 + +typedef struct { + uint8_t *key; + uint32_t key_length; + uint32_t count; + uint8_t bearer; + uint8_t direction; + uint8_t *message; + /* length in bits */ + uint32_t blength; +} nas_stream_cipher_t; + +int nas_stream_encrypt_eea2(nas_stream_cipher_t *stream_cipher, uint8_t **out); + +int nas_stream_encrypt_eia2(nas_stream_cipher_t *stream_cipher, uint8_t out[4]); + +#undef SECU_DEBUG + +#endif /* SECU_DEFS_H_ */ diff --git a/openair-cn/SGI/Makefile.am b/openair-cn/SGI/Makefile.am new file mode 100644 index 0000000000..cdbdc68a39 --- /dev/null +++ b/openair-cn/SGI/Makefile.am @@ -0,0 +1,29 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE \ + -I$(top_srcdir)/INTERTASK_INTERFACE + +noinst_LTLIBRARIES = libsgi.la +libsgi_la_LDFLAGS = -all-static +libsgi_la_SOURCES = \ + sgi_task.c sgi.h \ + sgi_socket.c \ + sgi_egress.c \ + sgi_util.c + +if ENABLE_USE_PCAP_FOR_SGI + libsgi_la_SOURCES += sgi_pcap.c \ + /usr/lib/libpcap.a + +endif + + +if ENABLE_USE_NETFILTER_FOR_SGI + libsgi_la_SOURCES += sgi_nf.c \ + /usr/lib/libnetfilter_queue.a \ + /usr/lib/libnfnetlink.la +endif + + diff --git a/openair-cn/SGI/sgi.h b/openair-cn/SGI/sgi.h new file mode 100755 index 0000000000..7c042e7e39 --- /dev/null +++ b/openair-cn/SGI/sgi.h @@ -0,0 +1,241 @@ +#ifndef SGI_H_ +#define SGI_H_ + +#include <net/ethernet.h> +#include <netinet/in.h> +#include <pthread.h> + #include <stdio.h> + +#ifdef ENABLE_USE_PCAP_FOR_SGI +#include <pcap.h> +#endif + +//#define SGI_TEST +// Packets include a ethernet header if SGI_PF_PACKET is defined +#define SGI_PF_PACKET + +#include "common_types.h" +#include "hashtable.h" +#include "obj_hashtable.h" +#include "sgw_lite_ie_defs.h" +#include "ip_forward_messages_types.h" + +//----------------------------------------------------------------------------- +#ifndef SGI_IF_DEBUG +# define SGI_IF_DEBUG(x, args...) do { fprintf(stdout, "[SGI_IF][D]"x, ##args); } \ + while(0) +#endif +#ifndef SGI_IF_ERROR +# define SGI_IF_ERROR(x, args...) do { fprintf(stderr, "[SGI_IF][E]"x, ##args); } \ + while(0) +#endif +#ifndef SGI_IF_WARNING +# define SGI_IF_WARNING(x, args...) do { fprintf(stderr, "[SGI_IF][W]"x, ##args); } \ + while(0) +#endif + +// refer to 3GPP TS 23.203 V10.6.0 (2012-03) page 33 +//#define MAX_DEFINED_QCI 0 +#define MAX_DEFINED_QCI 9 +#define SGI_MIN_EPS_BEARER_ID 5 +#define SGI_MAX_SERVED_USERS_PER_PGW 1024 +#define SGI_MAX_EPS_BEARERS_PER_USER 11 +#define MAX_DEFINED_IPV6_ADDRESSES_PER_UE 16 + + +#define NIP6ADDR(addr) \ + ntohs((addr)->s6_addr16[0]), \ + ntohs((addr)->s6_addr16[1]), \ + ntohs((addr)->s6_addr16[2]), \ + ntohs((addr)->s6_addr16[3]), \ + ntohs((addr)->s6_addr16[4]), \ + ntohs((addr)->s6_addr16[5]), \ + ntohs((addr)->s6_addr16[6]), \ + ntohs((addr)->s6_addr16[7]) + +#define NIPADDR(addr) \ + (uint8_t)(addr & 0x000000FF), \ + (uint8_t)((addr & 0x0000FF00) >> 8), \ + (uint8_t)((addr & 0x00FF0000) >> 16), \ + (uint8_t)((addr & 0xFF000000) >> 24) + +#define NMACADDR(addr) \ + (uint8_t)(addr[0]), \ + (uint8_t)(addr[1]), \ + (uint8_t)(addr[2]), \ + (uint8_t)(addr[3]), \ + (uint8_t)(addr[4]), \ + (uint8_t)(addr[5]) +#ifdef VLAN8021Q +typedef struct vlan_tag_s { + uint16_t vlan_tpid; /* ETH_P_8021Q */ + uint16_t vlan_tci; /* VLAN TCI */ +} vlan_tag_t __attribute__ ((__packed__)); + +typedef struct ether_header_8021q_s +{ + u_int8_t ether_dhost[ETH_ALEN]; /* destination eth addr */ + u_int8_t ether_shost[ETH_ALEN]; /* source ether addr */ + vlan_tag_t ether_vlan8021q; + u_int16_t ether_type; /* packet type ID field */ +} ether_header_8021q_t __attribute__ ((__packed__)); +#endif + +typedef struct arphdr_s { + __be16 ar_hrd; /* format of hardware address */ + __be16 ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + __be16 ar_op; /* ARP opcode (command) */ + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ + +}arphdr_t; + +typedef struct sgi_teid_mapping_s { + int is_outgoing_ipv4_packet_seen; + int is_outgoing_ipv6_packet_seen; + Teid_t enb_S1U_teid; ///< dest tunnel identifier + qci_t qci; + ebi_t eps_bearer_id; ///< EPS bearer identifier + char hw_addrlen; +#ifdef SGI_UE_ETHER_TRAFFIC + char ue_mac_addr[8]; +#endif + struct in6_addr in6_addr_captured[MAX_DEFINED_IPV6_ADDRESSES_PER_UE]; + struct in_addr in_add_captured; +} sgi_teid_mapping_t; + + +// Main goal is to do an association IP address <-> MAC address +// may be usefull for netfilter that does not capture MAC address +// if not set on certain hook points (table,path). +typedef struct sgi_addr_mapping_s { + int is_outgoing_packet_seen; + ebi_t eps_bearer_id; ///< EPS default bearer identifier, (really ?) + Teid_t enb_S1U_teid; ///< dest tunnel identifier, for default bearer + Teid_t sgw_S1U_teid; ///< dest tunnel identifier, for default bearer +#ifdef SGI_UE_ETHER_TRAFFIC + char ue_mac_addr[ETH_ALEN]; +#endif +} sgi_addr_mapping_t; + + + + +typedef struct sgi_data_s { + int sd[SGI_MAX_EPS_BEARERS_PER_USER]; + int sd6; + char *interface_name; + int interface_name_len; + int interface_index; +#ifndef SGI_UE_ETHER_TRAFFIC + char interface_hw_address[ETH_ALEN]; +#ifdef VLAN8021Q + struct ether_header_8021q_s eh; +#else + struct ether_header eh; +#endif +#endif + uint32_t ipv4_addr; + hash_table_t *teid_mapping; + hash_table_t *addr_v4_mapping; + obj_hash_table_t *addr_v6_mapping; + pthread_t capture_on_sgi_if_thread; + pthread_mutex_t thread_started_mutex; + int thread_started; + + void *sock_mmap_ring; + struct iovec *malloc_ring; + + int hw_address_of_router_captured; + uint32_t local_addr_v4_4_hw_address_router_capture; + uint32_t ipv4_addr_of_router; + + +#ifdef ENABLE_USE_PCAP_FOR_SGI + //brief PCAP descriptor for capturing packets on SGI interface. + pcap_t * pcap_descr; +#endif +#define SGI_BUFFER_RECV_LEN 3000 + unsigned char recv_buffer[sizeof(struct ether_header) + SGI_BUFFER_RECV_LEN][SGI_MAX_EPS_BEARERS_PER_USER]; + +} sgi_data_t; + + +typedef struct sgi_read_thread_args_s { + sgi_data_t *sgi_data; + int socket_index; +}sgi_read_thread_args_t; +//----------------------------------------------------------------------------- + +#include "mme_config.h" + + +#define SGI_MAX_EPS_BEARERS (SGI_MAX_SERVED_USERS_PER_PGW*SGI_MAX_EPS_BEARERS_PER_USER) + + + +//----------------------------------------------------------------------------- +// sgi_task.c +//----------------------------------------------------------------------------- +int sgi_init(const mme_config_t *mme_config); +char* sgi_status_2_str(SGIStatus_t statusP); + +//----------------------------------------------------------------------------- +// sgi_nf.c +//----------------------------------------------------------------------------- +#ifdef ENABLE_USE_NETFILTER_FOR_SGI +void* sgi_nf_fw_2_gtpv1u_thread(void *args_p); +#endif + +//----------------------------------------------------------------------------- +// sgi_pcap.c +//----------------------------------------------------------------------------- +#ifdef ENABLE_USE_PCAP_FOR_SGI +# define SGI_PCAPMAXBYTES2CAPTURE 65535 +# define SGI_PCAPTIMEDELAYKERNEL2USERSPACE 1000 + +/*! \fn void* sgi_pcap_loop(void*) +* \brief +* \param[in] devname The name of the device (ex "eth1") that will be listened for capturing packets. +* \param[in] iif The interface identifier that will be listened for capturing packets. +*/ +void* sgi_pcap_fw_2_gtpv1u_thread(void*); +#endif +//----------------------------------------------------------------------------- +// sgi_util.c +//----------------------------------------------------------------------------- +void sgi_print_hex_octets(unsigned char* dataP, unsigned long sizeP); +char* sgi_status_2_str (SGIStatus_t statusP); +char* sgi_arpopcode_2_str (unsigned short int opcodeP); +unsigned short in_cksum(unsigned short *addr, int len); +void sgi_send_arp_request(sgi_data_t *sgi_dataP, char* dst_ip_addrP); + +//----------------------------------------------------------------------------- +// sgi_socket.c +//----------------------------------------------------------------------------- +int sgi_create_sockets(sgi_data_t *sgi_data_p); +int sgi_send_data(uint8_t *buffer, uint32_t length, sgi_data_t *sgi_dataP, Teid_t originating_sgw_S1u_teidP); +#ifdef SGI_TEST +unsigned short in_cksum(unsigned short *addr, int len); +void sgi_test_send_ping(sgi_data_t *sgi_dataP, uint32_t markP, uint64_t src_mac_addrP, uint64_t dst_mac_addrP, char* src_ip_addrP, char* dst_ip_addrP); +#endif +#ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI +void sgi_sock_raw_cleanup_handler(void *args_p); +void* sgi_sock_raw_fw_2_gtpv1u_thread(void* args_p); +#endif + +//----------------------------------------------------------------------------- +// sgi_egress.c +//----------------------------------------------------------------------------- +void sgi_forward_ip_packet(sgi_data_t *sgi_dataP, struct ether_header *ehP, int packet_sizeP, sgi_addr_mapping_t *addr_mappingP); +#ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI +void sgi_process_raw_packet(sgi_data_t *sgi_dataP, unsigned char* dataP, int packet_sizeP); +#endif +#endif /* SGI_H_ */ diff --git a/openair-cn/SGI/sgi_egress.c b/openair-cn/SGI/sgi_egress.c new file mode 100755 index 0000000000..6234267a85 --- /dev/null +++ b/openair-cn/SGI/sgi_egress.c @@ -0,0 +1,307 @@ +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> + + +#include "sgi.h" +#include "intertask_interface.h" + +#include <netinet/ip6.h> +#include <netinet/ip.h> +#include <net/if_arp.h> + + +struct ipv6hdr { + __u8 priority:4, + version:4; + __u8 flow_lbl[3]; + + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; +}; + +#ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI + +#ifdef SGI_UE_ETHER_TRAFFIC +void sgi_process_raw_packet(sgi_data_t *sgi_data_pP, unsigned char* data_pP, int packet_sizeP) +{ + Gtpv1uTunnelDataReq *gtpv1u_tunnel_data_req_p = NULL; + MessageDef *message_p = NULL; + unsigned char *message_payload_p = NULL ; + struct ether_header *eh_p = (struct ether_header *) data_pP; + struct arphdr *arph_p = NULL; + struct iphdr *iph_p = NULL; + struct ipv6hdr *ip6h_p = NULL; + //struct arphdr *rarph = NULL; + //unsigned char *rarp_ptr = NULL; + //unsigned char *sha = NULL; /* Sender hardware address. */ + //unsigned char *tha = NULL; /* Target hardware address. */ + sgi_addr_mapping_t *addr_mapping_p = NULL; + //__be32 sip, tip; /* Sender, target IP address. */ + struct in6_addr dest6_addr; + u_int32_t dest4_addr; + struct in_addr in_dest_addr; + + SGI_IF_DEBUG("--------------------------------------------------------------\n%s :\n", __FUNCTION__); + sgi_print_hex_octets(data_pP, packet_sizeP); + + switch (htons(eh_p->ether_type)) { + + //******************* + case ETHERTYPE_IP: + //******************* + iph_p = (struct iphdr *) (data_pP + sizeof(struct ether_header)); + dest4_addr = iph_p->daddr; + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) == HASH_TABLE_OK) { + memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); + + } else { + if (sgi_data_pP->ipv4_addr == dest4_addr) { + SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); + return; + } else { + in_dest_addr.s_addr = dest4_addr; + SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); + return; + } + } + break; + + + //******************* + case ETHERTYPE_IPV6: + //******************* + ip6h_p = (struct ipv6hdr *) (data_pP + sizeof(struct ether_header)); + memcpy(dest6_addr.__in6_u.__u6_addr8, ip6h_p->daddr.__in6_u.__u6_addr8, 16); + if (obj_hashtbl_get(sgi_data_pP->addr_v6_mapping, (void*)&dest6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) == HASH_TABLE_OK) { + memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); + } else { + SGI_IF_WARNING("%s Dropping incoming egress IPV6 packet, IPV6 dest %X:%X:%X:%X:%X:%X:%X:%X not found \n", __FUNCTION__, NIP6ADDR(&dest6_addr)); + return; + } + break; + + + //******************* + case ETHERTYPE_REVARP: + //******************* + SGI_IF_ERROR("%s UNHANDLED ETHERTYPE_REVARP of incoming egress packet\n", __FUNCTION__); + return; + break; + + + //******************* + case ETHERTYPE_ARP: + //******************* + SGI_IF_DEBUG("%s HANDLED ETHERTYPE_ARP of incoming egress packet\n", __FUNCTION__); + arph_p = (struct arphdr *) (data_pP + sizeof(struct ether_header)); +#ifdef SGI_UE_ETHER_TRAFFIC + // The entry should be here but all signalling tied with RRC procedures not finished so + // a data packet can arrive before the MODIFY_BEARER REQUEST + // get " unsigned char __ar_tip[4]; /* Target IP address. */" (from /usr/include/net/if_apr.h line 68) + memcpy(&dest4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN*2+4], 4); + SGI_IF_DEBUG("%s ARP OPCODE %s TARGET IP %d.%d.%d.%d\n", __FUNCTION__, sgi_arpopcode_2_str(ntohl(arph_p->ar_op)), NIPADDR(dest4_addr)); + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) == HASH_TABLE_OK) { + memcpy(eh_p->ether_dhost, addr_mapping_p->ue_mac_addr, ETH_ALEN); + } else { + if (sgi_data_pP->ipv4_addr == dest4_addr) { + SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); + return; + } else { + in_dest_addr.s_addr = dest4_addr; + SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); + return; + } + } +#else +#endif + break; +// rarph = (struct arphdr *)(data_pP + sizeof(struct ether_header)); +// +// // If it's not Ethernet, delete it. +// if (rarph->ar_pro != htons(ETH_P_IP)) { +// SGI_IF_ERROR("%s ARP PACKET PROTOCOL OG INCOMING PACKET IS NOT ETHERNET\n",__FUNCTION__); +// break; +// } +// rarp_ptr = (unsigned char *) (rarph + 1); +// sha = rarp_ptr; +// rarp_ptr += ETH_ALEN; +// memcpy(&sip, rarp_ptr, 4); +// rarp_ptr += 4; +// tha = rarp_ptr; +// rarp_ptr += ETH_ALEN; +// memcpy(&tip, rarp_ptr, 4); +// SGI_IF_DEBUG("%s ARP DEST IP transport IP = %d.%d.%d.%d\n",__FUNCTION__, NIPADDR(tip)); +// // TO DO IF NECESSARY +// break; +// + + default: + SGI_IF_ERROR("%s UNHANDLED ether type %d of incoming egress packet\n", __FUNCTION__, eh_p->ether_type); + return; + } + + message_p = alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); + if (message_p == NULL) { + SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); + return; + } + message_payload_p = malloc(packet_sizeP); + if (message_payload_p == NULL) { + SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); + return; + } + memcpy(message_payload_p, data_pP, packet_sizeP); + + gtpv1u_tunnel_data_req_p = &message_p->msg.gtpv1uTunnelDataReq; + //LG HACK gtpv1u_tunnel_data_req_p->S1u_enb_teid = addr_mapping_p->enb_S1U_teid; +#warning forced S1u_enb_teid to 1 for testing, waiting for MODIFY_BEARER REQUEST + gtpv1u_tunnel_data_req_p->S1u_enb_teid = 1; + gtpv1u_tunnel_data_req_p->local_S1u_teid = addr_mapping_p->sgw_S1U_teid; + gtpv1u_tunnel_data_req_p->length = packet_sizeP; + gtpv1u_tunnel_data_req_p->buffer = message_payload_p; + SGI_IF_DEBUG("%s send GTPV1U_TUNNEL_DATA_REQ to GTPV1U S1u_enb_teid %u local_S1u_teid %u size %u\n", __FUNCTION__, gtpv1u_tunnel_data_req_p->S1u_enb_teid, gtpv1u_tunnel_data_req_p->local_S1u_teid, packet_sizeP); + + send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + +} +#else +void sgi_process_raw_packet(sgi_data_t *sgi_data_pP, unsigned char* data_pP, int packet_sizeP) +{ + Gtpv1uTunnelDataReq *gtpv1u_tunnel_data_req_p = NULL; + MessageDef *message_p = NULL; + unsigned char *message_payload_p = NULL ; + struct ether_header *eh_p = (struct ether_header *) data_pP; + struct arphdr *arph_p = NULL; + struct iphdr *iph_p = NULL; + struct ipv6hdr *ip6h_p = NULL; + sgi_addr_mapping_t *addr_mapping_p = NULL; + struct in6_addr dest6_addr; + u_int32_t dest4_addr; + u_int32_t src4_addr; + struct in_addr in_dest_addr; + + SGI_IF_DEBUG("--------------------------------------------------------------\n%s :\n", __FUNCTION__); + sgi_print_hex_octets(data_pP, packet_sizeP); + + switch (htons(eh_p->ether_type)) { + + //******************* + case ETHERTYPE_IP: + //******************* + iph_p = (struct iphdr *) (data_pP + sizeof(struct ether_header)); + dest4_addr = iph_p->daddr; + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { + if (sgi_data_pP->ipv4_addr == dest4_addr) { + SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); + return; + } else { + in_dest_addr.s_addr = dest4_addr; + SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); + return; + } + } + break; + + + //******************* + case ETHERTYPE_IPV6: + //******************* + ip6h_p = (struct ipv6hdr *) (data_pP + sizeof(struct ether_header)); + memcpy(dest6_addr.__in6_u.__u6_addr8, ip6h_p->daddr.__in6_u.__u6_addr8, 16); + if (obj_hashtbl_get(sgi_data_pP->addr_v6_mapping, (void*)&dest6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) != HASH_TABLE_OK) { + SGI_IF_WARNING("%s Dropping incoming egress IPV6 packet, IPV6 dest %X:%X:%X:%X:%X:%X:%X:%X not found \n", __FUNCTION__, NIP6ADDR(&dest6_addr)); + return; + } + break; + + + //******************* + case ETHERTYPE_REVARP: + //******************* + SGI_IF_ERROR("%s UNHANDLED ETHERTYPE_REVARP of incoming egress packet\n", __FUNCTION__); + return; + break; + + + //******************* + case ETHERTYPE_ARP: + //******************* + SGI_IF_DEBUG("%s HANDLED ETHERTYPE_ARP of incoming egress packet\n", __FUNCTION__); + arph_p = (struct arphdr *) (data_pP + sizeof(struct ether_header)); + // The entry should be here but all signalling tied with RRC procedures not finished so + // a data packet can arrive before the MODIFY_BEARER REQUEST + // get " unsigned char __ar_tip[4]; /* Target IP address. */" (from /usr/include/net/if_apr.h line 68) + memcpy(&dest4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN*2+4], 4); + SGI_IF_DEBUG("%s ARP OPCODE %s TARGET IP %d.%d.%d.%d\n", __FUNCTION__, sgi_arpopcode_2_str(ntohl(arph_p->ar_op)), NIPADDR(dest4_addr)); + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, dest4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { + if (sgi_data_pP->ipv4_addr == dest4_addr) { + SGI_IF_DEBUG("%s Dropping incoming egress IPV4 packet not UE IP flow\n", __FUNCTION__); + return; + } else { + if (sgi_data_pP->hw_address_of_router_captured) { + in_dest_addr.s_addr = dest4_addr; + SGI_IF_WARNING("%s Dropping incoming egress IPV4 packet, IPV4 dest %s not found \n", __FUNCTION__, inet_ntoa(in_dest_addr)); + } else { + // may be a response to our ARP request to router + if (htons(arph_p->ar_op) == ARPOP_REPLY) { + memcpy(&src4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN], 4); + SGI_IF_DEBUG("%s FOR ROUTER HW ADDRESS COMPARING: %d - %d %d - %d\n", + __FUNCTION__, + sgi_data_pP->local_addr_v4_4_hw_address_router_capture, + dest4_addr, + sgi_data_pP->ipv4_addr_of_router, + src4_addr); + if ((sgi_data_pP->local_addr_v4_4_hw_address_router_capture == dest4_addr) && (sgi_data_pP->ipv4_addr_of_router == src4_addr)) { + sgi_data_pP->hw_address_of_router_captured = 1; + sgi_data_pP->eh.ether_dhost[0] = ((unsigned char*)(&arph_p[1]))[0]; + sgi_data_pP->eh.ether_dhost[1] = ((unsigned char*)(&arph_p[1]))[1]; + sgi_data_pP->eh.ether_dhost[2] = ((unsigned char*)(&arph_p[1]))[2]; + sgi_data_pP->eh.ether_dhost[3] = ((unsigned char*)(&arph_p[1]))[3]; + sgi_data_pP->eh.ether_dhost[4] = ((unsigned char*)(&arph_p[1]))[4]; + sgi_data_pP->eh.ether_dhost[5] = ((unsigned char*)(&arph_p[1]))[5]; + SGI_IF_DEBUG("%s FOUND ROUTER HW ADDRESS: %02x:%02x:%02x:%02x:%02x:%02x\n", __FUNCTION__, NMACADDR(sgi_data_pP->eh.ether_dhost)); + } + } + } + return; + } + } + break; + + default: + SGI_IF_ERROR("%s UNHANDLED ether type %d of incoming egress packet\n", __FUNCTION__, eh_p->ether_type); + return; + } + + message_p = alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); + if (message_p == NULL) { + SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); + return; + } + message_payload_p = malloc(packet_sizeP - sizeof(sgi_data_pP->eh)); + if (message_payload_p == NULL) { + SGI_IF_ERROR("%s OUT OF MEMORY DROP EGRESS PACKET\n", __FUNCTION__); + return; + } + memcpy(message_payload_p, data_pP+sizeof(sgi_data_pP->eh), packet_sizeP - sizeof(sgi_data_pP->eh)); + + gtpv1u_tunnel_data_req_p = &message_p->msg.gtpv1uTunnelDataReq; + gtpv1u_tunnel_data_req_p->S1u_enb_teid = addr_mapping_p->enb_S1U_teid; +//#warning forced S1u_enb_teid to 1 for testing, waiting for MODIFY_BEARER REQUEST +// gtpv1u_tunnel_data_req_p->S1u_enb_teid = 1; + gtpv1u_tunnel_data_req_p->local_S1u_teid = addr_mapping_p->sgw_S1U_teid; + gtpv1u_tunnel_data_req_p->length = packet_sizeP; + gtpv1u_tunnel_data_req_p->buffer = message_payload_p; + SGI_IF_DEBUG("%s send GTPV1U_TUNNEL_DATA_REQ to GTPV1U S1u_enb_teid %u local_S1u_teid %u size %u\n", __FUNCTION__, gtpv1u_tunnel_data_req_p->S1u_enb_teid, gtpv1u_tunnel_data_req_p->local_S1u_teid, packet_sizeP); + + send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + +} +#endif +#endif diff --git a/openair-cn/SGI/sgi_nf.c b/openair-cn/SGI/sgi_nf.c new file mode 100755 index 0000000000..7bb25f57b6 --- /dev/null +++ b/openair-cn/SGI/sgi_nf.c @@ -0,0 +1,313 @@ +#include <stdio.h> +#include <string.h> + +#include <netinet/in.h> +#include <linux/netfilter.h> /* Defines verdicts (NF_ACCEPT, etc) */ +#include <libnfnetlink/libnfnetlink.h> +#include <libnetfilter_queue/libnetfilter_queue.h> +#include <libnetfilter_queue/linux_nfnetlink_queue.h> + +#include "mme_config.h" +#include "intertask_interface.h" +#include "sgi.h" +//----------------------------------------------------------------------------- +struct nfq_handle +{ + struct nfnl_handle *nfnlh; + struct nfnl_subsys_handle *nfnlssh; + struct nfq_q_handle *qh_list; +}; + +struct nfq_q_handle +{ + struct nfq_q_handle *next; + struct nfq_handle *h; + u_int16_t id; + + nfq_callback *cb; + void *data; +}; + +struct nfq_data { + struct nfattr **data; +}; + + +enum { + NFQ_XML_HW = (1 << 0), NFQ_XML_MARK = (1 << 1), NFQ_XML_DEV = (1 << 2), NFQ_XML_PHYSDEV = (1 << 3), + NFQ_XML_PAYLOAD = (1 << 4), NFQ_XML_TIME = (1 << 5), NFQ_XML_ALL = ~0U +}; +//------------------------------------------------------ +#define SNPRINTF_FAILURE(ret, rem, offset, len) \ +do { \ + if (ret < 0) \ + return ret; \ + len += ret; \ + if (ret > rem) \ + ret = rem; \ + offset += ret; \ + rem -= ret; \ +} while (0) + +//------------------------------------------------------ +static int nfq_snprintf(char *buf, size_t rem, struct nfq_data *tb, int flags) +//------------------------------------------------------ +{ + struct nfqnl_msg_packet_hdr *ph; + struct nfqnl_msg_packet_hw *hwph; + u_int32_t mark, ifi; + int size, offset = 0, len = 0, ret; + unsigned char *data; + + size = snprintf(buf + offset, rem, "<pkt>"); + SNPRINTF_FAILURE(size, rem, offset, len); + + + + ph = nfq_get_msg_packet_hdr(tb); + if (ph) { + size = snprintf(buf + offset, rem, + "<hook> %u <id>%u", + ph->hook, ntohl(ph->packet_id)); + SNPRINTF_FAILURE(size, rem, offset, len); + + hwph = nfq_get_packet_hw(tb); + if (hwph && (flags & NFQ_XML_HW)) { + int i, hlen = ntohs(hwph->hw_addrlen); + + size = snprintf(buf + offset, rem, "<hw><proto>%04x" + "</proto>", + ntohs(ph->hw_protocol)); + SNPRINTF_FAILURE(size, rem, offset, len); + + size = snprintf(buf + offset, rem, "<src>"); + SNPRINTF_FAILURE(size, rem, offset, len); + + for (i=0; i<hlen; i++) { + size = snprintf(buf + offset, rem, "%02x", + hwph->hw_addr[i]); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + size = snprintf(buf + offset, rem, "</src></hw>"); + SNPRINTF_FAILURE(size, rem, offset, len); + } else if (flags & NFQ_XML_HW) { + size = snprintf(buf + offset, rem, "<hw><proto>%04x" + "</proto></hw>", + ntohs(ph->hw_protocol)); + SNPRINTF_FAILURE(size, rem, offset, len); + } + } + + mark = nfq_get_nfmark(tb); + if (mark && (flags & NFQ_XML_MARK)) { + size = snprintf(buf + offset, rem, "<mark>%u</mark>", mark); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_indev(tb); + if (ifi && (flags & NFQ_XML_DEV)) { + size = snprintf(buf + offset, rem, "<indev>%u</indev>", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_outdev(tb); + if (ifi && (flags & NFQ_XML_DEV)) { + size = snprintf(buf + offset, rem, "<outdev>%u</outdev>", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_physindev(tb); + if (ifi && (flags & NFQ_XML_PHYSDEV)) { + size = snprintf(buf + offset, rem, + "<physindev>%u</physindev>", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ifi = nfq_get_physoutdev(tb); + if (ifi && (flags & NFQ_XML_PHYSDEV)) { + size = snprintf(buf + offset, rem, + "<physoutdev>%u</physoutdev>", ifi); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + ret = nfq_get_payload(tb, &data); + if (ret >= 0 && (flags & NFQ_XML_PAYLOAD)) { + int i; + + size = snprintf(buf + offset, rem, "<payload>"); + SNPRINTF_FAILURE(size, rem, offset, len); + + for (i=0; i<ret; i++) { + size = snprintf(buf + offset, rem, "%02x", + data[i] & 0xff); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + size = snprintf(buf + offset, rem, "</payload>"); + SNPRINTF_FAILURE(size, rem, offset, len); + } + + size = snprintf(buf + offset, rem, "</pkt>"); + SNPRINTF_FAILURE(size, rem, offset, len); + + return len; +} +//------------------------------------------------------ +static int sgi_nfqueue_callback(struct nfq_q_handle *myQueue, struct nfgenmsg *msg, + struct nfq_data *pkt, void *cbData) +//----------------------------------------------------------------------------- +{ + uint32_t id = 0; + struct nfqnl_msg_packet_hdr *header; + struct nfqnl_msg_packet_hw *macAddr; + MessageDef *message_p; + Gtpv1uTunnelDataReq *data_req_p; + Teid_t local_teid; + u_int32_t verdict; + + if ((header = nfq_get_msg_packet_hdr(pkt))) { + id = ntohl(header->packet_id); + SGI_IF_DEBUG("packet_id %u hw_protocol %u hook %u\n", ntohl(header->packet_id), ntohs(header->hw_protocol), header->hook); + } + + // The HW address is only fetchable at certain hook points + // LG Warning HW address is src address + macAddr = nfq_get_packet_hw(pkt); + if (macAddr) { + SGI_IF_DEBUG("MAC len %u addr %02X:%02X:%02X:%02X:%02X:%02X\n", + ntohs(macAddr->hw_addrlen), + macAddr->hw_addr[0], + macAddr->hw_addr[1], + macAddr->hw_addr[2], + macAddr->hw_addr[3], + macAddr->hw_addr[4], + macAddr->hw_addr[5]); + } else { + SGI_IF_DEBUG("No MAC addr\n"); + } + + /*timeval tv; + if (!nfq_get_timestamp(pkt, &tv)) { + cout << "; tstamp " << tv.tv_sec << "." << tv.tv_usec; + } else { + cout << "; no tstamp"; + }*/ + + //cout << "; mark " << nfq_get_nfmark(pkt); + // Print the payload; in copy meta mode, only headers will be included; + // in copy packet mode, whole packet will be returned. + char *pktData; + int len = nfq_get_payload(pkt, &pktData); + + // Note that you can also get the physical devices + SGI_IF_DEBUG("pkt id %d recvd: indev %d outdev %d mark %d len %d\n", + id, + nfq_get_indev(pkt), + nfq_get_outdev(pkt), + nfq_get_nfmark(pkt), + len); + + + //sgi_print_hex_octets((unsigned char *)pktData, len); + + message_p = alloc_new_message(TASK_FW_IP, GTPV1U_TUNNEL_DATA_REQ); + if (message_p == NULL) { + return -1; + } + data_req_p = &message_p->msg.gtpv1uTunnelDataReq; + data_req_p->buffer = malloc(sizeof(uint8_t) * len); + if (data_req_p->buffer == NULL) { + SGI_IF_ERROR("Failed to allocate new buffer\n"); + free(message_p); + return -1; + } else { + // MAY BE TO BE CHANGED + local_teid = nfq_get_nfmark(pkt); + + // if packet is marked, it is a packet going into a EPS bearer + //if (local_teid != 0) { + if (1) { + data_req_p->local_S1u_teid = local_teid; + + memcpy(data_req_p->buffer, pktData, len); + data_req_p->length = len; + + if (send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p) < 0) { + SGI_IF_ERROR("Failed to send message to task\n"); + free(message_p); + } + verdict = NF_STOLEN; + return nfq_set_verdict(myQueue, id, verdict, 0, NULL); + } else { + verdict = NF_ACCEPT; + return nfq_set_verdict(myQueue, id, verdict, len, pktData); + } + } + return 0; + // end sgi_nfqueue_callback +} +//----------------------------------------------------------------------------- +void* sgi_nf_fw_2_gtpv1u_thread(void *args_p) +//----------------------------------------------------------------------------- +{ + struct nfq_handle *nfqHandle; + struct nfq_q_handle *myQueue; + struct nfnl_handle *netlinkHandle; + int fd, res; + volatile sgi_data_t *sgi_data_p; + + sgi_data_p = (sgi_data_t*)args_p; + + SGI_IF_DEBUG("RX thread on netfilter queue started, operating on Device %s iif %d\n", sgi_data_p->interface_name, sgi_data_p->interface_index); + + // Get a queue connection handle from the module + if (!(nfqHandle = nfq_open())) { + SGI_IF_ERROR("Error in nfq_open()"); + exit(-1); + } + + // Unbind the handler from processing any IP packets + // Not totally sure why this is done, or if it's necessary... + if (nfq_unbind_pf(nfqHandle, PF_INET) < 0) { + SGI_IF_ERROR("Error in nfq_unbind_pf()"); + exit(-1); + } + + // Bind this handler to process IP packets... + if (nfq_bind_pf(nfqHandle, PF_INET) < 0) { + SGI_IF_ERROR("Error in nfq_bind_pf()"); + exit(-1); + } + + // Install a callback on queue 1 + if (!(myQueue = nfq_create_queue(nfqHandle, 1, &sgi_nfqueue_callback, NULL))) { + SGI_IF_ERROR("Error in nfq_create_queue()"); + exit(-1); + } + + // Turn on packet copy mode + if (nfq_set_mode(myQueue, NFQNL_COPY_PACKET, 0xffff) < 0) { + SGI_IF_ERROR("Could not set packet copy mode"); + exit(-1); + } + + netlinkHandle = nfq_nfnlh(nfqHandle); + fd = nfnl_fd(netlinkHandle); + + SGI_IF_DEBUG("Waiting for egress packets\n"); + sgi_data_p->thread_started = 1; + while ((res = recv(fd, &sgi_data_p->recv_buffer[sizeof(struct ether_header)], SGI_BUFFER_RECV_LEN, 0)) && res >= 0) { + // a callback mechanism is used + // rather than just handling it directly here, but that + // seems to be the convention... + nfq_handle_packet(nfqHandle, &sgi_data_p->recv_buffer[sizeof(struct ether_header)], res); + // end while receiving traffic + } + + nfq_destroy_queue(myQueue); + + nfq_close(nfqHandle); + + return NULL; +} diff --git a/openair-cn/SGI/sgi_pcap.c b/openair-cn/SGI/sgi_pcap.c new file mode 100755 index 0000000000..f5a6a015b8 --- /dev/null +++ b/openair-cn/SGI/sgi_pcap.c @@ -0,0 +1,60 @@ +#include <string.h> +#include "sgi.h" + + +//--------------------------------------------------------------------------------------------------------------------- +void* sgi_pcap_fw_2_gtpv1u_thread(void* args_p) +{ + bpf_u_int32 netaddr = 0, mask = 0; // To store network address and netmask + struct bpf_program filter; // Place to store the BPF filter program + char errbuf[PCAP_ERRBUF_SIZE]; // Error buffer + struct pcap_pkthdr pkthdr; // Packet information (timestamp, size...) + const unsigned char *packet = NULL; // Received raw data + char filter_string[] = ""; + sgi_data_t *sgi_data_p; + + sgi_data_p = (sgi_data_t*)args_p; + + SGI_IF_DEBUG("[PCAP] Device is %s and iif is %d\n", sgi_data_p->interface_name, sgi_data_p->interface_index); + + memset(errbuf, 0, PCAP_ERRBUF_SIZE); + + sgi_data_p->pcap_descr = pcap_open_live(sgi_data_p->interface_name, SGI_PCAPMAXBYTES2CAPTURE, 0, SGI_PCAPTIMEDELAYKERNEL2USERSPACE, errbuf); + if (sgi_data_p->pcap_descr == NULL) + SGI_IF_ERROR("Error %s", errbuf); + else if (*errbuf) + SGI_IF_WARNING("Warning %s\n", errbuf); + +// Look up info from the capture device + if (pcap_lookupnet(sgi_data_p->interface_name, &netaddr, &mask, errbuf) == -1) { + SGI_IF_ERROR("Can't get netmask for device %s\n", sgi_data_p->interface_name); + netaddr = 0; + mask = 0; + pthread_exit(NULL); + } + +// Compiles the filter expression into a BPF filter program + if (pcap_compile(sgi_data_p->pcap_descr, &filter, filter_string, 0, mask) == -1) { + SGI_IF_ERROR("Couldn't parse filter : %s\n", pcap_geterr(sgi_data_p->pcap_descr)); + pthread_exit(NULL); + } +// Load the filter program into the packet capture device + if (pcap_setfilter(sgi_data_p->pcap_descr, &filter) == -1) { + SGI_IF_ERROR("Couldn't install filter: %s\n", pcap_geterr(sgi_data_p->pcap_descr)); + pthread_exit(NULL); + } + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + sgi_data_p->thread_started = 1; + while (1) { + packet = pcap_next(sgi_data_p->pcap_descr, &pkthdr); // Get one packet + + if ( ( pkthdr.len > 0 ) && ( packet != NULL ) ){ + sgi_print_hex_octets(packet, pkthdr.len); + if (packet[54] == 0x85) { // case ROUTER SOLICITATION WITH ETHERNET HEADER + } + } + } + pthread_exit(NULL); +} + diff --git a/openair-cn/SGI/sgi_socket.c b/openair-cn/SGI/sgi_socket.c new file mode 100644 index 0000000000..789a0ea87d --- /dev/null +++ b/openair-cn/SGI/sgi_socket.c @@ -0,0 +1,774 @@ +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <fcntl.h> +#include <stdlib.h> + +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/mman.h> //mmap + +#include <asm/types.h> +#include <net/if.h> +#include <net/ethernet.h> +#include <linux/if_ether.h> +#include <net/if_arp.h> +#include <linux/if_packet.h> +#include <netinet/in.h> +#include <poll.h> +#include <arpa/inet.h> +#ifndef SGI_UE_ETHER_TRAFFIC +#include <sys/uio.h> +#endif + + +#include <netinet/ip6.h> +#include <netinet/ip.h> +#include "sgi.h" +#include "intertask_interface.h" + +#ifdef ENABLE_USE_NETFILTER_FOR_SGI +#define SGI_SOCKET_RAW 1 +#define SGI_SOCKET_BIND_TO_IF 1 +#undef SGI_MARKING +#undef SGI_PACKET_RX_RING +#undef SGI_SOCKET_UDP +#else +#define SGI_SOCKET_RAW 1 +#define SGI_SOCKET_BIND_TO_IF 1 +#undef SGI_PACKET_RX_RING +#undef SGI_MARKING +#undef SGI_SOCKET_UDP +#endif + + +//static char sgi_command_buffer[256]; + +#define HW_ADDRESS "%02x:%02x:%02x:%02x:%02x:%02x" +#define HW_ADDRESS_FORMAT(iFR) \ + (uint8_t)(iFR)[0], \ + (uint8_t)(iFR)[1], \ + (uint8_t)(iFR)[2], \ + (uint8_t)(iFR)[3], \ + (uint8_t)(iFR)[4], \ + (uint8_t)(iFR)[5] + +#define IPV4_ADDR "%u.%u.%u.%u" +#define IPV4_ADDR_FORMAT(aDDRESS) \ + (uint8_t)((aDDRESS) & 0x000000ff), \ + (uint8_t)(((aDDRESS) & 0x0000ff00) >> 8 ), \ + (uint8_t)(((aDDRESS) & 0x00ff0000) >> 16), \ + (uint8_t)(((aDDRESS) & 0xff000000) >> 24) + +struct ipv6hdr { + __u8 priority:4, + version:4; + __u8 flow_lbl[3]; + + __be16 payload_len; + __u8 nexthdr; + __u8 hop_limit; + + struct in6_addr saddr; + struct in6_addr daddr; +}; + + +/// The number of frames in the ring +// This number is not set in stone. Nor are block_size, block_nr or frame_size +#define CONF_RING_FRAMES 128 + +/// Offset of data from start of frame +#define PKT_OFFSET (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + \ + TPACKET_ALIGN(sizeof(struct sockaddr_ll))) + +int sgi_create_sockets(sgi_data_t *sgi_data_p) +{ +#ifdef SGI_SOCKET_BIND_TO_IF + struct sockaddr_ll socket_address; + char if_name[16]; +#endif +#ifdef SGI_MARKING + int value = 0; + const int *val_p=&value; +#endif +#ifdef SGI_PACKET_RX_RING + struct tpacket_req tp; +#endif + uint32_t i = 0; +#ifndef SGI_UE_ETHER_TRAFFIC + FILE *fp = NULL; + char filename[128]; + int rc = 0; + char *router_mac_addr = NULL; + int b = 0; + char addr_mac_byte[16]; +#endif + + if (sgi_data_p == NULL) { + return -1; + } + + SGI_IF_DEBUG("Creating sockets for sgi on interface %s\n", sgi_data_p->interface_name); + + // qci = 0 is for the default bearers QOS, Non-GBR + /* Create a RAW IP socket and request for all internet IP traffic */ + // work +//#define SGI_SOCKET_RAW + for (i = 0; i < SGI_MAX_EPS_BEARERS_PER_USER; i++) { + //sgi_data_p->sd[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + // works also + sgi_data_p->sd[i] = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW)); + //sgi_data_p->sd[i] = socket(AF_INET, SOCK_RAW, ETH_P_IP); + //sgi_data_p->sd[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); + + if (sgi_data_p->sd[i] < 0) { + SGI_IF_ERROR("Error during socket creation (%s:%d)\n",strerror(errno), errno); + goto error; + } + + /* socket options, tell the kernel we provide the IP structure + int one = 1; + const int *val = &one; + if(setsockopt(sgi_data_p->sd[i], IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0) + { + SGI_IF_ERROR("Error during socket setsockopt IP_HDRINCL (%s:%d)\n", strerror(errno), errno); + goto error; + }*/ + + +#ifdef SGI_MARKING + // setting socket option to use MARK value + //value = rab_id + SGI_MIN_EPS_BEARER_ID; + value = 5; + if (setsockopt (sgi_data_p->sd[i], SOL_SOCKET, SO_MARK, val_p, sizeof (value)) < 0) + { + SGI_IF_ERROR("error notifying kernel about MARK"); + goto error; + } + SGI_IF_DEBUG("Created socket %d for rab_id %d (for any UE context)\n", sgi_data_p->sd[i], value); +#endif + +#ifdef SGI_PACKET_RX_RING + // tell kernel to export data through mmap()ped ring + tp.tp_block_size = CONF_RING_FRAMES * getpagesize(); + tp.tp_block_nr = 1; + tp.tp_frame_size = getpagesize(); + tp.tp_frame_nr = CONF_RING_FRAMES; + + if (setsockopt(sgi_data_p->sd[i], SOL_PACKET, PACKET_RX_RING, (void*) &tp, sizeof(tp))) { + SGI_IF_ERROR("setsockopt() ring\n"); + goto error; + } + + // open ring + sgi_data_p->sock_mmap_ring = mmap(0, tp.tp_block_size * tp.tp_block_nr, PROT_READ | PROT_WRITE, MAP_SHARED, sgi_data_p->sd[i], 0); + if (!sgi_data_p->sock_mmap_ring) { + SGI_IF_ERROR("Failed to mmap socket (%s:%d)\n", strerror(errno), errno); + goto error; + } + /* Setup our ringbuffer */ + sgi_data_p->malloc_ring = malloc(tp.tp_frame_nr * sizeof(struct iovec)); + for(i=0; i<tp.tp_frame_nr; i++) { + sgi_data_p->malloc_ring[i].iov_base=(void *)((long)sgi_data_p->sock_mmap_ring)+(i*tp.tp_frame_size); + sgi_data_p->malloc_ring[i].iov_len=tp.tp_frame_size; + } + +#endif + +#ifdef SGI_SOCKET_BIND_TO_IF + sprintf(if_name, "%s.%d",sgi_data_p->interface_name,i+SGI_MIN_EPS_BEARER_ID); + + memset(&socket_address, 0, sizeof(struct sockaddr_ll)); + socket_address.sll_family = PF_PACKET; + + //socket_address.sll_addr = ;// Filled when we want to tx + //socket_address.sll_halen = ;// Filled when we want to tx + //socket_address.sll_family ;// Filled when we want to tx + + //socket_address.sll_hatype = ;// Filled when packet received + //socket_address.sll_pkttype = ;// Filled when packet received + socket_address.sll_ifindex = if_nametoindex(if_name); + socket_address.sll_protocol = htons(ETH_P_IP); + //socket_address.sll_protocol = htons(ETH_P_ALL); + + // Now we can bind the socket to send the IP traffic + if (bind(sgi_data_p->sd[i], (struct sockaddr *)&socket_address, sizeof(struct sockaddr_ll)) < 0) { + SGI_IF_ERROR("Bind socket to %s (%s:%d)\n", if_name, strerror(errno), errno); + goto error; + } +#endif + + } + +#ifndef SGI_UE_ETHER_TRAFFIC + if (sprintf(filename, "/sys/class/net/%s/address", sgi_data_p->interface_name) <= 0 ) { + SGI_IF_ERROR("Build of file name /sys/class/net/sgi_if_name/address Failed (%s:%d)\n", strerror(errno), errno); + goto error; + } + fp = fopen(filename, "r"); + if (fp) { + rc = fscanf(fp, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &sgi_data_p->interface_hw_address[0], + &sgi_data_p->interface_hw_address[1], + &sgi_data_p->interface_hw_address[2], + &sgi_data_p->interface_hw_address[3], + &sgi_data_p->interface_hw_address[4], + &sgi_data_p->interface_hw_address[5]); + fclose(fp); + if (rc <= 0) { + SGI_IF_ERROR("ERROR reading %s\n" ,filename); + goto error; + } + } else { + SGI_IF_ERROR("Correct /sys/class/net/sgi_if_name file not found\n"); + goto error; + } + memcpy((void*)(&sgi_data_p->eh.ether_shost[0]), (void*)(&sgi_data_p->interface_hw_address[0]), ETH_ALEN); + router_mac_addr = getenv("MAC_ROUTER"); + if (router_mac_addr == NULL) { + SGI_IF_ERROR("ERROR getting ENV variable MAC_ROUTER, should be set by start script\n"); + goto error; + } + for (b = 0 ; b < 6; b++) { + strncpy(addr_mac_byte, router_mac_addr+2*b, 2); + addr_mac_byte[2] = '\0'; + // we can do (unsigned int*) because x86 processors are little-endian + // (done for suppressing a warning) + rc = sscanf ((const char*)addr_mac_byte, "%02x", (uint32_t*)&i); + if (rc < 1) { + SGI_IF_ERROR("Error in converting string MAC_ROUTER address %s in char array\n", router_mac_addr); + goto error; + } + sgi_data_p->eh.ether_dhost[b] = (i & 0x000000FF); + } + SGI_IF_DEBUG("Found MAC address for ROUTER : %02x:%02x:%02x:%02x:%02x:%02x\n", + NMACADDR(sgi_data_p->eh.ether_dhost)); + +#ifdef VLAN8021Q + sgi_data_p->eh.ether_vlan8021q.vlan_tpid = htons(0x8100); + sgi_data_p->eh.ether_vlan8021q.vlan_tci = htons(0x7000 | 0x0000 | 0x0000); +#endif + SGI_IF_DEBUG("Found MAC address for SGI IF %s: %02x:%02x:%02x:%02x:%02x:%02x\n", + sgi_data_p->interface_name, NMACADDR(sgi_data_p->eh.ether_shost)); + +#endif + return 0; +error: + SGI_IF_ERROR("ERROR (%s)\n", strerror(errno)); + for (i=0; i<SGI_MAX_EPS_BEARERS_PER_USER; i++) { + if (sgi_data_p->sd[i] > 0) { + close(sgi_data_p->sd[i]); + } + sgi_data_p->sd[i] = -1; + } + return -1; +} +#ifdef SGI_UE_ETHER_TRAFFIC +int sgi_send_data(uint8_t *buffer_pP, uint32_t length, sgi_data_t *sgi_data_pP, Teid_t originating_sgw_S1u_teidP) +{ + struct ether_header *eh_p = (struct ether_header *) buffer_pP; + struct iphdr *iph_p = NULL; + struct arphdr *arph_p = NULL; + struct ipv6hdr *ip6h_p = NULL; + sgi_teid_mapping_t *mapping_p = NULL; + sgi_addr_mapping_t *addr_mapping_p = NULL; + hashtbl_rc_t hash_rc; + struct in6_addr src6_addr; /* source address */ + struct in6_addr *src6_addr_p; /* source address */ + u_int32_t src4_addr; + + if (buffer_pP == NULL) { + SGI_IF_ERROR("sgi_send_data: received bad parameter\n"); + return -1; + } + + // get IP version of this packet + switch (htons(eh_p->ether_type)) { + + //******************* + case ETHERTYPE_IP: + //******************* + iph_p = (struct iphdr *) (buffer_pP + sizeof(struct ether_header)); + // The entry should be here but all signalling tied with RRC procedures not finished so + // a data packet can arrive before the MODIFY_BEARER REQUEST + src4_addr = iph_p->saddr; + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, src4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + SGI_IF_ERROR("%s Error unknown context SGW teid %d\n", __FUNCTION__, originating_sgw_S1u_teidP); + return -1; + } else { + if (mapping_p->is_outgoing_ipv4_packet_seen == 0) { + mapping_p->hw_addrlen = ETH_ALEN; // TO DO + memcpy(mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + mapping_p->is_outgoing_ipv4_packet_seen = 1; + mapping_p->in_add_captured.s_addr = src4_addr; + + addr_mapping_p = calloc(1, sizeof(sgi_addr_mapping_t)); + memcpy(addr_mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + addr_mapping_p->is_outgoing_packet_seen = 1; + addr_mapping_p->enb_S1U_teid = mapping_p->enb_S1U_teid; + addr_mapping_p->sgw_S1U_teid = originating_sgw_S1u_teidP; + hashtbl_insert(sgi_data_pP->addr_v4_mapping, src4_addr, (void*)addr_mapping_p); + SGI_IF_DEBUG("%s ASSOCIATED %d.%d.%d.%d to MAC %02x:%02x:%02x:%02x:%02x:%02x teid %d\n", + __FUNCTION__, NIPADDR(src4_addr), NMACADDR(eh_p->ether_shost), originating_sgw_S1u_teidP); + } else { + SGI_IF_ERROR("Error IPv4 address already registered for teid %d\n", originating_sgw_S1u_teidP); + return -1; + } + } + + } else { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + } + break; + + //******************* + case ETHERTYPE_ARP: + //******************* + arph_p = (struct arphdr *) (buffer_pP + sizeof(struct ether_header)); + // The entry should be here but all signalling tied with RRC procedures not finished so + // a data packet can arrive before the MODIFY_BEARER REQUEST + memcpy(&src4_addr, &((unsigned char*)(&arph_p[1]))[ETH_ALEN], 4); + SGI_IF_ERROR("%s ARP OPCODE %s TARGET IP %d.%d.%d.%d\n", __FUNCTION__, sgi_arpopcode_2_str(ntohl(arph_p->ar_op)), NIPADDR(src4_addr)); + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, src4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + SGI_IF_ERROR("%s Error unknown context SGW teid %d\n", __FUNCTION__, originating_sgw_S1u_teidP); + return -1; + } else { + if (mapping_p->is_outgoing_ipv4_packet_seen == 0) { + mapping_p->hw_addrlen = ETH_ALEN; // TO DO + memcpy(mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + mapping_p->is_outgoing_ipv4_packet_seen = 1; + mapping_p->in_add_captured.s_addr = src4_addr; + + addr_mapping_p = calloc(1, sizeof(sgi_addr_mapping_t)); + memcpy(addr_mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + addr_mapping_p->is_outgoing_packet_seen = 1; + addr_mapping_p->enb_S1U_teid = mapping_p->enb_S1U_teid; + addr_mapping_p->sgw_S1U_teid = originating_sgw_S1u_teidP; + hashtbl_insert(sgi_data_pP->addr_v4_mapping, src4_addr, (void*)addr_mapping_p); + SGI_IF_DEBUG("%s ASSOCIATED %d.%d.%d.%d to MAC %02x:%02x:%02x:%02x:%02x:%02x teid %d\n", + __FUNCTION__, NIPADDR(src4_addr), NMACADDR(eh_p->ether_shost), originating_sgw_S1u_teidP); + } else { + SGI_IF_ERROR("Error IPv4 address already registered for teid %d\n", originating_sgw_S1u_teidP); + return -1; + } + } + + } else { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + } + break; + + + //******************* + case ETHERTYPE_IPV6: + ip6h_p = (struct ipv6hdr *) (buffer_pP + sizeof(struct ether_header)); + + if (obj_hashtbl_get(sgi_data_pP->addr_v6_mapping, &src6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) != HASH_TABLE_OK) { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + SGI_IF_ERROR("%s Error unknown context SGW teid %d\n", __FUNCTION__, originating_sgw_S1u_teidP); + return -1; + } else { + + if (mapping_p->is_outgoing_ipv6_packet_seen < MAX_DEFINED_IPV6_ADDRESSES_PER_UE) { + mapping_p->hw_addrlen = ETH_ALEN; + memcpy(mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + + memcpy(&mapping_p->in6_addr_captured[mapping_p->is_outgoing_ipv6_packet_seen].s6_addr, src6_addr.s6_addr, 16); + mapping_p->is_outgoing_ipv6_packet_seen +=1; + + addr_mapping_p = calloc(1, sizeof(sgi_addr_mapping_t)); + memcpy(addr_mapping_p->ue_mac_addr, eh_p->ether_shost, ETH_ALEN); + addr_mapping_p->is_outgoing_packet_seen = 1; + addr_mapping_p->enb_S1U_teid = mapping_p->enb_S1U_teid; + addr_mapping_p->sgw_S1U_teid = originating_sgw_S1u_teidP; + + src6_addr_p = malloc(sizeof(struct in6_addr)); + if (src6_addr_p == NULL) { + return -1; + } + memcpy(src6_addr_p->s6_addr, ip6h_p->saddr.s6_addr, 16); + obj_hashtbl_insert(sgi_data_pP->addr_v6_mapping, src6_addr_p,sizeof(struct in6_addr), (void*)addr_mapping_p); + } else { + SGI_IF_ERROR("Error TOO MANY IPv6 address already registered for teid %d\n", originating_sgw_S1u_teidP); + return -1; + } + } + + } else { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + } + break; + + default: + SGI_IF_WARNING("%s UNHANDLED ETHERTYPE: %X\n", __FUNCTION__, htons(eh_p->ether_type)); + break; + } + + assert(mapping_p != NULL); + if (send(sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], (void *)buffer_pP, length, 0) < 0) { + SGI_IF_ERROR("Error during send to socket %d bearer id %d : (%s:%d)\n", + sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], + mapping_p->eps_bearer_id, + strerror(errno), + errno); + return -1; + } + return 0; +} +#else +int sgi_send_data(uint8_t *buffer_pP, uint32_t length, sgi_data_t *sgi_data_pP, Teid_t originating_sgw_S1u_teidP) +{ + struct iphdr *iph_p = (struct iphdr *) buffer_pP; + struct ipv6hdr *ip6h_p = (struct ipv6hdr *) buffer_pP; + sgi_teid_mapping_t *mapping_p = NULL; + sgi_addr_mapping_t *addr_mapping_p = NULL; + hashtbl_rc_t hash_rc; + struct in6_addr src6_addr; /* source address */ + struct in6_addr *src6_addr_p; /* source address */ + u_int32_t src4_addr; + struct iovec iov[2]; + + if (buffer_pP == NULL) { + SGI_IF_ERROR("sgi_send_data: received bad parameter\n"); + return -1; + } + + // get IP version of this packet + switch (iph_p->version) { + + //******************* + case 4: + //******************* + // The entry should be here but all signalling tied with RRC procedures not finished so + // a data packet can arrive before the MODIFY_BEARER REQUEST + sgi_data_pP->eh.ether_type = htons(ETHERTYPE_IP); + src4_addr = iph_p->saddr; + if (hashtbl_get(sgi_data_pP->addr_v4_mapping, src4_addr, (void**)&addr_mapping_p) != HASH_TABLE_OK) { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + SGI_IF_ERROR("%s Error unknown context SGW teid %d\n", __FUNCTION__, originating_sgw_S1u_teidP); + return -1; + } else { + if (mapping_p->is_outgoing_ipv4_packet_seen == 0) { + mapping_p->hw_addrlen = ETH_ALEN; // TO DO + mapping_p->is_outgoing_ipv4_packet_seen = 1; + mapping_p->in_add_captured.s_addr = src4_addr; + + addr_mapping_p = calloc(1, sizeof(sgi_addr_mapping_t)); + addr_mapping_p->is_outgoing_packet_seen = 1; + addr_mapping_p->enb_S1U_teid = mapping_p->enb_S1U_teid; + addr_mapping_p->sgw_S1U_teid = originating_sgw_S1u_teidP; + hashtbl_insert(sgi_data_pP->addr_v4_mapping, src4_addr, (void*)addr_mapping_p); + SGI_IF_DEBUG("%s ASSOCIATED %d.%d.%d.%d to teid %d\n", + __FUNCTION__, NIPADDR(src4_addr), originating_sgw_S1u_teidP); + } else { + SGI_IF_ERROR("Error IPv4 address already registered for teid %d\n", originating_sgw_S1u_teidP); + return -1; + } + } + + } else { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + } + break; + + + + //******************* + case 6: + sgi_data_pP->eh.ether_type = htons(ETHERTYPE_IPV6); + if (obj_hashtbl_get(sgi_data_pP->addr_v6_mapping, &src6_addr, sizeof(struct in6_addr), (void**)&addr_mapping_p) != HASH_TABLE_OK) { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + SGI_IF_ERROR("%s Error unknown context SGW teid %d\n", __FUNCTION__, originating_sgw_S1u_teidP); + return -1; + } else { + + if (mapping_p->is_outgoing_ipv6_packet_seen < MAX_DEFINED_IPV6_ADDRESSES_PER_UE) { + mapping_p->hw_addrlen = 0; + + memcpy(&mapping_p->in6_addr_captured[mapping_p->is_outgoing_ipv6_packet_seen].s6_addr, src6_addr.s6_addr, 16); + mapping_p->is_outgoing_ipv6_packet_seen +=1; + + addr_mapping_p = calloc(1, sizeof(sgi_addr_mapping_t)); + addr_mapping_p->is_outgoing_packet_seen = 1; + addr_mapping_p->enb_S1U_teid = mapping_p->enb_S1U_teid; + addr_mapping_p->sgw_S1U_teid = originating_sgw_S1u_teidP; + + src6_addr_p = malloc(sizeof(struct in6_addr)); + if (src6_addr_p == NULL) { + return -1; + } + memcpy(src6_addr_p->s6_addr, ip6h_p->saddr.s6_addr, 16); + obj_hashtbl_insert(sgi_data_pP->addr_v6_mapping, src6_addr_p,sizeof(struct in6_addr), (void*)addr_mapping_p); + } else { + SGI_IF_ERROR("Error TOO MANY IPv6 address already registered for teid %d\n", originating_sgw_S1u_teidP); + return -1; + } + } + + } else { + hash_rc = hashtbl_get(sgi_data_pP->teid_mapping, originating_sgw_S1u_teidP, (void**)&mapping_p); + } + break; + + default: + SGI_IF_WARNING("%s UNHANDLED IP VERSION: %X\n", __FUNCTION__, iph_p->version); + break; + } + + assert(mapping_p != NULL); + iov[0].iov_base = &sgi_data_pP->eh; + iov[0].iov_len = sizeof(sgi_data_pP->eh); + iov[1].iov_base = (void *)buffer_pP; + iov[1].iov_len = length; +#ifdef VLAN8021Q + sgi_data_pP->eh.ether_vlan8021q.vlan_tci = htons(0x7000 | 0x0000 | mapping_p->eps_bearer_id); +#endif + //sgi_print_hex_octets(iov[0].iov_base, iov[0].iov_len); + //sgi_print_hex_octets(iov[1].iov_base, iov[1].iov_len); + if (writev(sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], (const struct iovec *)&iov, 2) < 0) { + SGI_IF_ERROR("Error during send to socket %d bearer id %d : (%s:%d)\n", + sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], + mapping_p->eps_bearer_id, + strerror(errno), + errno); + return -1; + } + +/* if (send(sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], (void *)buffer_pP, length, 0) < 0) { + SGI_IF_ERROR("Error during send to socket %d bearer id %d : (%s:%d)\n", + sgi_data_pP->sd[mapping_p->eps_bearer_id - SGI_MIN_EPS_BEARER_ID], + mapping_p->eps_bearer_id, + strerror(errno), + errno); + return -1; + } +*/ + return 0; +} + +#endif + +#ifdef SGI_TEST +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <netinet/in.h> +#include <netinet/in_systm.h> +#include <netinet/ether.h> +#include <netinet/ip.h> +#include <netinet/ip_icmp.h> +#include <string.h> +#include <arpa/inet.h> +#include <sys/socket.h> + +#define SGI_TEST_BUFF_LEN 500 +unsigned char sgi_test_tx_buffer[SGI_TEST_BUFF_LEN]; + + +void sgi_test_send_ping(sgi_data_t *sgi_dataP, uint32_t markP, uint64_t src_mac_addrP, uint64_t dst_mac_addrP, char* src_ip_addrP, char* dst_ip_addrP) +{ +#ifdef SGI_PF_PACKET + struct ether_header *eh = (struct ether_header *) sgi_test_tx_buffer; + struct iphdr *iph = (struct iphdr *) (sgi_test_tx_buffer + sizeof(struct ether_header)); + struct icmphdr *icmp = (struct icmphdr *) (sgi_test_tx_buffer + sizeof(struct ether_header) + sizeof(struct iphdr)); +#else + struct iphdr *iph = (struct iphdr *) sgi_test_tx_buffer; + struct icmphdr *icmp = (struct icmphdr *) (sgi_test_tx_buffer + sizeof(struct iphdr)); +#endif + struct hostent *hp, *hp2; + struct in_addr ip_dst; + struct in_addr ip_src; + + + +#ifdef SGI_PF_PACKET + eh->ether_shost[0] = (u_int8_t)((src_mac_addrP & 0x0000FF0000000000) >> 40); + eh->ether_shost[1] = (u_int8_t)((src_mac_addrP & 0x000000FF00000000) >> 32); + eh->ether_shost[2] = (u_int8_t)((src_mac_addrP & 0x00000000FF000000) >> 24); + eh->ether_shost[3] = (u_int8_t)((src_mac_addrP & 0x0000000000FF0000) >> 16); + eh->ether_shost[4] = (u_int8_t)((src_mac_addrP & 0x000000000000FF00) >> 8); + eh->ether_shost[5] = (u_int8_t) (src_mac_addrP & 0x00000000000000FF); + + eh->ether_dhost[0] = (u_int8_t)((dst_mac_addrP & 0x0000FF0000000000) >> 40); + eh->ether_dhost[1] = (u_int8_t)((dst_mac_addrP & 0x000000FF00000000) >> 32); + eh->ether_dhost[2] = (u_int8_t)((dst_mac_addrP & 0x00000000FF000000) >> 24); + eh->ether_dhost[3] = (u_int8_t)((dst_mac_addrP & 0x0000000000FF0000) >> 16); + eh->ether_dhost[4] = (u_int8_t)((dst_mac_addrP & 0x000000000000FF00) >> 8); + eh->ether_dhost[5] = (u_int8_t) (dst_mac_addrP & 0x00000000000000FF); + eh->ether_type = htons(ETH_P_IP); +#endif + if ((hp = gethostbyname(dst_ip_addrP)) == NULL) + { + SGI_IF_DEBUG("gethostbyname() is OK.\n"); + if ((ip_dst.s_addr = inet_addr(dst_ip_addrP)) == -1) + { + fprintf(stderr, "%s: Can't resolve, unknown host.\n", dst_ip_addrP); + exit(1); + } + } + else + bcopy(hp->h_addr_list[0], &ip_dst.s_addr, hp->h_length); + /* The following source address just redundant for target to collect */ + if ((hp2 = gethostbyname(src_ip_addrP)) == NULL) + { + SGI_IF_DEBUG("gethostbyname() is OK.\n"); + if ((ip_src.s_addr = inet_addr(src_ip_addrP)) == -1) + { + fprintf(stderr, "%s: Can't resolve, unknown host\n", src_ip_addrP); + exit(1); + } + } + else + bcopy(hp2->h_addr_list[0], &ip_src.s_addr, hp->h_length); + printf("Sending to %08X from spoofed %08X\n", ip_dst.s_addr, ip_src.s_addr); + /* Ip structure, check the ip.h */ + iph->version = 4; + iph->ihl = sizeof *iph >> 2; + iph->tos = 0; + iph->tot_len = htons(SGI_TEST_BUFF_LEN-sizeof(struct ether_header)); + iph->id = htons(4321); + iph->frag_off = htons(0); + iph->ttl = 255; + iph->protocol = IPPROTO_ICMP; + iph->check = htons(0); + iph->saddr = ip_src.s_addr; + iph->daddr = ip_dst.s_addr; + + icmp->type = ICMP_ECHO; + icmp->code = 0; + icmp->un.echo.id = 1000; + icmp->un.echo.sequence = 10; + /* Header checksum */ + icmp->checksum = 0; + + icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr)); + iph->check = in_cksum((unsigned short *)iph, sizeof(struct iphdr)); + /* sending time */ + if (send(sgi_dataP->sd[0], sgi_test_tx_buffer, SGI_TEST_BUFF_LEN, 0) < 0) + { + SGI_IF_ERROR("sendto() error (%s:%d)\n", strerror(errno), errno); + } + else + SGI_IF_DEBUG("sendto() is OK.\n"); +} + +#endif + +#ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI + +void sgi_sock_raw_cleanup_handler(void *args_p) +{ + sgi_data_t *sgi_data_p; + int socket_index; + + sgi_data_p = ((sgi_read_thread_args_t*)args_p)->sgi_data; + socket_index = ((sgi_read_thread_args_t*)args_p)->socket_index; + + SGI_IF_DEBUG("Called %s\n", __FUNCTION__); +#ifdef SGI_PACKET_RX_RING + free(sgi_data_p->malloc_ring); + sgi_data_p->malloc_ring = NULL; + if (munmap(sgi_data_p->sock_mmap_ring, CONF_RING_FRAMES * getpagesize())) { + SGI_IF_ERROR("munmap\n"); + } else { + sgi_data_p->sock_mmap_ring = NULL; + } +#endif + if (sgi_data_p->sd[socket_index] > 0) { + close(sgi_data_p->sd[socket_index]); + SGI_IF_DEBUG("Closed soket %d\n", sgi_data_p->sd[socket_index]); + } + sgi_data_p->sd[socket_index] = -1; + + free(args_p); +} + +void* sgi_sock_raw_fw_2_gtpv1u_thread(void* args_p) +{ + sgi_data_t *sgi_data_p; + int socket_index; +#ifdef SGI_PACKET_RX_RING + struct pollfd pfd; + int i; + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + char *names[]={ + "<", /* incoming */ + "B", /* broadcast */ + "M", /* multicast */ + "P", /* promisc */ + ">", /* outgoing */ + }; +#else + int num_bytes; +#endif + sgi_data_p = ((sgi_read_thread_args_t*)args_p)->sgi_data; + socket_index = ((sgi_read_thread_args_t*)args_p)->socket_index; + + SGI_IF_DEBUG("RX thread on raw socket started, operating on Device %s.%d\n", sgi_data_p->interface_name, socket_index+SGI_MIN_EPS_BEARER_ID); + + + pthread_cleanup_push(sgi_sock_raw_cleanup_handler, args_p); + + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); + + pthread_mutex_lock (&sgi_data_p->thread_started_mutex); + sgi_data_p->thread_started += 1; + pthread_mutex_unlock (&sgi_data_p->thread_started_mutex); + +#ifdef SGI_PACKET_RX_RING + i = 0; + while (1) { + while(*(unsigned long*)sgi_data_p->malloc_ring[i].iov_base) { + struct tpacket_hdr *h=sgi_data_p->malloc_ring[i].iov_base; + struct sockaddr_ll *sll=(void *)h + TPACKET_ALIGN(sizeof(*h)); + unsigned char *bp=(unsigned char *)h + h->tp_mac; + + SGI_IF_DEBUG("%u.%.6u: if%u %s %u bytes\n", + h->tp_sec, h->tp_usec, + sll->sll_ifindex, + names[sll->sll_pkttype], + h->tp_len); + + sgi_process_raw_packet(sgi_data_p, bp, h->tp_len); + pthread_mutex_lock(&mutex); /* memory barrier */ + /* tell the kernel this packet is done with */ + h->tp_status=0; + pthread_mutex_unlock(&mutex); /* memory barrier */ + + i=(i==CONF_RING_FRAMES-1) ? 0 : i+1; + } + + /* Sleep when nothings happen */ + pfd.fd=sgi_data_p->sd; + pfd.events=POLLIN|POLLERR; + pfd.revents=0; + poll(&pfd, 1, -1); + } +#else + while (1) { + num_bytes = recvfrom(sgi_data_p->sd[socket_index], &sgi_data_p->recv_buffer[0][socket_index], SGI_BUFFER_RECV_LEN, 0, NULL, NULL); + if (num_bytes > 0) { + sgi_process_raw_packet(sgi_data_p, &sgi_data_p->recv_buffer[0][socket_index], num_bytes); + } else { + SGI_IF_DEBUG("recvfrom bearer id %d %d (%s:%d)\n", socket_index + SGI_MIN_EPS_BEARER_ID, num_bytes, strerror(errno), errno); + } + } +#endif + pthread_cleanup_pop(0); + pthread_exit(NULL); +} +#endif + diff --git a/openair-cn/SGI/sgi_task.c b/openair-cn/SGI/sgi_task.c new file mode 100644 index 0000000000..480ee77590 --- /dev/null +++ b/openair-cn/SGI/sgi_task.c @@ -0,0 +1,292 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <assert.h> +#include <stdlib.h> +#include <unistd.h> + +#include <time.h> +#include <net/if.h> + +//----------------------------------------------------------------------------- +#include "mme_config.h" +#include "intertask_interface.h" +#include "sgi.h" + +//----------------------------------------------------------------------------- +static void* sgi_task_thread(void *args_p); +static int sgi_create_endpoint_request(sgi_data_t *sgi_dataP, SGICreateEndpointReq *req_p); +static int sgi_update_endpoint_request(sgi_data_t *sgi_dataP, SGIUpdateEndpointReq *req_p); +//----------------------------------------------------------------------------- +static pthread_t fw_2_sgi_task_thread; +//----------------------------------------------------------------------------- +static void* sgi_task_thread(void *args_p) +//----------------------------------------------------------------------------- +{ + sgi_data_t *sgi_data_p; + + if (args_p == NULL) { + return NULL; + } + + intertask_interface_mark_task_ready(TASK_FW_IP); + + sgi_data_p = (sgi_data_t *)args_p; + + + while(1) { + /* Trying to fetch a message from the message queue. + * If the queue is empty, this function will block till a + * message is sent to the task. + */ + MessageDef *received_message_p; + receive_msg(TASK_FW_IP, &received_message_p); + assert(received_message_p != NULL); + switch(received_message_p->header.messageId) { + case GTPV1U_TUNNEL_DATA_IND: { + /* We received data from GTPV1_U incoming from an UE. + * Forward it host adapter. + */ + Gtpv1uTunnelDataInd *data_ind_p; + data_ind_p = &received_message_p->msg.gtpv1uTunnelDataInd; + sgi_send_data(data_ind_p->buffer, data_ind_p->length, sgi_data_p, data_ind_p->local_S1u_teid); + /* Buffer is no longer needed, free it */ + free(data_ind_p->buffer); + } + break; + case SGI_CREATE_ENDPOINT_REQUEST: { + SGICreateEndpointReq *req_p; + req_p = &received_message_p->msg.sgiCreateEndpointReq; + sgi_create_endpoint_request(sgi_data_p, req_p); + + + } + break; + + case SGI_UPDATE_ENDPOINT_REQUEST: { + SGIUpdateEndpointReq *req_p; + req_p = &received_message_p->msg.sgiUpdateEndpointReq; + sgi_update_endpoint_request(sgi_data_p, req_p); + + + } + break; + default: { + SGI_IF_ERROR("Unkwnon message ID %d\n", received_message_p->header.messageId); + } + break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + + +//------------------------------------------------------ +static int sgi_create_endpoint_request(sgi_data_t *sgi_dataP, SGICreateEndpointReq *req_p) +//------------------------------------------------------ +{ + SGICreateEndpointResp *sgi_create_endpoint_resp_p; + MessageDef *message_p; + sgi_teid_mapping_t *mapping; + + SGI_IF_DEBUG("Rx IP_FW_CREATE_SGI_ENDPOINT_REQUEST, Context: S-GW S11 teid %u, S-GW S1U teid %u EPS bearer id %u\n", + req_p->context_teid, req_p->sgw_S1u_teid, req_p->eps_bearer_id); + + message_p = alloc_new_message(TASK_FW_IP, SGI_CREATE_ENDPOINT_RESPONSE); + if (message_p == NULL) { + return -1; + } + sgi_create_endpoint_resp_p = &message_p->msg.sgiCreateEndpointResp; + sgi_create_endpoint_resp_p->context_teid = req_p->context_teid; + sgi_create_endpoint_resp_p->sgw_S1u_teid = req_p->sgw_S1u_teid; + sgi_create_endpoint_resp_p->eps_bearer_id = req_p->eps_bearer_id; + sgi_create_endpoint_resp_p->pdn_type = req_p->pdn_type; + sgi_create_endpoint_resp_p->paa = req_p->paa; + sgi_create_endpoint_resp_p->status = SGI_STATUS_OK; + + if (hashtbl_is_key_exists(sgi_dataP->teid_mapping, req_p->sgw_S1u_teid) == HASH_TABLE_OK) + { + SGI_IF_ERROR("SGI_STATUS_ERROR_CONTEXT_ALREADY_EXIST Context: S11 teid %u\n", req_p->context_teid); + sgi_create_endpoint_resp_p->status = SGI_STATUS_ERROR_CONTEXT_ALREADY_EXIST; + } else { + mapping = malloc(sizeof(sgi_teid_mapping_t)); + if (mapping == NULL) { + sgi_create_endpoint_resp_p->status = SGI_STATUS_ERROR_NO_MEMORY_AVAILABLE; + } else { + memset(mapping, 0 , sizeof(sgi_teid_mapping_t)); + + mapping->eps_bearer_id = req_p->eps_bearer_id; + mapping->enb_S1U_teid = -1; + if (hashtbl_insert(sgi_dataP->teid_mapping, req_p->sgw_S1u_teid, mapping) != 0) { + SGI_IF_ERROR("SGI_STATUS_ERROR_SYSTEM_FAILURE Context: S11 teid %u\n", req_p->context_teid); + sgi_create_endpoint_resp_p->status = SGI_STATUS_ERROR_SYSTEM_FAILURE; + free(mapping); + } else { + SGI_IF_ERROR("SGI_STATUS_OK Context: S11 teid %u\n", req_p->context_teid); + sgi_create_endpoint_resp_p->status = SGI_STATUS_OK; + } + } + } + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +//------------------------------------------------------ +static int sgi_update_endpoint_request(sgi_data_t *sgi_dataP, SGIUpdateEndpointReq *req_p) +//------------------------------------------------------ +{ + SGIUpdateEndpointResp *sgi_update_endpoint_resp_p = NULL; + MessageDef *message_p = NULL; + sgi_teid_mapping_t *mapping = NULL; + + SGI_IF_DEBUG("Rx IP_FW_UPDATE_SGI_ENDPOINT_REQUEST, Context: S-GW S11 teid %u, S-GW S1U teid %u EPS bearer id %u\n", + req_p->context_teid, req_p->sgw_S1u_teid, req_p->eps_bearer_id); + + message_p = alloc_new_message(TASK_FW_IP, SGI_UPDATE_ENDPOINT_RESPONSE); + if (message_p == NULL) { + return -1; + } + sgi_update_endpoint_resp_p = &message_p->msg.sgiUpdateEndpointResp; + sgi_update_endpoint_resp_p->context_teid = req_p->context_teid; + sgi_update_endpoint_resp_p->sgw_S1u_teid = req_p->sgw_S1u_teid; + sgi_update_endpoint_resp_p->eps_bearer_id = req_p->eps_bearer_id; + sgi_update_endpoint_resp_p->enb_S1u_teid = req_p->enb_S1u_teid; + sgi_update_endpoint_resp_p->status = SGI_STATUS_OK; + + if (hashtbl_get(sgi_dataP->teid_mapping, req_p->sgw_S1u_teid, (void**)&mapping) == HASH_TABLE_OK) + { + mapping->enb_S1U_teid = req_p->enb_S1u_teid; + } else { + SGI_IF_ERROR("SGI_STATUS_ERROR_CONTEXT_NOT_FOUND Context: S11 teid %u\n", req_p->context_teid); + sgi_update_endpoint_resp_p->status = SGI_STATUS_ERROR_CONTEXT_NOT_FOUND; + } + return send_msg_to_task(TASK_SPGW_APP, INSTANCE_DEFAULT, message_p); +} + +//----------------------------------------------------------------------------- +int sgi_init(const mme_config_t *mme_config_p) +//----------------------------------------------------------------------------- +{ + + volatile sgi_data_t *sgi_data_p; + int len; + int i; + + SGI_IF_DEBUG("Initializing FW_IP task interface\n"); + + sgi_data_p = malloc(sizeof(sgi_data_t)); + memset((void *)sgi_data_p, 0, sizeof(sgi_data_t)); + for (i=0; i < SGI_MAX_EPS_BEARERS_PER_USER; i++) { + sgi_data_p->sd[i] = -1; + } + + sgi_data_p->thread_started = 0; + pthread_mutex_init (&sgi_data_p->thread_started_mutex, NULL); + + sgi_data_p->teid_mapping = hashtbl_create (SGI_MAX_EPS_BEARERS, NULL, NULL); + if (sgi_data_p->teid_mapping == NULL) { + SGI_IF_ERROR("Failed to create SGI hashtable teid_mapping\n"); + return -1; + } + + sgi_data_p->addr_v4_mapping = hashtbl_create (SGI_MAX_SERVED_USERS_PER_PGW, NULL, NULL); + if (sgi_data_p->addr_v4_mapping == NULL) { + SGI_IF_ERROR("Failed to create SGI hashtable addr_v4_mapping\n"); + return -1; + } + + sgi_data_p->addr_v6_mapping = obj_hashtbl_create (SGI_MAX_SERVED_USERS_PER_PGW, NULL, NULL, NULL); + if (sgi_data_p->addr_v6_mapping == NULL) { + SGI_IF_ERROR("Failed to create SGI hashtable addr_v6_mapping\n"); + return -1; + } + + + len = strlen(mme_config_p->ipv4.pgw_interface_name_for_SGI); + sgi_data_p->interface_name = calloc(len + 1, sizeof(char)); + memcpy(sgi_data_p->interface_name, mme_config_p->ipv4.pgw_interface_name_for_SGI, len); + sgi_data_p->interface_name[len] = '\0'; + sgi_data_p->ipv4_addr = mme_config_p->ipv4.pgw_ip_addr_for_SGI; + + sgi_data_p->interface_index = if_nametoindex(sgi_data_p->interface_name); + + + if (sgi_create_sockets(sgi_data_p) < 0) { + SGI_IF_ERROR("Could not create socket, leaving thread %s\n", __FUNCTION__); + free(sgi_data_p); + return -1; + } + + if (pthread_create(&fw_2_sgi_task_thread, NULL, &sgi_task_thread, (void *)sgi_data_p) < 0) { + SGI_IF_ERROR("sgi_task_thread pthread_create: %s", strerror(errno)); + return -1; + } + +#ifdef ENABLE_USE_PCAP_FOR_SGI + if (pthread_create(&sgi_data_p->capture_on_sgi_if_thread, NULL, &sgi_pcap_fw_2_gtpv1u_thread, (void *)sgi_data_p) < 0) { + SGI_IF_ERROR("sgi_pcap_fw_2_gtpv1u_thread pthread_create: %s", strerror(errno)); + return -1; + } +#endif +#ifdef ENABLE_USE_NETFILTER_FOR_SGI + if (pthread_create(&sgi_data_p->capture_on_sgi_if_thread, NULL, &sgi_nf_fw_2_gtpv1u_thread, (void *)sgi_data_p) < 0) { + SGI_IF_ERROR("sgi_nf_fw_2_gtpv1u_thread pthread_create: %s", strerror(errno)); + return -1; + } +#endif +#ifdef ENABLE_USE_RAW_SOCKET_FOR_SGI + for (i=0; i < SGI_MAX_EPS_BEARERS_PER_USER; i++) { + sgi_read_thread_args_t *args_p = malloc(sizeof(sgi_read_thread_args_t)); + args_p->sgi_data = sgi_data_p; + args_p->socket_index = i; + if (pthread_create(&sgi_data_p->capture_on_sgi_if_thread, NULL, &sgi_sock_raw_fw_2_gtpv1u_thread, (void *)args_p) < 0) { + SGI_IF_ERROR("sgi_sock_raw_fw_2_gtpv1u_thread pthread_create: %s", strerror(errno)); + return -1; + } + } +#endif + + while (sgi_data_p->thread_started != SGI_MAX_EPS_BEARERS_PER_USER ) { + usleep(1000); + } + /*SGI_IF_DEBUG("ARP RESOLVING ROUTER...\n"); + while (sgi_data_p->hw_address_of_router_captured == 0) { + sgi_send_arp_request(sgi_data_p, "router.eur"); + sleep(2); + }*/ + SGI_IF_DEBUG("Initializing FW_IP task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/SGI/sgi_util.c b/openair-cn/SGI/sgi_util.c new file mode 100755 index 0000000000..4978be429a --- /dev/null +++ b/openair-cn/SGI/sgi_util.c @@ -0,0 +1,208 @@ +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <netdb.h> +#include <sys/socket.h> +#include <arpa/inet.h> +#include <net/if_arp.h> +#include <netinet/in.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include "sgi.h" + +#define FW_2_PRINT_BUFFER_LEN 10000 +static char fw_2_print_buffer[FW_2_PRINT_BUFFER_LEN]; +//----------------------------------------------------------------------------- +void sgi_print_hex_octets(unsigned char* dataP, unsigned long sizeP) +//----------------------------------------------------------------------------- +{ + unsigned long octet_index = 0; + unsigned long buffer_marker = 0; + unsigned char aindex; + + if (dataP == NULL) { + return; + } + + + SGI_IF_DEBUG("------+-------------------------------------------------|\n"); + SGI_IF_DEBUG(" | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n"); + SGI_IF_DEBUG("------+-------------------------------------------------|\n"); + for (octet_index = 0; octet_index < sizeP; octet_index++) { + if ((octet_index % 16) == 0){ + if (octet_index != 0) { + buffer_marker+=snprintf(&fw_2_print_buffer[buffer_marker], FW_2_PRINT_BUFFER_LEN - buffer_marker, " |\n"); + SGI_IF_DEBUG("%s", fw_2_print_buffer); + buffer_marker = 0; + } + buffer_marker+=snprintf(&fw_2_print_buffer[buffer_marker], FW_2_PRINT_BUFFER_LEN - buffer_marker, " %04ld |", octet_index); + } + /* + * Print every single octet in hexadecimal form + */ + buffer_marker+=snprintf(&fw_2_print_buffer[buffer_marker], FW_2_PRINT_BUFFER_LEN - buffer_marker, " %02x", dataP[octet_index]); + /* + * Align newline and pipes according to the octets in groups of 2 + */ + } + + /* + * Append enough spaces and put final pipe + */ + for (aindex = octet_index; aindex < 16; ++aindex) + buffer_marker+=snprintf(&fw_2_print_buffer[buffer_marker], FW_2_PRINT_BUFFER_LEN - buffer_marker, " "); + //SGI_IF_DEBUG(" "); + buffer_marker+=snprintf(&fw_2_print_buffer[buffer_marker], FW_2_PRINT_BUFFER_LEN - buffer_marker, " |\n"); + SGI_IF_DEBUG("%s",fw_2_print_buffer); +} + +//----------------------------------------------------------------------------- +char* sgi_status_2_str(SGIStatus_t statusP) +//----------------------------------------------------------------------------- +{ + switch (statusP) { + case SGI_STATUS_OK: return "SGI_STATUS_OK";break; + case SGI_STATUS_ERROR_CONTEXT_ALREADY_EXIST: return "SGI_STATUS_ERROR_CONTEXT_ALREADY_EXIST";break; + case SGI_STATUS_ERROR_CONTEXT_NOT_FOUND: return "SGI_STATUS_ERROR_CONTEXT_NOT_FOUND";break; + case SGI_STATUS_ERROR_INVALID_MESSAGE_FORMAT: return "SGI_STATUS_ERROR_INVALID_MESSAGE_FORMAT";break; + case SGI_STATUS_ERROR_SERVICE_NOT_SUPPORTED: return "SGI_STATUS_ERROR_SERVICE_NOT_SUPPORTED";break; + case SGI_STATUS_ERROR_SYSTEM_FAILURE: return "SGI_STATUS_ERROR_SYSTEM_FAILURE";break; + case SGI_STATUS_ERROR_NO_RESOURCES_AVAILABLE: return "SGI_STATUS_ERROR_NO_RESOURCES_AVAILABLE";break; + case SGI_STATUS_ERROR_NO_MEMORY_AVAILABLE: return "SGI_STATUS_ERROR_NO_MEMORY_AVAILABLE";break; + default: return "UNKNOWN_SGI_STATUS"; + } +} + +//----------------------------------------------------------------------------- +char* sgi_arpopcode_2_str(unsigned short int opcodeP) +//----------------------------------------------------------------------------- +{ + switch (opcodeP) { + case ARPOP_REQUEST: return "ARPOP_REQUEST";break; + case ARPOP_REPLY: return "ARPOP_REPLY";break; + case ARPOP_RREQUEST: return "ARPOP_RREQUEST";break; + case ARPOP_RREPLY: return "ARPOP_RREPLY";break; + case ARPOP_InREQUEST: return "ARPOP_InREQUEST";break; + case ARPOP_InREPLY: return "ARPOP_InREPLY";break; + case ARPOP_NAK: return "ARPOP_NAK";break; + default: return "UNKNOWN_ARP_OPCODE"; + } +} +//----------------------------------------------------------------------------- +unsigned short in_cksum(unsigned short *addr, int len) +//----------------------------------------------------------------------------- +{ + register int sum = 0; + u_short answer = 0; + register u_short *w = addr; + register int nleft = len; + /* + * Our algorithm is simple, using a 32 bit accumulator (sum), we add + * sequential 16 bit words to it, and at the end, fold back all the + * carry bits from the top 16 bits into the lower 16 bits. + */ + while (nleft > 1) + { + sum += *w++; + nleft -= 2; + } + /* mop up an odd byte, if necessary */ + if (nleft == 1) + { + *(u_char *) (&answer) = *(u_char *) w; + sum += answer; + } + /* add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + answer = ~sum; /* truncate to 16 bits */ + return (answer); +} +//----------------------------------------------------------------------------- +void sgi_send_arp_request(sgi_data_t *sgi_dataP, char* dst_ip_addrP) +//----------------------------------------------------------------------------- +{ + char buffer[100]; // ARP request is 60 bytes including ethernet + struct arphdr_s *arph = (struct arphdr_s *)(buffer); + struct hostent *hp = NULL; + uint32_t i; + struct in_addr ip_dst; + struct ifreq ifr; + struct iovec iov[2]; + + sgi_dataP->eh.ether_dhost[0] = (u_int8_t)(0xFF); + sgi_dataP->eh.ether_dhost[1] = (u_int8_t)(0xFF); + sgi_dataP->eh.ether_dhost[2] = (u_int8_t)(0xFF); + sgi_dataP->eh.ether_dhost[3] = (u_int8_t)(0xFF); + sgi_dataP->eh.ether_dhost[4] = (u_int8_t)(0xFF); + sgi_dataP->eh.ether_dhost[5] = (u_int8_t)(0xFF); + + // get IP address of the default virtual interface + ifr.ifr_addr.sa_family = AF_INET; + sprintf(ifr.ifr_name, "%s.%d",sgi_dataP->interface_name,SGI_MIN_EPS_BEARER_ID); + if (ioctl(sgi_dataP->sd[0], SIOCGIFADDR, &ifr) != 0) { + SGI_IF_ERROR("Error during IP ADDRESS RETRIEVAL ON SGI INTERFACE (%s:%d)\n",strerror(errno), errno); + exit (-1); + } + + if ((hp = gethostbyname(dst_ip_addrP)) == NULL) + { + SGI_IF_DEBUG("gethostbyname() is OK.\n"); + if ((ip_dst.s_addr = inet_addr(dst_ip_addrP)) == -1) + { + SGI_IF_ERROR("%s: Can't resolve, unknown host.\n", dst_ip_addrP); + exit(1); + } + } + else + bcopy(hp->h_addr_list[0], &ip_dst.s_addr, hp->h_length); + + arph->ar_hrd = htons(ARPHRD_ETHER); + arph->ar_pro = htons(ETH_P_IP); + arph->ar_hln = ETH_ALEN; + arph->ar_pln = 4; + arph->ar_op = htons(ARPOP_REQUEST); + + // sources + memcpy(arph->ar_sha, sgi_dataP->eh.ether_shost, ETH_ALEN); + + i = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr.s_addr; + arph->ar_sip[3] = i >> 24; + arph->ar_sip[2] = (i & 0x00FF0000) >> 16; + arph->ar_sip[1] = (i & 0x0000FF00) >> 8; + arph->ar_sip[0] = (i & 0x000000FF); + + // destinations + memset(arph->ar_tha, 0, ETH_ALEN); + + i = ip_dst.s_addr; + arph->ar_tip[3] = i >> 24; + arph->ar_tip[2] = (i & 0x00FF0000) >> 16; + arph->ar_tip[1] = (i & 0x0000FF00) >> 8; + arph->ar_tip[0] = (i & 0x000000FF); + // save ip address of router for comparing with ARP REPLY + sgi_dataP->ipv4_addr_of_router = ip_dst.s_addr; + + iov[0].iov_base = &sgi_dataP->eh; + iov[0].iov_len = sizeof(sgi_dataP->eh); + iov[1].iov_base = (void *)buffer; + iov[1].iov_len = sizeof (struct arphdr) + ETH_ALEN*2 + 4*2; +#ifdef VLAN8021Q + sgi_data_p->eh.ether_vlan8021q.vlan_tpid = htons(0x8100); + sgi_dataP->eh.ether_vlan8021q.vlan_tci = htons(0x7000 | 0x0000 | SGI_MIN_EPS_BEARER_ID); +#endif + sgi_dataP->eh.ether_type = htons(ETH_P_ARP); + + sgi_print_hex_octets(iov[0].iov_base, iov[0].iov_len); + sgi_print_hex_octets(iov[1].iov_base, iov[1].iov_len); + if (writev(sgi_dataP->sd[0], (const struct iovec *)&iov, 2) < 0) { + SGI_IF_ERROR("Error during send ARP to socket %d bearer id %d : (%s:%d)\n", + sgi_dataP->sd[0], + SGI_MIN_EPS_BEARER_ID, + strerror(errno), + errno); + exit(1); + } + +} + diff --git a/openair-cn/SGW-LITE/Makefile.am b/openair-cn/SGW-LITE/Makefile.am new file mode 100644 index 0000000000..7a5505a5b4 --- /dev/null +++ b/openair-cn/SGW-LITE/Makefile.am @@ -0,0 +1,16 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/MME_APP \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/HASHTABLE + +noinst_LTLIBRARIES = libsgw_lite.la +libsgw_lite_la_LDFLAGS = -all-static + +libsgw_lite_la_SOURCES= \ + s11_causes.c s11_causes.h \ + sgw_lite_task.c \ + sgw_lite_handlers.c sgw_lite_handlers.h \ + sgw_lite_context_manager.c sgw_lite_context_manager.h \ + sgw_lite.h diff --git a/openair-cn/SGW-LITE/s11_causes.c b/openair-cn/SGW-LITE/s11_causes.c new file mode 100644 index 0000000000..21476f764c --- /dev/null +++ b/openair-cn/SGW-LITE/s11_causes.c @@ -0,0 +1,88 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +#include "s11_causes.h" +#include "common_types.h" +#include "sgw_lite_ie_defs.h" + +static const SGWCauseMapping_t causes[] = { + { LOCAL_DETACH, "Local detach", 0, 0, 0, 0 }, + { COMPLETE_DETACH, "Complete detach", 0, 0, 0, 0 }, + { RAT_CHANGE_3GPP_TO_NON_3GPP, "From 3GPP to non 3GPP RAT change", 0, 0, 0, 0 }, + { ISR_DEACTIVATION, "ISR deactivation", 0, 0, 0, 0 }, + { ERROR_IND_FROM_RNC_ENB_SGSN, "Error ind received from RNC/eNB/SGSN", 0, 0, 0, 0 }, + { IMSI_DETACH_ONLY, "IMSI detach only", 0, 0, 0, 0 }, + { REQUEST_ACCEPTED, "Request accepted", 1, 1, 1, 1 }, + { REQUEST_ACCEPTED_PARTIALLY, "Request accepted partially", 1, 1, 1, 0 }, + { NEW_PDN_TYPE_NW_PREF, "New PDN type network preference", 1, 0, 0, 0 }, + { NEW_PDN_TYPE_SAB_ONLY, "New PDN type single address bearer only", 1, 0, 0, 0 }, + { CONTEXT_NOT_FOUND, "Context not found", 0, 1, 1, 1 }, + { INVALID_MESSAGE_FORMAT, "Invalid message format", 1, 1, 1, 1 }, + { INVALID_LENGTH, "Invalid length", 1, 1, 1, 0 }, + { SERVICE_NOT_SUPPORTED, "Service not supported", 0, 0, 1, 0 }, + { SYSTEM_FAILURE, "System failure", 1, 1, 1, 0 }, + { NO_RESOURCES_AVAILABLE, "No resources available", 1, 0, 0, 0 }, + { MISSING_OR_UNKNOWN_APN, "Missing or unknown APN", 1, 0, 0, 0 }, + { GRE_KEY_NOT_FOUND, "GRE KEY not found", 1, 0, 0, 0 }, + { DENIED_IN_RAT, "Denied in RAT", 1, 1, 0, 0 }, + { UE_NOT_RESPONDING, "UE not responding", 0, 1, 0, 0 }, + { SERVICE_DENIED, "Service Denied", 0, 0, 0, 0 }, + { UNABLE_TO_PAGE_UE, "Unable to page UE", 0, 1, 0, 0 }, + { NO_MEMORY_AVAILABLE, "No memory available", 1, 1, 1, 0 }, + { REQUEST_REJECTED, "Request rejected", 1, 1, 1, 0 }, + { INVALID_PEER, "Invalid peer", 0, 0, 0, 1 }, + { TEMP_REJECT_HO_IN_PROGRESS, "Temporarily rejected due to HO in progress",0, 0, 0, 0 }, + { M_PDN_APN_NOT_ALLOWED, "Multiple PDN for a given APN not allowed", 1, 0, 0, 0 }, + { 0, NULL, 0, 0, 0, 0 }, +}; + +static int compare_cause_id(const void *m1, const void *m2) +{ + struct SGWCauseMapping_e *scm1 = (struct SGWCauseMapping_e*)m1; + struct SGWCauseMapping_e *scm2 = (struct SGWCauseMapping_e*)m2; + + return (scm1->value - scm2->value); +} + +char *sgw_cause_2_string(uint8_t cause_value) +{ + SGWCauseMapping_t *res, key; + key.value = cause_value; + res = bsearch(&key, causes, sizeof(causes), sizeof(SGWCauseMapping_t), compare_cause_id); + if (res == NULL) { + return "Unknown cause"; + } else { + return res->name; + } +} diff --git a/openair-cn/SGW-LITE/s11_causes.h b/openair-cn/SGW-LITE/s11_causes.h new file mode 100644 index 0000000000..545b04a20c --- /dev/null +++ b/openair-cn/SGW-LITE/s11_causes.h @@ -0,0 +1,47 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef S11_CAUSES_H_ +#define S11_CAUSES_H_ + +typedef struct SGWCauseMapping_e { + uint8_t value; + /* Displayable cause name */ + char *name; + /* Possible cause in message? */ + unsigned create_session_response:1; + unsigned create_bearer_response:1; + unsigned modify_bearer_response:1; + unsigned delete_session_response:1; +} SGWCauseMapping_t; + +char *sgw_cause_2_string(uint8_t cause_value); + +#endif /* S11_CAUSES_H_ */ diff --git a/openair-cn/SGW-LITE/sgw_lite.h b/openair-cn/SGW-LITE/sgw_lite.h new file mode 100755 index 0000000000..76d71c7a6f --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite.h @@ -0,0 +1,63 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef SGW_LITE_H_ +#define SGW_LITE_H_ + +#include "hashtable.h" +#include "tree.h" +#include "commonDef.h" +#include "common_types.h" +#include "sgw_lite_context_manager.h" + +typedef struct sgw_app_s{ + + char *sgw_interface_name_for_S1u_S12_S4_up; + uint32_t sgw_ip_address_for_S1u_S12_S4_up; + + char *sgw_interface_name_for_S11_S4; // unused now + uint32_t sgw_ip_address_for_S11_S4; // unused now + + uint32_t sgw_ip_address_for_S5_S8_up; // unused now + + // key is S11 S-GW local teid + hash_table_t *s11teid2mme_hashtable; + + // key is S1-U S-GW local teid + hash_table_t *s1uteid2enb_hashtable; + + // the key of this hashtable is the S11 s-gw local teid. + hash_table_t *s11_bearer_context_information_hashtable; + + +} sgw_app_t; + +#endif + diff --git a/openair-cn/SGW-LITE/sgw_lite_context_manager.c b/openair-cn/SGW-LITE/sgw_lite_context_manager.c new file mode 100644 index 0000000000..acc08abe8b --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_context_manager.c @@ -0,0 +1,364 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "tree.h" +#include "hashtable.h" + +#include "intertask_interface.h" +#include "sgw_lite_defs.h" +#include "sgw_lite_context_manager.h" +#include "sgw_lite.h" + +extern sgw_app_t sgw_app; + + +//----------------------------------------------------------------------------- +static void sgw_lite_display_s11teid2mme_mapping(uint64_t keyP, void *dataP, void* unusedParameterP) +//----------------------------------------------------------------------------- +{ + mme_sgw_tunnel_t * mme_sgw_tunnel= NULL; + + if (dataP != NULL) { + mme_sgw_tunnel = (mme_sgw_tunnel_t *)dataP; + SPGW_APP_DEBUG("| %u\t<------------->\t%u\n", mme_sgw_tunnel->remote_teid, mme_sgw_tunnel->local_teid); + } else { + SPGW_APP_DEBUG("INVALID S11 TEID MAPPING FOUND\n"); + } +} +//----------------------------------------------------------------------------- +void sgw_lite_display_s11teid2mme_mappings(void) +//----------------------------------------------------------------------------- +{ + SPGW_APP_DEBUG("+--------------------------------------+\n"); + SPGW_APP_DEBUG("| MME <--- S11 TE ID MAPPINGS ---> SGW |\n"); + SPGW_APP_DEBUG("+--------------------------------------+\n"); + hashtbl_apply_funct_on_elements(sgw_app.s11teid2mme_hashtable, sgw_lite_display_s11teid2mme_mapping, NULL); + SPGW_APP_DEBUG("+--------------------------------------+\n"); +} +//----------------------------------------------------------------------------- +static void sgw_lite_display_pdn_connection_sgw_eps_bearers(uint64_t keyP, void *dataP, void* unusedParameterP) +//----------------------------------------------------------------------------- +{ + sgw_eps_bearer_entry_t *eps_bearer_entry = NULL; + + if (dataP != NULL) { + eps_bearer_entry = (sgw_eps_bearer_entry_t *)dataP; + SPGW_APP_DEBUG("|\t\t\t\t%"PRId64"\t<-> ebi: %u, enb_teid_for_S1u: %u, s_gw_teid_for_S1u_S12_S4_up: %u (tbc)\n", + keyP, + eps_bearer_entry->eps_bearer_id, + eps_bearer_entry->enb_teid_for_S1u, + eps_bearer_entry->s_gw_teid_for_S1u_S12_S4_up); + } else { + SPGW_APP_DEBUG("\t\t\t\tINVALID eps_bearer_entry FOUND\n"); + } +} + +//----------------------------------------------------------------------------- +static void sgw_lite_display_s11_bearer_context_information(uint64_t keyP, void *dataP, void* unusedParameterP) +//----------------------------------------------------------------------------- +{ + s_plus_p_gw_eps_bearer_context_information_t * sp_context_information= NULL; + hashtbl_rc_t hash_rc; + + if (dataP != NULL) { + sp_context_information = (s_plus_p_gw_eps_bearer_context_information_t *)dataP; + SPGW_APP_DEBUG("| KEY %"PRId64": \n", keyP); + SPGW_APP_DEBUG("|\tsgw_eps_bearer_context_information: |\n"); + //Imsi_t imsi; ///< IMSI (International Mobile Subscriber Identity) is the subscriber permanent identity. + SPGW_APP_DEBUG("|\t\timsi_unauthenticated_indicator:\t%u\n", sp_context_information->sgw_eps_bearer_context_information.imsi_unauthenticated_indicator); + //char msisdn[MSISDN_LENGTH]; ///< The basic MSISDN of the UE. The presence is dictated by its storage in the HSS. + SPGW_APP_DEBUG("|\t\tmme_teid_for_S11: \t%u\n", sp_context_information->sgw_eps_bearer_context_information.mme_teid_for_S11); + //ip_address_t mme_ip_address_for_S11; ///< MME IP address the S11 interface. + SPGW_APP_DEBUG("|\t\ts_gw_teid_for_S11_S4: \t%u\n", sp_context_information->sgw_eps_bearer_context_information.s_gw_teid_for_S11_S4); + //ip_address_t s_gw_ip_address_for_S11_S4; ///< S-GW IP address for the S11 interface and the S4 Interface (control plane). + //cgi_t last_known_cell_Id; ///< This is the last location of the UE known by the network + + SPGW_APP_DEBUG("|\t\tpdn_connection:\n"); + SPGW_APP_DEBUG("|\t\t\tapn_in_use: %s\n", sp_context_information->sgw_eps_bearer_context_information.pdn_connection.apn_in_use); + SPGW_APP_DEBUG("|\t\t\tdefault_bearer: %u\n", sp_context_information->sgw_eps_bearer_context_information.pdn_connection.default_bearer); + SPGW_APP_DEBUG("|\t\t\teps_bearers:\n"); + + hash_rc = hashtbl_apply_funct_on_elements(sp_context_information->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, + sgw_lite_display_pdn_connection_sgw_eps_bearers, + NULL); + if (hash_rc != HASH_TABLE_OK) { + SPGW_APP_DEBUG("Invalid sgw_eps_bearers hashtable for display\n"); + } + + //void *trxn; + //uint32_t peer_ip; + } else { + SPGW_APP_DEBUG("INVALID s_plus_p_gw_eps_bearer_context_information FOUND\n"); + } +} +//----------------------------------------------------------------------------- +void sgw_lite_display_s11_bearer_context_information_mapping(void) +//----------------------------------------------------------------------------- +{ + SPGW_APP_DEBUG("+-----------------------------------------+\n"); + SPGW_APP_DEBUG("| S11 BEARER CONTEXT INFORMATION MAPPINGS |\n"); + SPGW_APP_DEBUG("+-----------------------------------------+\n"); + hashtbl_apply_funct_on_elements(sgw_app.s11_bearer_context_information_hashtable, sgw_lite_display_s11_bearer_context_information, NULL); + SPGW_APP_DEBUG("+--------------------------------------+\n"); +} +//----------------------------------------------------------------------------- +void pgw_lite_cm_free_apn(pgw_apn_t *apnP) +//----------------------------------------------------------------------------- +{ + if (apnP != NULL) { + if (apnP->pdn_connections != NULL) { + obj_hashtbl_destroy(apnP->pdn_connections); + } + } +} +//----------------------------------------------------------------------------- +Teid_t sgw_lite_get_new_S11_tunnel_id(void) +//----------------------------------------------------------------------------- +{ + // TO DO: RANDOM + static Teid_t tunnel_id = 0; + tunnel_id += 1; + return tunnel_id; +} + +//----------------------------------------------------------------------------- +mme_sgw_tunnel_t *sgw_lite_cm_create_s11_tunnel(Teid_t remote_teid, Teid_t local_teid) +//----------------------------------------------------------------------------- +{ + + mme_sgw_tunnel_t *new_tunnel; + + new_tunnel = malloc(sizeof(mme_sgw_tunnel_t)); + + if (new_tunnel == NULL) { + /* Malloc failed, may be ENOMEM error */ + SPGW_APP_ERROR("Failed to create tunnel for remote_teid %u\n", remote_teid); + return NULL; + } + + new_tunnel->remote_teid = remote_teid; + new_tunnel->local_teid = local_teid; + + /* Trying to insert the new tunnel into the tree. + * If collision_p is not NULL (0), it means tunnel is already present. + */ + hashtbl_insert(sgw_app.s11teid2mme_hashtable, local_teid, new_tunnel); + + return new_tunnel; +} + +//----------------------------------------------------------------------------- +int sgw_lite_cm_remove_s11_tunnel(Teid_t local_teid) +//----------------------------------------------------------------------------- +{ + int temp; + + temp = hashtbl_remove(sgw_app.s11teid2mme_hashtable, local_teid); + + return temp; +} + +//----------------------------------------------------------------------------- +sgw_eps_bearer_entry_t * sgw_lite_cm_create_eps_bearer_entry(void) +//----------------------------------------------------------------------------- +{ + sgw_eps_bearer_entry_t *eps_bearer_entry; + + eps_bearer_entry = malloc(sizeof(sgw_eps_bearer_entry_t)); + + if (eps_bearer_entry == NULL) { + /* Malloc failed, may be ENOMEM error */ + SPGW_APP_ERROR("Failed to create new EPS bearer object\n"); + return NULL; + } + return eps_bearer_entry; +} + + +//----------------------------------------------------------------------------- +sgw_pdn_connection_t * sgw_lite_cm_create_pdn_connection(void) +//----------------------------------------------------------------------------- +{ + sgw_pdn_connection_t *pdn_connection; + + pdn_connection = malloc(sizeof(sgw_pdn_connection_t)); + + if (pdn_connection == NULL) { + /* Malloc failed, may be ENOMEM error */ + SPGW_APP_ERROR("Failed to create new PDN connection object\n"); + return NULL; + } + memset(pdn_connection, 0, sizeof(sgw_pdn_connection_t)); + + pdn_connection->sgw_eps_bearers = hashtbl_create(12, NULL, NULL); + if ( pdn_connection->sgw_eps_bearers == NULL) { + SPGW_APP_ERROR("Failed to create eps bearers collection object\n"); + free(pdn_connection); + return NULL; + } + + return pdn_connection; +} +//----------------------------------------------------------------------------- +void sgw_lite_cm_free_pdn_connection(sgw_pdn_connection_t *pdn_connectionP) +//----------------------------------------------------------------------------- +{ + if (pdn_connectionP != NULL) { + if (pdn_connectionP->sgw_eps_bearers != NULL) { + hashtbl_destroy(pdn_connectionP->sgw_eps_bearers); + } + } +} +//----------------------------------------------------------------------------- +void sgw_lite_cm_free_s_plus_p_gw_eps_bearer_context_information(s_plus_p_gw_eps_bearer_context_information_t *contextP) +//----------------------------------------------------------------------------- +{ + if (contextP == NULL) { + return; + } + /*if (contextP->sgw_eps_bearer_context_information.pdn_connections != NULL) { + obj_hashtbl_destroy(contextP->sgw_eps_bearer_context_information.pdn_connections); + }*/ + if (contextP->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers != NULL) { + hashtbl_destroy(contextP->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers); + } + + if (contextP->pgw_eps_bearer_context_information.apns != NULL) { + obj_hashtbl_destroy(contextP->pgw_eps_bearer_context_information.apns); + } + free(contextP); +} + +//----------------------------------------------------------------------------- +s_plus_p_gw_eps_bearer_context_information_t * sgw_lite_cm_create_bearer_context_information_in_collection(Teid_t teid) +//----------------------------------------------------------------------------- +{ + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information; + + new_bearer_context_information = malloc(sizeof(s_plus_p_gw_eps_bearer_context_information_t)); + + if (new_bearer_context_information == NULL) { + /* Malloc failed, may be ENOMEM error */ + SPGW_APP_ERROR("Failed to create new bearer context information object for S11 remote_teid %u\n", teid); + return NULL; + } + memset(new_bearer_context_information, 0, sizeof(s_plus_p_gw_eps_bearer_context_information_t)); + SPGW_APP_DEBUG("sgw_lite_cm_create_bearer_context_information_in_collection %d\n", teid); + + /*new_bearer_context_information->sgw_eps_bearer_context_information.pdn_connections = obj_hashtbl_create(32, NULL, NULL, sgw_lite_cm_free_pdn_connection); + + if ( new_bearer_context_information->sgw_eps_bearer_context_information.pdn_connections == NULL) { + SPGW_APP_ERROR("Failed to create PDN connections collection object entry for EPS bearer teid %u \n", teid); + sgw_lite_cm_free_s_plus_p_gw_eps_bearer_context_information(new_bearer_context_information); + return NULL; + }*/ + + new_bearer_context_information->pgw_eps_bearer_context_information.apns = obj_hashtbl_create(32, NULL, NULL, pgw_lite_cm_free_apn); + + if ( new_bearer_context_information->pgw_eps_bearer_context_information.apns == NULL) { + SPGW_APP_ERROR("Failed to create APN collection object entry for EPS bearer S11 teid %u \n", teid); + sgw_lite_cm_free_s_plus_p_gw_eps_bearer_context_information(new_bearer_context_information); + return NULL; + } + + /* Trying to insert the new tunnel into the tree. + * If collision_p is not NULL (0), it means tunnel is already present. + */ + hashtbl_insert(sgw_app.s11_bearer_context_information_hashtable, teid, new_bearer_context_information); + SPGW_APP_DEBUG("Added new s_plus_p_gw_eps_bearer_context_information_t in s11_bearer_context_information_hashtable key teid %u\n", teid); + + return new_bearer_context_information; +} + +int sgw_lite_cm_remove_bearer_context_information(Teid_t teid) { + int temp; + temp = hashtbl_remove(sgw_app.s11_bearer_context_information_hashtable, teid); + return temp; +} + +//--- EPS Bearer Entry + +//----------------------------------------------------------------------------- +sgw_eps_bearer_entry_t * sgw_lite_cm_create_eps_bearer_entry_in_collection(hash_table_t *eps_bearersP, ebi_t eps_bearer_idP) +//----------------------------------------------------------------------------- +{ + sgw_eps_bearer_entry_t *new_eps_bearer_entry; + hashtbl_rc_t hash_rc = HASH_TABLE_OK; + + if (eps_bearersP == NULL) { + SPGW_APP_ERROR("Failed to create EPS bearer entry for EPS bearer id %u. reason eps bearer hashtable is NULL \n", eps_bearer_idP); + return NULL; + } + new_eps_bearer_entry = malloc(sizeof(sgw_eps_bearer_entry_t)); + + if (new_eps_bearer_entry == NULL) { + /* Malloc failed, may be ENOMEM error */ + SPGW_APP_ERROR("Failed to create EPS bearer entry for EPS bearer id %u \n", eps_bearer_idP); + return NULL; + } + memset(new_eps_bearer_entry, 0, sizeof(sgw_eps_bearer_entry_t)); + + new_eps_bearer_entry->eps_bearer_id = eps_bearer_idP; + + hash_rc = hashtbl_insert(eps_bearersP, eps_bearer_idP, new_eps_bearer_entry); + SPGW_APP_DEBUG("Inserted new EPS bearer entry for EPS bearer id %u status %s\n", eps_bearer_idP, hashtble_rc_code2string(hash_rc)); + + hash_rc = hashtbl_apply_funct_on_elements(eps_bearersP, + sgw_lite_display_pdn_connection_sgw_eps_bearers, + NULL); + if (hash_rc != HASH_TABLE_OK) { + SPGW_APP_DEBUG("Invalid sgw_eps_bearers hashtable for display\n"); + } + /* CHECK DUPLICATES IN HASH TABLES ? if (temp == 1) { + SPGW_APP_WARNING("This EPS bearer entry already exists: %u\n", eps_bearer_idP); + free(new_eps_bearer_entry); + new_eps_bearer_entry = collision_p; + }*/ + return new_eps_bearer_entry; +} +//----------------------------------------------------------------------------- +int sgw_lite_cm_remove_eps_bearer_entry(hash_table_t *eps_bearersP, ebi_t eps_bearer_idP) +//----------------------------------------------------------------------------- +{ + int temp; + + if (eps_bearersP == NULL) { + return -1; + } + temp = hashtbl_remove(eps_bearersP, eps_bearer_idP); + + return temp; +} + diff --git a/openair-cn/SGW-LITE/sgw_lite_context_manager.h b/openair-cn/SGW-LITE/sgw_lite_context_manager.h new file mode 100644 index 0000000000..81df35d918 --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_context_manager.h @@ -0,0 +1,232 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#ifndef SGW_LITE_CONTEXT_MANAGER_H_ +#define SGW_LITE_CONTEXT_MANAGER_H_ + +#include "commonDef.h" +#include "common_types.h" +#include "mme_app_ue_context.h" // for cgi_t +#include "hashtable.h" +#include "obj_hashtable.h" + +/******************************** +* P-GW contexts * +*********************************/ +typedef struct pgw_eps_bearer_entry_gtp_based_S5_S8_only_s { + ebi_t eps_bearer_id; ///< An EPS bearer identity uniquely identifies an EPS bearer for one UE accessing via E-UTRAN + // TO DO traffic_flow_template_t tft; ///< Traffic Flow Template + + ip_address_t s_gw_address_in_use_up; ///< The IP address of the S-GW currently used for sending user plane traffic. + Teid_t s_gw_teid_for_S5_S8_up; ///< S-GW Tunnel Endpoint Identifier for the S5/S8 interface for the user plane. + + ip_address_t p_gw_ip_address_for_S5_S8_up; ///< P-GW IP address for user plane data received from PDN GW. + Teid_t p_gw_teid_for_S5_S8_up; ///< P-GW Tunnel Endpoint Identifier for the GTP Based S5/S8 interface for user plane. + + // TO BE CHECKED + BearerQOS_t eps_bearer_qos; ///< ARP, GBR, MBR, QCI. + // NOT NEEDED charging_id ///< Charging identifier, identifies charging records generated by S-GW and PDN GW. + +} pgw_eps_bearer_entry_t; + +typedef struct pgw_pdn_connection_s { + //ip_addresses; ///< IPv4 address and/or IPv6 prefix + pdn_type_t pdn_type; ///< IPv4, IPv6, or IPv4v6 + ip_address_t s_gw_address_in_use_cp; ///< The IP address of the S-GW currently used for sending control plane signalling. + Teid_t s_gw_teid_for_S5_S8_cp; ///< S-GW Tunnel Endpoint Identifier for the S5/S8 interface for the control plane. (For GTP-based S5/S8 only). + ip_address_t s_gw_address_in_use_up; ///< The IP address of the S-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only). + // NOT NEEDED s_gw_gre_key_for_dl_traffic_up ///< Serving GW assigned GRE Key for the S5/S8 interface for the user plane for downlink traffic. (For PMIP-based S5/S8 only). + ip_address_t p_gw_ip_address_for_S5_S8_cp; ///< P-GW IP address for the S5/S8 for the control plane signalling. + Teid_t p_gw_teid_for_S5_S8_cp; ///< P-GW Tunnel Endpoint Identifier for the S5/S8 control plane interface. (For GTP-based S5/S8 only). + ip_address_t p_gw_address_in_use_up; ///< The IP address of the P-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only). + // NOT NEEDED p_gw_gre_key_for_uplink_traffic_up ///< PDN GW assigned GRE Key for the S5/S8 interface for the user plane for uplink traffic. (For PMIP-based S5/S8 only). + // NOT NEEDED MS Info Change Reporting Action ///< Denotes whether the MME and/or the SGSN is/are requested to send changes in User Location Information change for this bearer. + // NOT NEEDED CSG Information Reporting Action ///< Denotes whether the MME and/or the SGSN is/are requested to send changes in User CSG Information change for this bearer. + /// This field denotes separately whether the MME/SGSN are requested to send changes in User CSG Information for (a) CSG cells, + /// (b) hybrid cells in which the subscriber is a CSG member, and (c) hybrid cells in which the subscriber is not a CSG member, or any combination of the above. + ebi_t default_bearer; ///< Identifies the default bearer within the PDN connection by its EPS Bearer Id. The default bearer is the one which is established first within the PDN connection. (For GTP based + /// S5/S8 or for PMIP based S5/S8 if multiple PDN connections to the same APN are supported). + + hash_table_t *pgw_eps_bearers; +} pgw_pdn_connection_t; + + +typedef struct pgw_apn_s { + APN_t apn_in_use; ///< The APN currently used, as received from the S-GW. + ambr_t apn_ambr; ///< The maximum aggregated uplink and downlink MBR values to be shared across all Non-GBR bearers, + /// which are established for this APN. + obj_hash_table_t *pdn_connections; ///< For each PDN Connection within the APN + +} pgw_apn_t; + + +// The PDN GW maintains the following EPS bearer context information for UEs. +// For emergency attached UEs which are not authenticated, IMEI is stored in context. +typedef struct pgw_eps_bearer_context_information_s { + Imsi_t imsi; ///< IMSI (International Mobile Subscriber Identity) is the subscriber permanent identity. + int8_t imsi_unauthenticated_indicator; ///< This is an IMSI indicator to show the IMSI is unauthenticated. + // TO BE CHECKED me_identity_t me_identity; ///< Mobile Equipment Identity (e.g. IMEI/IMEISV). + char msisdn[MSISDN_LENGTH]; ///< The basic MSISDN of the UE. The presence is dictated by its storage in the HSS. + // NOT NEEDED selected_cn_operator_id ///< Selected core network operator identity (to support networksharing as defined in TS 23.251 + rat_type_t rat_type; ///< Current RAT + // NOT NEEDED Trace reference ///< Identifies a record or a collection of records for a particular trace. + // NOT NEEDED Trace type ///< Indicates the type of trace + // NOT NEEDED Trigger id ///< Identifies the entity that initiated the trace + // NOT NEEDED OMC identity ///< Identifies the OMC that shall receive the trace record(s). + + // TO BE CONTINUED... + obj_hash_table_t *apns; +} pgw_eps_bearer_context_information_t; + +/******************************** +* S-GW contexts * +*********************************/ +//-------------------------------- +// EPS Bearer entry +//-------------------------------- + +// A primary key for a EPS Bearer entry can be a tuple (eps bearer id, imsi) +typedef struct sgw_eps_bearer_entry_s { + ebi_t eps_bearer_id; ///< An EPS bearer identity uniquely identifies an EPS bearer for one UE accessing via E-UTRAN + // TO DO traffic_flow_template_t tft; ///< Traffic Flow Template + + ip_address_t p_gw_address_in_use_up; ///< The IP address of the P-GW currently used for sending user plane traffic. (For GTP-based S5/S8 only). + Teid_t p_gw_teid_for_S5_S8_up; ///< P-GW Tunnel Endpoint Identifier for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only). + + ip_address_t s_gw_ip_address_for_S5_S8_up; ///< S-GW IP address for user plane data received from PDN GW. (For GTP-based S5/S8 only). + Teid_t s_gw_teid_for_S5_S8_up; ///< S-GW Tunnel Endpoint Identifier for the S5/S8 interface for the user plane. (For GTP-based S5/S8 only). + + ip_address_t s_gw_ip_address_for_S1u_S12_S4_up; ///< S-GW IP address for the S1-u interface (Used by the eNodeB), for the S12 interface (used by the RNC) and for the S4 interface (used by the SGSN). + Teid_t s_gw_teid_for_S1u_S12_S4_up; ///< S-GW Tunnel Endpoint Identifier for the S1-u interface, for the S12 interface (used by the RNC) and for the S4 interface (used by the SGSN). + + ip_address_t enb_ip_address_for_S1u; ///< eNodeB IP address for the S1-u interface (Used by the S-GW). + Teid_t enb_teid_for_S1u; ///< eNodeB Tunnel Endpoint Identifier for the S1-u interface. + + // TO BE CHECKED + BearerQOS_t eps_bearer_qos; ///< ARP, GBR, MBR, QCI. + // NOT NEEDED charging_id ///< Charging identifier, identifies charging records generated by S-GW and PDN GW. + +} sgw_eps_bearer_entry_t; + + +typedef struct sgw_pdn_connection_s { + APN_t apn_in_use; ///< The APN currently used, as received from the MME or S4 SGSN. + // NOT NEEDED NOW eps_pdn_charging ///< The charging characteristics of this PDN connection, e.g.normal, prepaid, flat-rate and/or hot billing. + // NOT IMPLEMENTED NOW + ip_address_t p_gw_address_in_use_cp; ///< The IP address of the P-GW currently used for sending control plane signalling. + // NOT IMPLEMENTED NOW + Teid_t p_gw_teid_for_S5_S8_cp; ///< P-GW Tunnel Endpoint Identifier for the S5/S8 interface for the control plane. (For GTP-based S5/S8 only). + // NOT IMPLEMENTED NOW + ip_address_t p_gw_address_in_use_up; ///< The IP address of the P-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only) + // NOT NEEDED p_gw_gre_key_for_uplink_traffic_up ///< PDN GW assigned GRE Key for the S5/S8 interface for the user plane for uplink traffic. (For PMIP-based S5/S8 only) + ip_address_t s_gw_ip_address_for_S5_S8_cp; ///< S-GW IP address for the S5/S8 for the control plane signalling. + Teid_t s_gw_teid_for_S5_S8_cp; ///< S-GW Tunnel Endpoint Identifier for the S5/S8 control plane interface. (For GTP-based S5/S8 only). + ip_address_t s_gw_address_in_use_up; ///< The IP address of the S-GW currently used for sending user plane traffic. (For PMIP-based S5/S8 only) + // NOT NEEDED s_gw_gre_key_for_dl_traffic_up ///< user plane for downlink traffic. (For PMIP-based S5/S8 only) + ebi_t default_bearer; ///< Identifies the default bearer within the PDN connection by its EPS Bearer Id. (For PMIP based S5/S8.) + + // eps bearers + hash_table_t *sgw_eps_bearers; + +} sgw_pdn_connection_t; + +// The Serving GW maintains the following EPS bearer context information for UEs. +// Struct sgw_eps_bearer_context_information_t contain the context fields for one UE. +typedef struct sgw_eps_bearer_context_information_s { + Imsi_t imsi; ///< IMSI (International Mobile Subscriber Identity) is the subscriber permanent identity. + int8_t imsi_unauthenticated_indicator; /// This is an IMSI indicator to show the IMSI is unauthenticated. + // TO BE CHECKED me_identity_t me_identity; ///< Mobile Equipment Identity (e.g. IMEI/IMEISV). + char msisdn[MSISDN_LENGTH]; ///< The basic MSISDN of the UE. The presence is dictated by its storage in the HSS. + // NOT NEEDED selected_cn_operator_id ///< Selected core network operator identity (to support networksharing as defined in TS 23.251 + Teid_t mme_teid_for_S11; ///< MME Tunnel Endpoint Identifier for the S11 interface + ip_address_t mme_ip_address_for_S11; ///< MME IP address the S11 interface. + Teid_t s_gw_teid_for_S11_S4; ///< S-GW Tunnel Endpoint Identifier for the S11 Interface and the S4 Interface (control plane) + ip_address_t s_gw_ip_address_for_S11_S4; ///< S-GW IP address for the S11 interface and the S4 Interface (control plane). + // NOT NEEDED Trace reference ///< Identifies a record or a collection of records for a particular trace. + // NOT NEEDED Trace type ///< Indicates the type of trace + // NOT NEEDED Trigger id ///< Identifies the entity that initiated the trace + // NOT NEEDED OMC identity ///< Identifies the OMC that shall receive the trace record(s). + cgi_t last_known_cell_Id; ///< This is the last location of the UE known by the network + // NOT NEEDED NOW Last known Cell Id age ///< This is the age of the above UE location information + + // ONLY ONE PDN CONNECTION + // Do not know now what is the key for this hashtable + //obj_hash_table_t *pdn_connections; + sgw_pdn_connection_t pdn_connection; + + /* S11 specific parameter. Not used in standalone mode */ + void *trxn; + uint32_t peer_ip; + + MessageDef* initial_message_p; +} sgw_eps_bearer_context_information_t; + +/******************************** +* Paired contexts * +*********************************/ +// data entry for s11_bearer_context_information_hashtable +// like this if needed in future, the split of S and P GW should be easier. +typedef struct s_plus_p_gw_eps_bearer_context_information_s { + sgw_eps_bearer_context_information_t sgw_eps_bearer_context_information; + pgw_eps_bearer_context_information_t pgw_eps_bearer_context_information; +} s_plus_p_gw_eps_bearer_context_information_t; + + +// data entry for s11teid2mme_hashtable +typedef struct mme_sgw_tunnel_s { + uint32_t local_teid; ///< Tunnel endpoint Identifier + uint32_t remote_teid; ///< Tunnel endpoint Identifier +} mme_sgw_tunnel_t; + +// data entry for s1uteid2enb_hashtable +typedef struct enb_sgw_s1u_tunnel_s { + uint32_t local_teid; ///< S-GW Tunnel endpoint Identifier + uint32_t remote_teid; ///< eNB Tunnel endpoint Identifier + ip_address_t enb_ip_address_for_S11; ///< eNB IP address the S1U interface. +} enb_sgw_s1u_tunnel_t; + + +void sgw_lite_display_s11teid2mme_mappings(void); +void sgw_lite_display_s11_bearer_context_information_mapping(void); +void pgw_lite_cm_free_apn(pgw_apn_t *apnP); + + +Teid_t sgw_lite_get_new_S11_tunnel_id(void); +mme_sgw_tunnel_t * sgw_lite_cm_create_s11_tunnel(Teid_t remote_teid, Teid_t local_teid); +int sgw_lite_cm_remove_s11_tunnel(Teid_t local_teid); +sgw_eps_bearer_entry_t * sgw_lite_cm_create_eps_bearer_entry(void); +sgw_pdn_connection_t * sgw_lite_cm_create_pdn_connection(void); +void sgw_lite_cm_free_pdn_connection(sgw_pdn_connection_t *pdn_connectionP); +s_plus_p_gw_eps_bearer_context_information_t * sgw_lite_cm_create_bearer_context_information_in_collection(Teid_t teid); +void sgw_lite_cm_free_s_plus_p_gw_eps_bearer_context_information(s_plus_p_gw_eps_bearer_context_information_t *contextP); +int sgw_lite_cm_remove_bearer_context_information(Teid_t teid); +sgw_eps_bearer_entry_t * sgw_lite_cm_create_eps_bearer_entry_in_collection(hash_table_t *eps_bearersP, ebi_t eps_bearer_idP); +int sgw_lite_cm_remove_eps_bearer_entry(hash_table_t *eps_bearersP, ebi_t eps_bearer_idP); + +#endif /* SGW_LITE_CONTEXT_MANAGER_H_ */ diff --git a/openair-cn/SGW-LITE/sgw_lite_defs.h b/openair-cn/SGW-LITE/sgw_lite_defs.h new file mode 100644 index 0000000000..ca0da47105 --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_defs.h @@ -0,0 +1,49 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef SGW_LITE_DEFS_H_ +#define SGW_LITE_DEFS_H_ + +#ifndef SPGW_APP_DEBUG +# define SPGW_APP_DEBUG(x, args...) do { fprintf(stdout, "[SPGW-APP] [D]"x, ##args); } \ + while(0) +#endif +#ifndef SPGW_APP_WARNING +# define SPGW_APP_WARNING(x, args...) do { fprintf(stdout, "[SPGW-APP] [W]"x, ##args); } \ + while(0) +#endif +#ifndef SPGW_APP_ERROR +# define SPGW_APP_ERROR(x, args...) do { fprintf(stderr, "[SPGW-APP] [E]"x, ##args); } \ + while(0) +#endif + +int sgw_lite_init(const mme_config_t *mme_config); + +#endif /* SGW_LITE_DEFS_H_ */ diff --git a/openair-cn/SGW-LITE/sgw_lite_handlers.c b/openair-cn/SGW-LITE/sgw_lite_handlers.c new file mode 100644 index 0000000000..b45d30aeed --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_handlers.c @@ -0,0 +1,636 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> + +#include "assertions.h" +#include "common_types.h" +#include "intertask_interface.h" + +#include "sgw_lite_defs.h" +#include "sgw_lite_handlers.h" +#include "sgw_lite_context_manager.h" +#include "sgw_lite.h" + +extern sgw_app_t sgw_app; + +int sgw_lite_handle_create_session_request(SgwCreateSessionRequest *session_req_p) +{ + mme_sgw_tunnel_t* new_endpoint = NULL; + s_plus_p_gw_eps_bearer_context_information_t* s_plus_p_gw_eps_bearer_context_information = NULL; + sgw_eps_bearer_entry_t* eps_bearer_entry_p = NULL; + MessageDef* message_p = NULL; + + /* Upon reception of create session request from MME, + * S-GW should create UE, eNB and MME contexts and forward message to P-GW. + */ + if (session_req_p->rat_type != RAT_EUTRAN) { + SPGW_APP_WARNING("Received session request with RAT != RAT_TYPE_EUTRAN: type %d\n", + session_req_p->rat_type); + } + + /* As we are abstracting GTP-C transport, FTeid ip address is useless. + * We just use the teid to identify MME tunnel. Normally we received either: + * - ipv4 address if ipv4 flag is set + * - ipv6 address if ipv6 flag is set + * - ipv4 and ipv6 if both flags are set + * Communication between MME and S-GW involves S11 interface so we are expecting + * S11_MME_GTP_C (11) as interface_type. + */ + if ((session_req_p->sender_fteid_for_cp.teid == 0) && + (session_req_p->sender_fteid_for_cp.interface_type != S11_MME_GTP_C)) { + /* MME sent request with teid = 0. This is not valid... */ + SPGW_APP_WARNING("F-TEID parameter mismatch\n"); + return -1; + } + new_endpoint = sgw_lite_cm_create_s11_tunnel(session_req_p->sender_fteid_for_cp.teid, sgw_lite_get_new_S11_tunnel_id()); + if (new_endpoint == NULL) { + SPGW_APP_WARNING("Could not create new tunnel endpoint between S-GW and MME " + "for S11 abstraction\n"); + return -1; + } + + SPGW_APP_DEBUG("Rx CREATE-SESSION-REQUEST MME S11 teid %u S-GW S11 teid %u APN %s EPS bearer Id %d\n", new_endpoint->remote_teid, new_endpoint->local_teid, session_req_p->apn, session_req_p->bearer_to_create.eps_bearer_id); + SPGW_APP_DEBUG(" IMSI %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n",IMSI(&session_req_p->imsi)); + + s_plus_p_gw_eps_bearer_context_information = sgw_lite_cm_create_bearer_context_information_in_collection(new_endpoint->local_teid); + if (s_plus_p_gw_eps_bearer_context_information != NULL) { + /* We try to create endpoint for S11 interface. A NULL endpoint means that + * either the teid is already in list of known teid or ENOMEM error has been + * raised during malloc. + */ + + //-------------------------------------------------- + // copy informations from create session request to bearer context information + //-------------------------------------------------- + memcpy(s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.imsi.digit, session_req_p->imsi.digit, IMSI_DIGITS_MAX); + memcpy(s_plus_p_gw_eps_bearer_context_information->pgw_eps_bearer_context_information.imsi.digit, session_req_p->imsi.digit, IMSI_DIGITS_MAX); + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.imsi_unauthenticated_indicator = 1; + s_plus_p_gw_eps_bearer_context_information->pgw_eps_bearer_context_information.imsi_unauthenticated_indicator = 1; + + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.mme_teid_for_S11 = session_req_p->sender_fteid_for_cp.teid; + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.s_gw_teid_for_S11_S4 = new_endpoint->local_teid; + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.trxn = session_req_p->trxn; + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.peer_ip = session_req_p->peer_ip; + // may use ntohl or reverse, will see + + FTEID_T_2_IP_ADDRESS_T((&session_req_p->sender_fteid_for_cp) , (&s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.mme_ip_address_for_S11)); + + //-------------------------------------- + // PDN connection + //-------------------------------------- + /*pdn_connection = sgw_lite_cm_create_pdn_connection(); + + if (pdn_connection == NULL) { + // Malloc failed, may be ENOMEM error + SPGW_APP_ERROR("Failed to create new PDN connection\n"); + return -1; + }*/ + memset(&s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection, 0, sizeof(sgw_pdn_connection_t)); + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers = hashtbl_create(12, NULL, NULL); + if ( s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers == NULL) { + SPGW_APP_ERROR("Failed to create eps bearers collection object\n"); + DevMessage("Failed to create eps bearers collection object\n"); + return -1; + } + + if (session_req_p->apn) { + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.apn_in_use = strdup(session_req_p->apn); + } else { + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.apn_in_use = "NO APN"; + } + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.default_bearer = session_req_p->bearer_to_create.eps_bearer_id; + + //obj_hashtbl_insert(s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connections, pdn_connection->apn_in_use, strlen(pdn_connection->apn_in_use), pdn_connection); + //-------------------------------------- + // EPS bearer entry + //-------------------------------------- + eps_bearer_entry_p = sgw_lite_cm_create_eps_bearer_entry_in_collection( + s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, + session_req_p->bearer_to_create.eps_bearer_id); + + sgw_lite_display_s11teid2mme_mappings(); + sgw_lite_display_s11_bearer_context_information_mapping(); + + if (eps_bearer_entry_p == NULL) { + SPGW_APP_ERROR("Failed to create new EPS bearer entry\n"); + // TO DO FREE new_bearer_context_information_p and by cascade... + return -1; + + } + eps_bearer_entry_p->eps_bearer_qos = session_req_p->bearer_to_create.bearer_level_qos; + + + //s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_informationteid = teid; + + /* Trying to insert the new tunnel into the tree. + * If collision_p is not NULL (0), it means tunnel is already present. + */ + + //s_plus_p_gw_eps_bearer_context_information->sgw_eps_bearer_context_informations_gw_ip_address_for_S11_S4 = + + /* Establishing EPS bearer. Requesting S1-U (GTPV1-U) task to create a + * tunnel for S1 user plane interface. If status in response is successfull (0), + * the tunnel endpoint is locally ready. + */ + message_p = alloc_new_message(TASK_SPGW_APP, GTPV1U_CREATE_TUNNEL_REQ); + if (message_p == NULL) { + sgw_lite_cm_remove_s11_tunnel(new_endpoint->remote_teid); + return -1; + } + + message_p->msg.gtpv1uCreateTunnelReq.context_teid = new_endpoint->local_teid; + message_p->msg.gtpv1uCreateTunnelReq.eps_bearer_id = session_req_p->bearer_to_create.eps_bearer_id; + SPGW_APP_DEBUG("Tx GTPV1U_CREATE_TUNNEL_REQ -> TASK_GTPV1_U, Context: S-GW S11 teid %u eps bearer id %d (from session req)\n", + message_p->msg.gtpv1uCreateTunnelReq.context_teid, + message_p->msg.gtpv1uCreateTunnelReq.eps_bearer_id); + return send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + } else { + SPGW_APP_WARNING("Could not create new transaction for SESSION_CREATE message\n"); + free(new_endpoint); + return -1; + } +} + +int sgw_lite_handle_sgi_endpoint_created(SGICreateEndpointResp *resp_p) +{ + task_id_t to_task; + + SgwCreateSessionResponse *create_session_response_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information_p = NULL; + MessageDef *message_p = NULL; + hashtbl_rc_t hash_rc; + + SPGW_APP_DEBUG("Rx SGI_CREATE_ENDPOINT_RESPONSE,Context: S11 teid %u, SGW S1U teid %u EPS bearer id %u\n", + resp_p->context_teid, resp_p->sgw_S1u_teid, resp_p->eps_bearer_id); + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, resp_p->context_teid, (void**)&new_bearer_context_information_p); + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_CREATE_SESSION_RESPONSE); + + if (message_p == NULL) { + return -1; + } + + create_session_response_p = &message_p->msg.sgwCreateSessionResponse; + + if (hash_rc == HASH_TABLE_OK) { + create_session_response_p->teid = new_bearer_context_information_p->sgw_eps_bearer_context_information.mme_teid_for_S11; + + /* Preparing to send create session response on S11 abstraction interface. + * we set the cause value regarding the S1-U bearer establishment result status. + */ + if (resp_p->status == 0) { + uint32_t address = sgw_app.sgw_ip_address_for_S1u_S12_S4_up; + create_session_response_p->bearer_context_created.s1u_sgw_fteid.teid = resp_p->sgw_S1u_teid; + create_session_response_p->bearer_context_created.s1u_sgw_fteid.interface_type = S1_U_SGW_GTP_U; + create_session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4 = 1; + /* Should be filled in with S-GW S1-U local address. Running everything on localhost for now */ + create_session_response_p->bearer_context_created.s1u_sgw_fteid.ipv4_address = address; + + /* Set the Cause information from bearer context created. + * "Request accepted" is returned when the GTPv2 entity has accepted a control plane request. + */ + create_session_response_p->cause = REQUEST_ACCEPTED; + create_session_response_p->bearer_context_created.cause = REQUEST_ACCEPTED; + } else { + create_session_response_p->cause = M_PDN_APN_NOT_ALLOWED; + create_session_response_p->bearer_context_created.cause = M_PDN_APN_NOT_ALLOWED; + } + create_session_response_p->s11_sgw_teid.teid = resp_p->context_teid; + create_session_response_p->bearer_context_created.eps_bearer_id = resp_p->eps_bearer_id; + create_session_response_p->trxn = new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn; + create_session_response_p->peer_ip = new_bearer_context_information_p->sgw_eps_bearer_context_information.peer_ip; + } else { + create_session_response_p->cause = CONTEXT_NOT_FOUND; + create_session_response_p->bearer_context_created.cause = CONTEXT_NOT_FOUND; + } + + SPGW_APP_DEBUG("Tx CREATE-SESSION-RESPONSE MME -> %s, teid %u S-GW teid %u S1U teid %u EPS bearer id %u status %d\n", + to_task == TASK_MME_APP ? "TASK_MME_APP" : "TASK_S11", + create_session_response_p->teid, + create_session_response_p->s11_sgw_teid.teid, + create_session_response_p->bearer_context_created.s1u_sgw_fteid.teid, + create_session_response_p->bearer_context_created.eps_bearer_id, + create_session_response_p->bearer_context_created.cause); + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); +} + +int sgw_lite_handle_gtpv1uCreateTunnelResp(Gtpv1uCreateTunnelResp *endpoint_created_p) +{ + task_id_t to_task; + + SgwCreateSessionResponse *create_session_response_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information_p = NULL; + SGICreateEndpointReq *sgi_create_endpoint_req_p = NULL; + MessageDef *message_p = NULL; + sgw_eps_bearer_entry_t *eps_bearer_entry_p = NULL; + hashtbl_rc_t hash_rc; + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + SPGW_APP_DEBUG("Rx GTPV1U_CREATE_TUNNEL_RESP, Context S-GW S11 teid %u, S-GW S1U teid %u EPS bearer id %u status %d\n", + endpoint_created_p->context_teid, + endpoint_created_p->S1u_teid, + endpoint_created_p->eps_bearer_id, + endpoint_created_p->status); + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, endpoint_created_p->context_teid, (void**)&new_bearer_context_information_p); + + if (hash_rc == HASH_TABLE_OK) { + hash_rc = hashtbl_get (new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, endpoint_created_p->eps_bearer_id, (void**)&eps_bearer_entry_p); + + DevAssert(hash_rc == HASH_TABLE_OK); + + SPGW_APP_DEBUG("Updated eps_bearer_entry_p eps_b_id %u with SGW S1U teid %u\n", endpoint_created_p->eps_bearer_id, endpoint_created_p->S1u_teid); + eps_bearer_entry_p->s_gw_teid_for_S1u_S12_S4_up = endpoint_created_p->S1u_teid; + + sgw_lite_display_s11_bearer_context_information_mapping(); + + /* SEND IP_FW_CREATE_IP_ENDPOINT_REQUEST to FW_IP task */ + message_p = alloc_new_message(TASK_SPGW_APP, SGI_CREATE_ENDPOINT_REQUEST); + if (message_p == NULL) { + return -1; + } + sgi_create_endpoint_req_p = &message_p->msg.sgiCreateEndpointReq; + // IP forward will forward packets to this teid + sgi_create_endpoint_req_p->context_teid = endpoint_created_p->context_teid; + sgi_create_endpoint_req_p->sgw_S1u_teid = endpoint_created_p->S1u_teid; + sgi_create_endpoint_req_p->eps_bearer_id = endpoint_created_p->eps_bearer_id; + + //create_sgi_endpoint_req_p->pdn_type = new_bearer_context_information_p-> + // TO DO TFT, QOS + return send_msg_to_task(TASK_FW_IP, INSTANCE_DEFAULT, message_p); + } else { + SPGW_APP_DEBUG("Rx SGW_S1U_ENDPOINT_CREATED, Context: teid %u NOT FOUND\n", endpoint_created_p->context_teid); + message_p = alloc_new_message(TASK_SPGW_APP, SGW_CREATE_SESSION_RESPONSE); + if (message_p == NULL) { + return -1; + } + create_session_response_p = &message_p->msg.sgwCreateSessionResponse; + memset(create_session_response_p, 0, sizeof(SgwCreateSessionResponse)); + create_session_response_p->cause = CONTEXT_NOT_FOUND; + create_session_response_p->bearer_context_created.cause = CONTEXT_NOT_FOUND; + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } +} + +int sgw_lite_handle_gtpv1uUpdateTunnelResp(Gtpv1uUpdateTunnelResp *endpoint_updated_p) +{ + SgwModifyBearerResponse *modify_response_p = NULL; + SGIUpdateEndpointReq *update_request_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information_p = NULL; + MessageDef *message_p = NULL; + sgw_eps_bearer_entry_t *eps_bearer_entry_p = NULL; + hashtbl_rc_t hash_rc; + task_id_t to_task; + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + SPGW_APP_DEBUG("Rx GTPV1U_UPDATE_TUNNEL_RESP, Context teid %u, SGW S1U teid %u, eNB S1U teid %u, EPS bearer id %u, status %d\n", + endpoint_updated_p->context_teid, + endpoint_updated_p->sgw_S1u_teid, + endpoint_updated_p->enb_S1u_teid, + endpoint_updated_p->eps_bearer_id, + endpoint_updated_p->status); + + + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, endpoint_updated_p->context_teid, (void**)&new_bearer_context_information_p); + + if (hash_rc == HASH_TABLE_OK) { + hash_rc = hashtbl_get (new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, endpoint_updated_p->eps_bearer_id, (void**)&eps_bearer_entry_p); + + if ((hash_rc == HASH_TABLE_KEY_NOT_EXISTS) || (hash_rc == HASH_TABLE_BAD_PARAMETER_HASHTABLE)) { + SPGW_APP_DEBUG("Sending SGW_MODIFY_BEARER_RESPONSE trxn %p bearer %u CONTEXT_NOT_FOUND (sgw_eps_bearers)\n", + new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn, + endpoint_updated_p->eps_bearer_id); + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_RESPONSE); + if (message_p == NULL) { + return -1; + } + modify_response_p = &message_p->msg.sgwModifyBearerResponse; + memset(modify_response_p, 0, sizeof(SgwModifyBearerResponse)); + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = endpoint_updated_p->eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn; + + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } else if (hash_rc == HASH_TABLE_OK) { + + message_p = alloc_new_message(TASK_SPGW_APP, SGI_UPDATE_ENDPOINT_REQUEST); + if (message_p == NULL) { + return -1; + } + update_request_p = &message_p->msg.sgiUpdateEndpointReq; + memset(update_request_p, 0, sizeof(SGIUpdateEndpointReq)); + update_request_p->context_teid = endpoint_updated_p->context_teid; + update_request_p->sgw_S1u_teid = endpoint_updated_p->sgw_S1u_teid; + update_request_p->enb_S1u_teid = endpoint_updated_p->enb_S1u_teid; + update_request_p->eps_bearer_id = endpoint_updated_p->eps_bearer_id; + + return send_msg_to_task(TASK_FW_IP, INSTANCE_DEFAULT, message_p); + } + } else { + SPGW_APP_DEBUG("Sending SGW_MODIFY_BEARER_RESPONSE trxn %p bearer %u CONTEXT_NOT_FOUND (s11_bearer_context_information_hashtable)\n", + new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn, + endpoint_updated_p->eps_bearer_id); + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_RESPONSE); + if (message_p == NULL) { + return -1; + } + modify_response_p = &message_p->msg.sgwModifyBearerResponse; + memset(modify_response_p, 0, sizeof(SgwModifyBearerResponse)); + + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = endpoint_updated_p->eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn; + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } + return -1; +} + +int sgw_lite_handle_sgi_endpoint_updated(SGIUpdateEndpointResp *resp_p) +{ + SgwModifyBearerResponse *modify_response_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information_p = NULL; + MessageDef *message_p = NULL; + sgw_eps_bearer_entry_t *eps_bearer_entry_p = NULL; + hashtbl_rc_t hash_rc; + task_id_t to_task; + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + SPGW_APP_DEBUG("Rx SGI_UPDATE_ENDPOINT_RESPONSE, Context teid %u, SGW S1U teid %u, eNB S1U teid %u, EPS bearer id %u, status %d\n", + resp_p->context_teid, + resp_p->sgw_S1u_teid, + resp_p->enb_S1u_teid, + resp_p->eps_bearer_id, + resp_p->status); + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_RESPONSE); + if (message_p == NULL) { + return -1; + } + modify_response_p = &message_p->msg.sgwModifyBearerResponse; + memset(modify_response_p, 0, sizeof(SgwModifyBearerResponse)); + + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, resp_p->context_teid, (void**)&new_bearer_context_information_p); + + + if (hash_rc == HASH_TABLE_OK) { + hash_rc = hashtbl_get (new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, + resp_p->eps_bearer_id, + (void**)&eps_bearer_entry_p); + + if ((hash_rc == HASH_TABLE_KEY_NOT_EXISTS) || (hash_rc == HASH_TABLE_BAD_PARAMETER_HASHTABLE)) { + SPGW_APP_DEBUG("Rx SGI_UPDATE_ENDPOINT_RESPONSE: CONTEXT_NOT_FOUND (pdn_connection.sgw_eps_bearers context)\n"); + modify_response_p->teid = resp_p->context_teid; // TO BE CHECKED IF IT IS THIS TEID + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = resp_p->eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = 0; + + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } else if (hash_rc == HASH_TABLE_OK) { + SPGW_APP_DEBUG("Rx SGI_UPDATE_ENDPOINT_RESPONSE: REQUEST_ACCEPTED\n"); + + // accept anyway + modify_response_p->teid = resp_p->context_teid; // TO BE CHECKED IF IT IS THIS TEID + modify_response_p->present = MODIFY_BEARER_RESPONSE_MOD; + modify_response_p->choice.bearer_modified.eps_bearer_id = resp_p->eps_bearer_id; + modify_response_p->choice.bearer_modified.cause = REQUEST_ACCEPTED; + modify_response_p->cause = REQUEST_ACCEPTED; + modify_response_p->trxn = new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn; + } + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } else { + SPGW_APP_DEBUG("Rx SGI_UPDATE_ENDPOINT_RESPONSE: CONTEXT_NOT_FOUND (S11 context)\n"); + + modify_response_p->teid = resp_p->context_teid; // TO BE CHECKED IF IT IS THIS TEID + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = resp_p->eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = 0; + + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } +} + +int sgw_lite_handle_modify_bearer_request(SgwModifyBearerRequest *modify_bearer_p) +{ + SgwModifyBearerResponse *modify_response_p = NULL; + Gtpv1uUpdateTunnelReq *gtpv1u_update_tunnel_req_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *new_bearer_context_information_p = NULL; + MessageDef *message_p = NULL; + sgw_eps_bearer_entry_t *eps_bearer_entry_p = NULL; + hashtbl_rc_t hash_rc; + task_id_t to_task; + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, teid %u, EPS bearer id %u\n", + modify_bearer_p->teid, + modify_bearer_p->bearer_context_to_modify.eps_bearer_id); + + sgw_lite_display_s11teid2mme_mappings(); + sgw_lite_display_s11_bearer_context_information_mapping(); + + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, modify_bearer_p->teid, (void**)&new_bearer_context_information_p); + + if (hash_rc == HASH_TABLE_OK) { + + new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.default_bearer = modify_bearer_p->bearer_context_to_modify.eps_bearer_id; + new_bearer_context_information_p->sgw_eps_bearer_context_information.trxn = modify_bearer_p->trxn; + + hash_rc = hashtbl_is_key_exists (new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, modify_bearer_p->bearer_context_to_modify.eps_bearer_id); + + if (hash_rc == HASH_TABLE_KEY_NOT_EXISTS) { + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_RESPONSE); + if (message_p == NULL) { + return -1; + } + modify_response_p = &message_p->msg.sgwModifyBearerResponse; + memset(modify_response_p, 0, sizeof(SgwModifyBearerResponse)); + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = modify_bearer_p->bearer_context_to_modify.eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = modify_bearer_p->trxn; + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } else if (hash_rc == HASH_TABLE_OK) { + // TO DO + hash_rc = hashtbl_get (new_bearer_context_information_p->sgw_eps_bearer_context_information.pdn_connection.sgw_eps_bearers, modify_bearer_p->bearer_context_to_modify.eps_bearer_id, (void**)&eps_bearer_entry_p); + FTEID_T_2_IP_ADDRESS_T( (&modify_bearer_p->bearer_context_to_modify.s1_eNB_fteid) , (&eps_bearer_entry_p->enb_ip_address_for_S1u) ); + eps_bearer_entry_p->enb_teid_for_S1u = modify_bearer_p->bearer_context_to_modify.s1_eNB_fteid.teid; + + // UPDATE GTPV1U mapping tables with eNB references (teid, addresses) + message_p = alloc_new_message(TASK_SPGW_APP, GTPV1U_UPDATE_TUNNEL_REQ); + if (message_p == NULL) { + return -1; + } + gtpv1u_update_tunnel_req_p = &message_p->msg.gtpv1uUpdateTunnelReq; + memset(gtpv1u_update_tunnel_req_p, 0, sizeof(Gtpv1uUpdateTunnelReq)); + gtpv1u_update_tunnel_req_p->context_teid = modify_bearer_p->teid; + gtpv1u_update_tunnel_req_p->sgw_S1u_teid = eps_bearer_entry_p->s_gw_teid_for_S1u_S12_S4_up; ///< SGW S1U local Tunnel Endpoint Identifier + gtpv1u_update_tunnel_req_p->enb_S1u_teid = eps_bearer_entry_p->enb_teid_for_S1u; ///< eNB S1U Tunnel Endpoint Identifier + gtpv1u_update_tunnel_req_p->enb_ip_address_for_S1u = eps_bearer_entry_p->enb_ip_address_for_S1u; + gtpv1u_update_tunnel_req_p->eps_bearer_id = eps_bearer_entry_p->eps_bearer_id; + SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, gtpv1u_update_tunnel_req_p->context_teid = %u\n",modify_bearer_p->teid); + SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, gtpv1u_update_tunnel_req_p->sgw_S1u_teid = %u\n",gtpv1u_update_tunnel_req_p->sgw_S1u_teid); + SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, gtpv1u_update_tunnel_req_p->enb_S1u_teid = %u\n",gtpv1u_update_tunnel_req_p->enb_S1u_teid); + //SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, gtpv1u_update_tunnel_req_p->enb_ip_address_for_S1u = %u\n",modify_bearer_p->enb_ip_address_for_S1u); + SPGW_APP_DEBUG("Rx MODIFY_BEARER_REQUEST, gtpv1u_update_tunnel_req_p->eps_bearer_id = %u\n",gtpv1u_update_tunnel_req_p->eps_bearer_id); + + return send_msg_to_task(TASK_GTPV1_U, INSTANCE_DEFAULT, message_p); + } + } else { + message_p = alloc_new_message(TASK_SPGW_APP, SGW_MODIFY_BEARER_RESPONSE); + if (message_p == NULL) { + return -1; + } + modify_response_p = &message_p->msg.sgwModifyBearerResponse; + + modify_response_p->present = MODIFY_BEARER_RESPONSE_REM; + modify_response_p->choice.bearer_for_removal.eps_bearer_id = modify_bearer_p->bearer_context_to_modify.eps_bearer_id; + modify_response_p->choice.bearer_for_removal.cause = CONTEXT_NOT_FOUND; + modify_response_p->cause = CONTEXT_NOT_FOUND; + modify_response_p->trxn = modify_bearer_p->trxn; + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } + return -1; +} + +int sgw_lite_handle_delete_session_request(SgwDeleteSessionRequest *delete_session_req_p) +{ + task_id_t to_task; + hashtbl_rc_t hash_rc; + + SgwDeleteSessionResponse *delete_session_resp_p; + MessageDef *message_p = NULL; + s_plus_p_gw_eps_bearer_context_information_t *ctx_p = NULL; + +#if defined(ENABLE_STANDALONE_EPC) + to_task = TASK_MME_APP; +#else + to_task = TASK_S11; +#endif + + message_p = alloc_new_message(TASK_SPGW_APP, SGW_DELETE_SESSION_RESPONSE); + if (message_p == NULL) { + return -1; + } + delete_session_resp_p = &message_p->msg.sgwDeleteSessionResponse; + + SPGW_APP_WARNING("Delete session handler needs to be completed...\n"); + + if (delete_session_req_p->indication_flags & OI_FLAG) { + SPGW_APP_DEBUG("OI flag is set for this message indicating the request" + "should be forwarded to P-GW entity\n"); + } + + hash_rc = hashtbl_get(sgw_app.s11_bearer_context_information_hashtable, + delete_session_req_p->teid, + (void**)&ctx_p); + + if (hash_rc == HASH_TABLE_OK) { + if ((delete_session_req_p->sender_fteid_for_cp.ipv4 != 0) && + (delete_session_req_p->sender_fteid_for_cp.ipv6 != 0)) { + /* Sender F-TEID IE present */ + if (delete_session_resp_p->teid != ctx_p->sgw_eps_bearer_context_information.mme_teid_for_S11) { + delete_session_resp_p->teid = ctx_p->sgw_eps_bearer_context_information.mme_teid_for_S11; + delete_session_resp_p->cause = INVALID_PEER; + SPGW_APP_DEBUG("Mismatch in MME Teid for CP\n"); + } else { + delete_session_resp_p->teid = delete_session_req_p->sender_fteid_for_cp.teid; + } + } else { + delete_session_resp_p->cause = REQUEST_ACCEPTED; + delete_session_resp_p->teid = ctx_p->sgw_eps_bearer_context_information.mme_teid_for_S11; + } + delete_session_resp_p->trxn = delete_session_req_p->trxn; + delete_session_resp_p->peer_ip = delete_session_req_p->peer_ip; + + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } else { + /* Context not found... set the cause to CONTEXT_NOT_FOUND + * 3GPP TS 29.274 #7.2.10.1 + */ + message_p = alloc_new_message(TASK_SPGW_APP, SGW_DELETE_SESSION_RESPONSE); + if (message_p == NULL) { + return -1; + } + delete_session_resp_p = &message_p->msg.sgwDeleteSessionResponse; + + if ((delete_session_req_p->sender_fteid_for_cp.ipv4 == 0) && + (delete_session_req_p->sender_fteid_for_cp.ipv6 == 0)) { + delete_session_resp_p->teid = 0; + } else { + delete_session_resp_p->teid = delete_session_req_p->sender_fteid_for_cp.teid; + } + delete_session_resp_p->cause = CONTEXT_NOT_FOUND; + delete_session_resp_p->trxn = delete_session_req_p->trxn; + delete_session_resp_p->peer_ip = delete_session_req_p->peer_ip; + + return send_msg_to_task(to_task, INSTANCE_DEFAULT, message_p); + } + + return -1; +} diff --git a/openair-cn/SGW-LITE/sgw_lite_handlers.h b/openair-cn/SGW-LITE/sgw_lite_handlers.h new file mode 100644 index 0000000000..c74c0d5c77 --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_handlers.h @@ -0,0 +1,42 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef SGW_LITE_HANDLERS_H_ +#define SGW_LITE_HANDLERS_H_ + +int sgw_lite_handle_create_session_request(SgwCreateSessionRequest *session_req_p); +int sgw_lite_handle_sgi_endpoint_created (SGICreateEndpointResp *resp_p); +int sgw_lite_handle_sgi_endpoint_updated (SGIUpdateEndpointResp *resp_p); +int sgw_lite_handle_gtpv1uCreateTunnelResp(Gtpv1uCreateTunnelResp *endpoint_created_p); +int sgw_lite_handle_gtpv1uUpdateTunnelResp(Gtpv1uUpdateTunnelResp *endpoint_updated_p); +int sgw_lite_handle_modify_bearer_request (SgwModifyBearerRequest *modify_bearer_p); +int sgw_lite_handle_delete_session_request(SgwDeleteSessionRequest *delete_session_p); + +#endif /* SGW_LITE_HANDLERS_H_ */ diff --git a/openair-cn/SGW-LITE/sgw_lite_ie_defs.h b/openair-cn/SGW-LITE/sgw_lite_ie_defs.h new file mode 100644 index 0000000000..486c3b3c1d --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_ie_defs.h @@ -0,0 +1,570 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "common_types.h" + +#ifndef SGW_LITE_IE_DEFS_H_ +#define SGW_LITE_IE_DEFS_H_ + +typedef uint8_t EBI_t; +typedef uint8_t APNRestriction_t; +typedef uint8_t DelayValue_t; +typedef uint32_t Teid_t; +typedef uint32_t SequenceNumber_t; + +/* Only one type of address can be present at the same time + * This type is applicable to IP address Information Element defined + * in 3GPP TS 29.274 #8.9 + */ +typedef struct { +#define GTP_IP_ADDR_v4 0x0 +#define GTP_IP_ADDR_v6 0x1 + unsigned present:1; + union { + uint8_t v4[4]; + uint8_t v6[16]; + } address; +} gtp_ip_address_t; + +/* 3GPP TS 29.274 Figure 8.12 */ + +typedef uint32_t indication_flags_t; + +/* Bit mask for octet 7 in indication IE */ +#if defined(UPDATE_RELEASE_10) +# define S6AF_FLAG (1U << 20) +# define S4AF_FLAG (1U << 19) +# define MBMDT_FLAG (1U << 18) +#endif +#define ISRAU_FLAG (1U << 17) +#define CCRSI_FLAG (1U << 16) + +/* Bit mask for octet 6 in indication IE */ +#define SQSI_FLAG (1U << 15) +#define UIMSI_FLAG (1U << 14) +#define CFSI_FLAG (1U << 13) +#define CRSI_FLAG (1U << 12) +#define P_FLAG (1U << 11) +#define PT_FLAG (1U << 10) +#define SI_FLAG (1U << 9) +#define MSV_FLAG (1U << 8) + +/* Bit mask for octet 5 in indication IE */ +#define DAF_FLAG (1U << 7) +#define DTF_FLAG (1U << 6) +#define HI_FLAG (1U << 5) +#define DFI_FLAG (1U << 4) +#define OI_FLAG (1U << 3) +#define ISRSI_FLAG (1U << 2) +#define ISRAI_FLAG (1U << 1) +#define SGW_CI_FLAG (1U << 0) + +typedef struct { + pdn_type_t pdn_type; + uint8_t ipv4_address[4]; + uint8_t ipv6_address[16]; + /* Note in rel.8 the ipv6 prefix length has a fixed value of /64 */ + uint8_t ipv6_prefix_length; +} PAA_t; + +#define IMSI(imsi) \ + (imsi)->digit[0], \ + (imsi)->digit[1], \ + (imsi)->digit[2], \ + (imsi)->digit[3], \ + (imsi)->digit[4], \ + (imsi)->digit[5], \ + (imsi)->digit[6], \ + (imsi)->digit[7], \ + (imsi)->digit[8], \ + (imsi)->digit[9], \ + (imsi)->digit[10], \ + (imsi)->digit[11], \ + (imsi)->digit[12], \ + (imsi)->digit[13], \ + (imsi)->digit[14] + +typedef struct { + uint8_t digit[IMSI_DIGITS_MAX]; + uint8_t length; +} Imsi_t; + +typedef struct { + uint8_t digit[MSISDN_LENGTH]; + uint8_t length; +} Msisdn_t; + +#define MEI_IMEI 0x0 +#define MEI_IMEISV 0x1 + +typedef struct { + uint8_t present; + union { + unsigned imei:15; + unsigned imeisv:16; + } choice; +} Mei_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint16_t lac; + uint16_t ci; +} Cgi_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint16_t lac; + uint16_t sac; +} Sai_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint16_t lac; + uint16_t rac; +} Rai_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint16_t tac; +} Tai_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint32_t eci; +} Ecgi_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint16_t lac; +} Lai_t; + +#define ULI_CGI 0x01 +#define ULI_SAI 0x02 +#define ULI_RAI 0x04 +#define ULI_TAI 0x08 +#define ULI_ECGI 0x10 +#define ULI_LAI 0x20 + +typedef struct { + uint8_t present; + struct { + Cgi_t cgi; + Sai_t sai; + Rai_t rai; + Tai_t tai; + Ecgi_t ecgi; + Lai_t lai; + } s; +} Uli_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; +} ServingNetwork_t; +/* +typedef enum RatType_e { + RAT_TYPE_UTRAN = 1, + RAT_TYPE_GERAN, + RAT_TYPE_WLAN, + RAT_TYPE_GAN, + RAT_TYPE_HSPA_EVOLUTION, + RAT_TYPE_EUTRAN, +} RatType_t;*/ + +/* WARNING: not complete... */ +typedef enum InterfaceType_e { + S1_U_ENODEB_GTP_U = 0, + S1_U_SGW_GTP_U = 1, + S12_RNC_GTP_U = 2, + S12_SGW_GTP_U = 3, + S5_S8_SGW_GTP_U = 4, + S5_S8_PGW_GTP_U = 5, + S5_S8_SGW_GTP_C = 6, + S5_S8_PGW_GTP_C = 7, + S11_MME_GTP_C = 10, + S11_SGW_GTP_C = 11, +} InterfaceType_t; + +typedef struct { + unsigned ipv4:1; + unsigned ipv6:1; + InterfaceType_t interface_type; + Teid_t teid; ///< TEID or GRE Key + uint32_t ipv4_address; + uint8_t ipv6_address[16]; +} FTeid_t; +/* + * typedef struct { + pdn_type_t pdn_type; + union { + uint8_t ipv4_address[4]; + uint8_t ipv6_address[16]; + } address; + } ip_address_t; + + */ +#define FTEID_T_2_IP_ADDRESS_T(fte_p,ip_p) \ +do { \ + if (fte_p->ipv4) { \ + ip_p->pdn_type = IPv4; \ + ip_p->address.ipv4_address[0] = (uint8_t)(fte_p->ipv4_address & 0x000000FF); \ + ip_p->address.ipv4_address[1] = (uint8_t)((fte_p->ipv4_address & 0x0000FF00) >> 8); \ + ip_p->address.ipv4_address[2] = (uint8_t)((fte_p->ipv4_address & 0x00FF0000) >> 16); \ + ip_p->address.ipv4_address[3] = (uint8_t)((fte_p->ipv4_address & 0xFF000000) >> 24); \ + } \ + if (fte_p->ipv6) { \ + if (fte_p->ipv4) { \ + ip_p->pdn_type = IPv4_AND_v6; \ + } else { \ + ip_p->pdn_type = IPv6; \ + } \ + memcpy(ip_p->address.ipv6_address, fte_p->ipv6_address, 16); \ + } \ +} while (0) + +typedef enum { + TARGET_ID_RNC_ID = 0, + TARGET_ID_MACRO_ENB_ID = 1, + TARGET_ID_CELL_ID = 2, + TARGET_ID_HOME_ENB_ID = 3 + /* Other values are spare */ +} target_type_t; + +typedef struct { + uint16_t lac; + uint8_t rac; + + /* Length of RNC Id can be 2 bytes if length of element is 8 + * or 4 bytes long if length is 10. + */ + uint32_t rnc_id; +} rnc_id_t; + +typedef struct { + unsigned enb_id:20; + uint16_t tac; +} macro_enb_id_t; + +typedef struct { + unsigned enb_id:28; + uint16_t tac; +} home_enb_id_t; + +typedef struct { + /* Common part */ + uint8_t target_type; + + uint8_t mcc[3]; + uint8_t mnc[3]; + union { + rnc_id_t rnc_id; + macro_enb_id_t macro_enb_id; + home_enb_id_t home_enb_id; + } target_id; +} target_identification_t; + +typedef enum SelectionMode_e { + MS_O_N_P_APN_S_V = 0, ///< MS or network provided APN, subscribed verified + MS_P_APN_S_N_V = 1, ///< MS provided APN, subscription not verified + N_P_APN_S_N_V = 2, ///< Network provided APN, subscription not verified +} SelectionMode_t; + +typedef struct { + uint32_t uplink_ambr; + uint32_t downlink_ambr; +} AMBR_t; + +typedef enum node_id_type_e { + GLOBAL_UNICAST_IPv4 = 0, + GLOBAL_UNICAST_IPv6 = 1, + TYPE_EXOTIC = 2, ///< (MCC * 1000 + MNC) << 12 + Integer value assigned to MME by operator +} node_id_type_t; + +typedef struct { + node_id_type_t node_id_type; + uint16_t csid; ///< Connection Set Identifier + union { + uint32_t unicast_ipv4; + uint8_t unicast_ipv6[16]; + struct { + uint16_t mcc; + uint16_t mnc; + uint16_t operator_specific_id; + } exotic; + } node_id; +} FQ_CSID_t; + +typedef struct { + uint8_t time_zone; + unsigned daylight_saving_time:2; +} UETimeZone_t; + +typedef enum AccessMode_e { + CLOSED_MODE = 0, + HYBRID_MODE = 1, +} AccessMode_t; + +typedef struct { + uint8_t mcc[3]; + uint8_t mnc[3]; + uint32_t csg_id; + AccessMode_t access_mode; + unsigned lcsg:1; + unsigned cmi:1; +} UCI_t; + +typedef struct { + /* PPC (Prohibit Payload Compression): + * This flag is used to determine whether an SGSN should attempt to + * compress the payload of user data when the users asks for it + * to be compressed (PPC = 0), or not (PPC = 1). + */ + unsigned ppc:1; + + /* VB (Voice Bearer): + * This flag is used to indicate a voice bearer when doing PS-to-CS + * SRVCC handover. + */ + unsigned vb:1; +} bearer_flags_t; + +#define PRE_EMPTION_CAPABILITY_ENABLED (0x0) +#define PRE_EMPTION_CAPABILITY_DISABLED (0x1) +#define PRE_EMPTION_VULNERABILITY_ENABLED (0x0) +#define PRE_EMPTION_VULNERABILITY_DISABLED (0x1) + +typedef struct { + /* PCI (Pre-emption Capability) + * The following values are defined: + * - PRE-EMPTION_CAPABILITY_ENABLED (0) + * This value indicates that the service data flow or bearer is allowed + * to get resources that were already assigned to another service data + * flow or bearer with a lower priority level. + * - PRE-EMPTION_CAPABILITY_DISABLED (1) + * This value indicates that the service data flow or bearer is not + * allowed to get resources that were already assigned to another service + * data flow or bearer with a lower priority level. + * Default value: PRE-EMPTION_CAPABILITY_DISABLED + */ + unsigned pci:1; + /* PL (Priority Level): defined in 3GPP TS.29.212 #5.3.45 + * Values 1 to 15 are defined, with value 1 as the highest level of priority. + * Values 1 to 8 should only be assigned for services that are authorized to + * receive prioritized treatment within an operator domain. Values 9 to 15 + * may be assigned to resources that are authorized by the home network and + * thus applicable when a UE is roaming. + */ + unsigned pl:4; + /* PVI (Pre-emption Vulnerability): defined in 3GPP TS.29.212 #5.3.47 + * Defines whether a service data flow can lose the resources assigned to it + * in order to admit a service data flow with higher priority level. + * The following values are defined: + * - PRE-EMPTION_VULNERABILITY_ENABLED (0) + * This value indicates that the resources assigned to the service data + * flow or bearer can be pre-empted and allocated to a service data flow + * or bearer with a higher priority level. + * - PRE-EMPTION_VULNERABILITY_DISABLED (1) + * This value indicates that the resources assigned to the service data + * flow or bearer shall not be pre-empted and allocated to a service data + * flow or bearer with a higher priority level. + * Default value: EMPTION_VULNERABILITY_ENABLED + */ + unsigned pvi:1; + uint8_t qci; + ambr_t gbr; ///< Guaranteed bit rate + ambr_t mbr; ///< Maximum bit rate +} BearerQOS_t; + +/* TFT operation Code */ +typedef enum { + /* 0 = spare */ + + CREATE_NEW_TFT = 0x1, + DELETE_EXISTING_TFT = 0x2, + ADD_PACKET_FILTERS_TO_EXISTING_TFT = 0x3, + REPLACE_PACKET_FILTERS_IN_EXISTING_TFT = 0x4, + DELETE_PACKET_FILTERS_FROM_EXISTING_TFT = 0x5, + NO_TFT_OPERATION = 0x6, + + TFT_OPERATION_CODE_MAX + + /* Other Values Reserved */ +} tft_operation_code_t; + +/* Defined in 3GPP TS 24.008 Table 10.5.162 */ +typedef enum { + PACKET_FILTER_PRE_REL_7 = 0, + PACKET_FILTER_DIRECTION_DL_ONLY = 1, + PACKET_FILTER_DIRECTION_UL_ONLY = 2, + PACKET_FILTER_BIDIRECTIONAL = 3, +} packet_filter_direction_t; + +/* The Traffic Flow Template is specified in 3GPP TS 24.008 #10.5.6.12 + */ +typedef struct { + /* The TFT operation code "No TFT operation" shall be used + * if a parameters list is included but no packet filter + * list is included in the traffic flow template information + * element. + */ + tft_operation_code_t tft_operation_code; + + /* The E bit indicates if a parameters list is included + * in the TFT IE and it is encoded as follows: + * - 0 parameters list is not included + * - 1 parameters list is included + */ + unsigned e_bit:1; + + /* For the "delete existing TFT" operation and for the "no TFT + * operation", the number of packet filters shall be coded + * as 0. For all other operations, the number of packet filters + * shall be greater than 0 and less than or equal to 15. + */ + uint8_t number_of_packet_filters; + + /* TODO: add packet filter list as defined in 3GPP TS 29.274 Table 10.5.162 */ +} tft_t; + +/* Cause as defined in 3GPP TS 29.274 #8.4 */ +typedef enum SGWCause_e { + /* Request / Initial message */ + LOCAL_DETACH = 2, + COMPLETE_DETACH = 3, + RAT_CHANGE_3GPP_TO_NON_3GPP = 4, ///< RAT changed from 3GPP to Non-3GPP + ISR_DEACTIVATION = 5, + ERROR_IND_FROM_RNC_ENB_SGSN = 6, + IMSI_DETACH_ONLY = 7, + /* Acceptance in a Response/Triggered message */ + REQUEST_ACCEPTED = 16, + REQUEST_ACCEPTED_PARTIALLY = 17, + NEW_PDN_TYPE_NW_PREF = 18, ///< New PDN type due to network preference + NEW_PDN_TYPE_SAB_ONLY = 19, ///< New PDN type due to single address bearer only + /* Rejection in a Response triggered message. */ + CONTEXT_NOT_FOUND = 64, + INVALID_MESSAGE_FORMAT = 65, + INVALID_LENGTH = 67, + SERVICE_NOT_SUPPORTED = 68, + MANDATORY_IE_INCORRECT = 69, + MANDATORY_IE_MISSING = 70, + SYSTEM_FAILURE = 72, + NO_RESOURCES_AVAILABLE = 73, + SEMANTIC_ERROR_IN_TFT = 74, + SYNTACTIC_ERROR_IN_TFT = 75, + SEMANTIC_ERRORS_IN_PF = 76, + SYNTACTIC_ERRORS_IN_PF = 77, + MISSING_OR_UNKNOWN_APN = 78, + GRE_KEY_NOT_FOUND = 80, + RELOCATION_FAILURE = 81, + DENIED_IN_RAT = 82, + UE_NOT_RESPONDING = 87, + UE_REFUSES = 88, + SERVICE_DENIED = 89, + UNABLE_TO_PAGE_UE = 90, + NO_MEMORY_AVAILABLE = 91, + REQUEST_REJECTED = 94, + DATA_FORWARDING_NOT_SUPPORTED = 106, + INVALID_REPLY_FROM_REMOTE_PEER = 107, + FALLBACK_TO_GTPV1 = 108, + INVALID_PEER = 109, + TEMP_REJECT_HO_IN_PROGRESS = 110, ///< Temporarily rejected due to handover procedure in progress + REJECTED_FOR_PMIPv6_REASON = 112, ///< Request rejected for a PMIPv6 reason (see 3GPP TS 29.275 [26]). + M_PDN_APN_NOT_ALLOWED = 116, ///< Multiple PDN connections for a given APN not allowed. + SGW_CAUSE_MAX +} SGWCause_t; + +typedef struct { + uint8_t cause_value; + uint8_t pce:1; + uint8_t bce:1; + uint8_t cs:1; + + uint8_t offending_ie_type; + uint16_t offending_ie_length; + uint8_t offending_ie_instance; +} gtp_cause_t; + +typedef struct { + uint8_t eps_bearer_id; ///< EPS Bearer ID + BearerQOS_t bearer_level_qos; + tft_t tft; ///< Bearer TFT +} bearer_to_create_t; + +typedef struct { + uint8_t eps_bearer_id; ///< EPS Bearer ID + SGWCause_t cause; + + /* This parameter is used on S11 interface only */ + FTeid_t s1u_sgw_fteid; ///< S1-U SGW F-TEID + + /* This parameter is used on S4 interface only */ + FTeid_t s4u_sgw_fteid; ///< S4-U SGW F-TEID + + /* This parameter is used on S11 and S5/S8 interface only for a + * GTP-based S5/S8 interface and during: + * - E-UTRAN Inintial attch + * - PDP Context Activation + * - UE requested PDN connectivity + */ + FTeid_t s5_s8_u_pgw_fteid; ///< S4-U SGW F-TEID + + /* This parameter is used on S4 interface only and when S12 interface is used */ + FTeid_t s12_sgw_fteid; ///< S12 SGW F-TEID + + /* This parameter is received only if the QoS parameters have been modified */ + BearerQOS_t *bearer_level_qos; + + tft_t tft; ///< Bearer TFT +} bearer_context_created_t; + +typedef struct { + uint8_t eps_bearer_id; ///< EPS Bearer ID + SGWCause_t cause; + FTeid_t s1u_sgw_fteid; ///< Sender F-TEID for user plane +} bearer_context_modified_t; + +typedef struct { + uint8_t eps_bearer_id; ///< EPS bearer ID + SGWCause_t cause; +} bearer_for_removal_t; + +typedef struct { + uint8_t eps_bearer_id; ///< EPS Bearer ID + FTeid_t s1_eNB_fteid; ///< S1 eNodeB F-TEID +} bearer_context_to_modify_t; + +#endif /* SGW_LITE_IE_DEFS_H_ */ + diff --git a/openair-cn/SGW-LITE/sgw_lite_task.c b/openair-cn/SGW-LITE/sgw_lite_task.c new file mode 100644 index 0000000000..84fd3cb13c --- /dev/null +++ b/openair-cn/SGW-LITE/sgw_lite_task.c @@ -0,0 +1,143 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <assert.h> + +#include "intertask_interface.h" +#include "sgw_lite_defs.h" +#include "sgw_lite_handlers.h" +#include "sgw_lite.h" +#include "mme_config.h" +#include "hashtable.h" + +sgw_app_t sgw_app; + +static void *sgw_lite_intertask_interface(void *args_p) +{ + intertask_interface_mark_task_ready(TASK_SPGW_APP); + while(1) { + MessageDef *received_message_p; + receive_msg(TASK_SPGW_APP, &received_message_p); + switch(received_message_p->header.messageId) { + case SGW_CREATE_SESSION_REQUEST: { + /* We received a create session request from MME (with GTP abstraction here) + * procedures might be: + * E-UTRAN Initial Attach + * UE requests PDN connectivity + */ + sgw_lite_handle_create_session_request(&received_message_p->msg.sgwCreateSessionRequest); + } break; + + case SGW_MODIFY_BEARER_REQUEST: { + sgw_lite_handle_modify_bearer_request(&received_message_p->msg.sgwModifyBearerRequest); + } break; + + case SGW_DELETE_SESSION_REQUEST: { + sgw_lite_handle_delete_session_request(&received_message_p->msg.sgwDeleteSessionRequest); + } break; + + case GTPV1U_CREATE_TUNNEL_RESP: { + SPGW_APP_DEBUG("Received teid for S1-U: %u and status: %s\n", + received_message_p->msg.gtpv1uCreateTunnelResp.S1u_teid , + received_message_p->msg.gtpv1uCreateTunnelResp.status == 0 ? "Success" : + "Failure"); + sgw_lite_handle_gtpv1uCreateTunnelResp(&received_message_p->msg.gtpv1uCreateTunnelResp); + } break; + + case GTPV1U_UPDATE_TUNNEL_RESP: { + sgw_lite_handle_gtpv1uUpdateTunnelResp(&received_message_p->msg.gtpv1uUpdateTunnelResp); + } break; + + case SGI_CREATE_ENDPOINT_RESPONSE: { + sgw_lite_handle_sgi_endpoint_created(&received_message_p->msg.sgiCreateEndpointResp); + } break; + + case SGI_UPDATE_ENDPOINT_RESPONSE: { + sgw_lite_handle_sgi_endpoint_updated(&received_message_p->msg.sgiUpdateEndpointResp); + } break; + + default: { + SPGW_APP_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int sgw_lite_init(const mme_config_t *mme_config_p) +{ + SPGW_APP_DEBUG("Initializing SPGW-APP task interface\n"); + if (intertask_interface_create_task(TASK_SPGW_APP, + &sgw_lite_intertask_interface, NULL) < 0) { + perror("pthread_create"); + SPGW_APP_DEBUG("Initializing SPGW-APP task interface: ERROR\n"); + return -1; + } + + sgw_app.s11teid2mme_hashtable = hashtbl_create (8192, NULL, NULL); + if (sgw_app.s11teid2mme_hashtable == NULL) { + perror("hashtbl_create"); + SPGW_APP_DEBUG("Initializing SPGW-APP task interface: ERROR\n"); + return -1; + } + + sgw_app.s1uteid2enb_hashtable = hashtbl_create (8192, NULL, NULL); + if (sgw_app.s1uteid2enb_hashtable == NULL) { + perror("hashtbl_create"); + SPGW_APP_DEBUG("Initializing SPGW-APP task interface: ERROR\n"); + return -1; + } + + + sgw_app.s11_bearer_context_information_hashtable = hashtbl_create (8192, NULL, sgw_lite_cm_free_s_plus_p_gw_eps_bearer_context_information); + if (sgw_app.s11_bearer_context_information_hashtable == NULL) { + perror("hashtbl_create"); + SPGW_APP_DEBUG("Initializing SPGW-APP task interface: ERROR\n"); + return -1; + } + + sgw_app.sgw_interface_name_for_S1u_S12_S4_up = mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up; + sgw_app.sgw_ip_address_for_S1u_S12_S4_up = mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up; + sgw_app.sgw_interface_name_for_S11_S4 = mme_config_p->ipv4.sgw_interface_name_for_S11; + sgw_app.sgw_ip_address_for_S11_S4 = mme_config_p->ipv4.sgw_ip_address_for_S11; + //sgw_app.sgw_ip_address_for_S5_S8_cp = mme_config_p->ipv4.sgw_ip_address_for_S5_S8_cp; + sgw_app.sgw_ip_address_for_S5_S8_up = mme_config_p->ipv4.sgw_ip_address_for_S5_S8_up; + + SPGW_APP_DEBUG("Initializing SPGW-APP task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/TEST/Makefile.am b/openair-cn/TEST/Makefile.am new file mode 100644 index 0000000000..fc80f2a00b --- /dev/null +++ b/openair-cn/TEST/Makefile.am @@ -0,0 +1,88 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + @CHECK_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/GTPV1-U \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/include \ + -I$(top_srcdir)/GTPV1-U/nw-gtpv1u/shared \ + -I$(top_srcdir)/SCTP \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/IPV4 \ + -I$(top_builddir)/S1AP/MESSAGES \ + -I$(top_builddir)/S1AP \ + -I$(top_srcdir)/S1AP \ + -I$(top_srcdir)/SECU \ + -I$(top_srcdir)/S6A \ + -I$(top_srcdir)/SGW-LITE \ + -I$(top_srcdir)/UDP \ + -I$(top_srcdir)/UTILS \ + -I$(top_srcdir)/UTILS/TIMER \ + -I$(top_srcdir)/UTILS/HASTABLE + +if HAVE_CHECK +TESTS = \ + test_kdf \ + test_aes128_cmac_encrypt \ + test_aes128_ctr_encrypt \ + test_aes128_ctr_decrypt \ + test_secu_kenb \ + test_secu_knas \ + test_secu_knas_encrypt_eea2 \ + test_secu_knas_encrypt_eia2 +else +TESTS = +endif + +libtest_util_la_SOURCES = \ + test_util.c test_util.h + +noinst_LTLIBRARIES = libtest_util.la + +common_ldadd = $(top_builddir)/SECU/libsecu.la \ + libtest_util.la \ + @CHECK_LIBS@ + +check_PROGRAMS = \ + test_kdf \ + test_aes128_cmac_encrypt \ + test_aes128_ctr_encrypt \ + test_aes128_ctr_decrypt \ + test_secu_kenb \ + test_secu_knas \ + test_secu_knas_encrypt_eea2 \ + test_secu_knas_encrypt_eia2 + +test_kdf_LDADD = \ + $(common_ldadd) + +test_secu_knas_LDADD = \ + $(common_ldadd) + +test_secu_kenb_LDADD = \ + $(common_ldadd) + +test_secu_knas_encrypt_eea2_LDADD = \ + $(common_ldadd) + +test_secu_knas_encrypt_eia2_LDADD = \ + $(common_ldadd) + +test_aes128_ctr_encrypt_LDADD = \ + $(common_ldadd) + +test_aes128_ctr_decrypt_LDADD = \ + $(common_ldadd) + +test_aes128_cmac_encrypt_LDADD = \ + $(common_ldadd) + +# test_s1ap_LDADD = libtest_util.la \ +# $(top_builddir)/S1AP/libs1ap.la +# +# test_s1ap_SOURCES = test_s1ap.c \ +# $(top_srcdir)/S1AP/s1ap_eNB_decoder.c \ +# $(top_srcdir)/S1AP/s1ap_eNB_decoder.h \ +# $(top_srcdir)/S1AP/s1ap_eNB_encoder.c \ +# $(top_srcdir)/S1AP/s1ap_eNB_encoder.h +# +# test_secu_kenb_SOURCES = test_secu_kenb.c +# test_secu_knas_SOURCES = test_secu_knas.c diff --git a/openair-cn/TEST/oaisim_mme_client_test.c b/openair-cn/TEST/oaisim_mme_client_test.c new file mode 100644 index 0000000000..3ec7ba4ea4 --- /dev/null +++ b/openair-cn/TEST/oaisim_mme_client_test.c @@ -0,0 +1,119 @@ +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/sctp.h> +#include <arpa/inet.h> + +#include "sctp_primitives_client.h" + +#include "s1ap_common.h" +#include "s1ap_eNB.h" +#include "s1ap_mme.h" +#include "s1ap_ies_defs.h" + +char ip_addr[] = "127.0.0.1"; + +int assoc[2]; +uint8_t id[] = { 0x03, 0x56, 0xf0, 0xd8 }; +char identity[] = { 0x02, 0x08, 0x34 }; +char tac[] = { 0x00, 0x01 }; +char infoNAS[] = { 0x07, 0x42, 0x01, 0xE0, 0x06, 0x00, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x00, 0x2C, + 0x52, 0x01, 0xC1, 0x01, 0x09, 0x10, 0x03, 0x77, 0x77, 0x77, 0x07, 0x61, 0x6E, 0x72, 0x69, 0x74, + 0x73, 0x75, 0x03, 0x63, 0x6F, 0x6D, 0x05, 0x01, 0x0A, 0x01, 0x20, 0x37, 0x27, 0x0E, 0x80, 0x80, + 0x21, 0x0A, 0x03, 0x00, 0x00, 0x0A, 0x81, 0x06, 0x0A, 0x00, 0x00, 0x01, 0x50, 0x0B, 0xF6, + 0x00, 0xF1, 0x10, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01 + }; + +uint32_t eNB_UE_S1AP_ID = 0; + +int s1ap_eNB_generate_initial_ue_message(uint8_t **buffer, + uint32_t *length); + +int s1ap_eNB_generate_initial_ue_message(uint8_t **buffer, + uint32_t *length) +{ + InitialUEMessageIEs initialUEmessageIEs; + InitialUEMessageIEs *initialUEmessageIEs_p = &initialUEmessageIEs; + + memset(initialUEmessageIEs_p, 0, sizeof(InitialUEMessageIEs)); + + initialUEmessageIEs.eNB_UE_S1AP_ID = eNB_UE_S1AP_ID; + initialUEmessageIEs.nas_pdu.buf = infoNAS; + initialUEmessageIEs.nas_pdu.size = sizeof(infoNAS); + + initialUEmessageIEs.tai.tAC.buf = tac; + initialUEmessageIEs.tai.tAC.size = 2; + initialUEmessageIEs.tai.pLMNidentity.buf = identity; + initialUEmessageIEs.tai.pLMNidentity.size = 3; + initialUEmessageIEs.eutran_cgi.pLMNidentity.buf = identity; + initialUEmessageIEs.eutran_cgi.pLMNidentity.size = 3; + initialUEmessageIEs.eutran_cgi.cell_ID.buf = id; + initialUEmessageIEs.eutran_cgi.cell_ID.size = 4; + initialUEmessageIEs.eutran_cgi.cell_ID.bits_unused = 4; + + initialUEmessageIEs.rrC_Establishment_Cause = RRC_Establishment_Cause_mo_Data; + + return s1ap_eNB_encode_initial_ue_message(initialUEmessageIEs_p, buffer, length); +} + +void recv_callback(uint8_t *buffer, uint32_t length) +{ + uint8_t *bufferS; + uint32_t len; + s1ap_eNB_generate_initial_ue_message(&bufferS, &len); + sctp_send_msg(assoc[0], 1, bufferS, len); +} + +int main(int argc, char *argv[]) +{ + asn_enc_rval_t retVal; + uint8_t *buffer; + uint32_t len; + + SupportedTAs_Item_t ta; + PLMNidentity_t plmnIdentity; + + asn_debug = 0; + asn1_xer_print = 0; + + S1SetupRequestIEs s1SetupRequest; + memset(&s1SetupRequest, 0, sizeof(S1SetupRequestIEs)); + s1SetupRequest.global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.buf = id; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.size = 3; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.bits_unused = 4; + OCTET_STRING_fromBuf(&s1SetupRequest.global_ENB_ID.pLMNidentity, identity, 3); + + s1SetupRequest.presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT; + OCTET_STRING_fromBuf(&s1SetupRequest.eNBname, "ENB 1 eurecom", + strlen("ENB 1 eurecom")); + + memset(&ta, 0, sizeof(SupportedTAs_Item_t)); + memset(&plmnIdentity, 0, sizeof(PLMNidentity_t)); + OCTET_STRING_fromBuf(&ta.tAC, tac, 2); + OCTET_STRING_fromBuf(&plmnIdentity, identity, 3); + ASN_SEQUENCE_ADD(&ta.broadcastPLMNs, &plmnIdentity); + ASN_SEQUENCE_ADD(&s1SetupRequest.supportedTAs, &ta); + + s1SetupRequest.defaultPagingDRX = PagingDRX_v64; + + s1ap_eNB_encode_s1setuprequest(&s1SetupRequest, &buffer, &len); + + assoc[0] = sctp_connect_to_remote_host(ip_addr, 36412, &recv_callback); + sctp_send_msg(0, 0, buffer, len); + + free(buffer); + +// generateUplinkNASTransport(&buffer, &len); +// sctp_send_msg(assoc[0], 0, buffer, len); +// s1ap_mme_decode_pdu(buffer, len); + + pthread_join(sctp_get_receiver_thread(assoc[0]), NULL); + + return(0); +} diff --git a/openair-cn/TEST/oaisim_mme_itti_test.c b/openair-cn/TEST/oaisim_mme_itti_test.c new file mode 100644 index 0000000000..22072f8e01 --- /dev/null +++ b/openair-cn/TEST/oaisim_mme_itti_test.c @@ -0,0 +1,101 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <sys/time.h> +#include <sys/resource.h> + +#include <sched.h> + +#include "mme_config.h" +#include "gtpv1u_sgw_defs.h" + +#include "intertask_interface_init.h" + +#include "sctp_primitives_server.h" +#include "udp_primitives_server.h" +#include "s1ap_mme.h" +#include "log.h" +#include "timer.h" +#include "sgw_lite_defs.h" +#include "ipv4_defs.h" + +int main(int argc, char *argv[]) +{ + int i = 0; + int prio = 0; + mme_config_t mme_config; + MessageDef *message_p; + struct sched_param param = { + .sched_priority = 10, + }; + + config_parse_opt_line(argc, argv, &mme_config); + fprintf(stdout, "Starting %s ITTI test\n", PACKAGE_STRING); + + if (setpriority(PRIO_PROCESS, 0, prio) < 0) { + fprintf(stderr, "Cannot assign requested prio: %d\n" + "%d:%s\n", prio, errno, strerror(errno)); + return -1; + } + + if (sched_setscheduler(0, SCHED_RR, ¶m) < 0) { + fprintf(stderr, "Cannot assign requested scheduler policy\n" + "%d:%s\n", errno, strerror(errno)); + return -1; + } + + /* Calling each layer init function */ + log_init(&mme_config); + intertask_interface_init(THREAD_MAX, MESSAGES_ID_MAX, threads_name, messages_info); + sctp_init(&mme_config); + udp_init(&mme_config); + s1ap_mme_init(&mme_config); + gtpv1u_init(&mme_config); + ipv4_init(&mme_config); + + sgw_lite_init(&mme_config); + + message_p = alloc_new_message(TASK_S1AP, MESSAGE_TEST); + + while(i < (1 << 15)) { + if (send_broadcast_message(message_p) < 0) { + fprintf(stderr, "Failed to send broadcast message %d\n", i); + } + i++; + } + fprintf(stderr, "Successfully sent %lu messages", get_current_message_number()); + + return 0; +} diff --git a/openair-cn/TEST/oaisim_mme_list_benchmark.c b/openair-cn/TEST/oaisim_mme_list_benchmark.c new file mode 100644 index 0000000000..777cac1673 --- /dev/null +++ b/openair-cn/TEST/oaisim_mme_list_benchmark.c @@ -0,0 +1,291 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/sctp.h> +#include <arpa/inet.h> + +#include "sctp_primitives_client.h" + +#include "s1ap_common.h" +#include "s1ap_eNB.h" +#include "s1ap_mme.h" +#include "s1ap_ies_defs.h" + +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_decoder.h" + +#define NB_OF_ENB 10 +#define NB_OF_UES 100 + +static int connected_eNB = 0; +static char ip_addr[] = "127.0.0.1"; +uint32_t ipv4_local = 0x7F000001; +static uint8_t id[] = { 0x03, 0x56, 0xf0, 0xd8 }; +static char identity[] = { 0x02, 0x08, 0x34 }; +static char tac[] = { 0x00, 0x01 }; +static char infoNAS[] = { 0x07, 0x42, 0x01, 0xE0, 0x06, 0x00, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x00, 0x2C, + 0x52, 0x01, 0xC1, 0x01, 0x09, 0x10, 0x03, 0x77, 0x77, 0x77, 0x07, 0x61, 0x6E, 0x72, 0x69, 0x74, + 0x73, 0x75, 0x03, 0x63, 0x6F, 0x6D, 0x05, 0x01, 0x0A, 0x01, 0x20, 0x37, 0x27, 0x0E, 0x80, 0x80, + 0x21, 0x0A, 0x03, 0x00, 0x00, 0x0A, 0x81, 0x06, 0x0A, 0x00, 0x00, 0x01, 0x50, 0x0B, 0xF6, + 0x00, 0xF1, 0x10, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01 + }; +uint32_t nb_eNB = NB_OF_ENB; +uint32_t nb_ue = NB_OF_UES; + +void s1ap_test_generate_s1_setup_request(uint32_t eNB_id, uint8_t **buffer, + uint32_t *length); +int s1ap_test_generate_initial_ue_message(uint32_t eNB_UE_S1AP_ID, + uint8_t **buffer, + uint32_t *length); +int recv_callback(uint32_t assocId, + uint32_t stream, + uint8_t *buffer, + uint32_t length); +int sctp_connected(void *args, + uint32_t assocId, + uint32_t instreams, + uint32_t outstreams); + +void s1ap_test_generate_s1_setup_request(uint32_t eNB_id, uint8_t **buffer, + uint32_t *length) +{ + S1SetupRequestIEs_t s1SetupRequest; + SupportedTAs_Item_t ta; + PLMNidentity_t plmnIdentity; + uint8_t *id_p = (uint8_t *)(&eNB_id + 1); + + memset(&s1SetupRequest, 0, sizeof(S1SetupRequestIEs_t)); + s1SetupRequest.global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.buf = id_p; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.size = 3; + s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.bits_unused = 4; + OCTET_STRING_fromBuf(&s1SetupRequest.global_ENB_ID.pLMNidentity, identity, 3); + + s1SetupRequest.presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT; + OCTET_STRING_fromBuf(&s1SetupRequest.eNBname, "ENB 1 eurecom", + strlen("ENB 1 eurecom")); + + memset(&ta, 0, sizeof(SupportedTAs_Item_t)); + memset(&plmnIdentity, 0, sizeof(PLMNidentity_t)); + OCTET_STRING_fromBuf(&ta.tAC, tac, 2); + OCTET_STRING_fromBuf(&plmnIdentity, identity, 3); + ASN_SEQUENCE_ADD(&ta.broadcastPLMNs, &plmnIdentity); + ASN_SEQUENCE_ADD(&s1SetupRequest.supportedTAs, &ta); + + s1SetupRequest.defaultPagingDRX = PagingDRX_v64; + + s1ap_eNB_encode_s1_setup_request(&s1SetupRequest, buffer, length); +} + +int s1ap_test_generate_initial_ue_message(uint32_t eNB_UE_S1AP_ID, + uint8_t **buffer, + uint32_t *length) +{ + InitialUEMessageIEs_t initialUEmessageIEs; + InitialUEMessageIEs_t *initialUEmessageIEs_p = &initialUEmessageIEs; + + memset(initialUEmessageIEs_p, 0, sizeof(InitialUEMessageIEs_t)); + + initialUEmessageIEs.eNB_UE_S1AP_ID = eNB_UE_S1AP_ID & 0x00ffffff; + initialUEmessageIEs.nas_pdu.buf = (uint8_t *)infoNAS; + initialUEmessageIEs.nas_pdu.size = sizeof(infoNAS); + + initialUEmessageIEs.tai.tAC.buf = (uint8_t *)tac; + initialUEmessageIEs.tai.tAC.size = 2; + initialUEmessageIEs.tai.pLMNidentity.buf = (uint8_t *)identity; + initialUEmessageIEs.tai.pLMNidentity.size = 3; + initialUEmessageIEs.eutran_cgi.pLMNidentity.buf = (uint8_t *)identity; + initialUEmessageIEs.eutran_cgi.pLMNidentity.size = 3; + initialUEmessageIEs.eutran_cgi.cell_ID.buf = (uint8_t *)id; + initialUEmessageIEs.eutran_cgi.cell_ID.size = 4; + initialUEmessageIEs.eutran_cgi.cell_ID.bits_unused = 4; + + initialUEmessageIEs.rrC_Establishment_Cause = RRC_Establishment_Cause_mo_Data; + + return s1ap_eNB_encode_initial_ue_message(initialUEmessageIEs_p, buffer, length); +} + +int s1ap_test_generate_initial_setup_resp(uint32_t eNB_UE_S1AP_ID, + uint32_t mme_UE_S1AP_ID, + uint8_t eRAB_id, + uint32_t teid, + uint8_t **buffer, + uint32_t *length) +{ + InitialContextSetupResponseIEs_t initialResponseIEs; + InitialContextSetupResponseIEs_t *initialResponseIEs_p = &initialResponseIEs; + + E_RABSetupItemCtxtSURes_t e_RABSetupItemCtxtSURes; + + memset(initialResponseIEs_p, 0, sizeof(InitialContextSetupResponseIEs_t)); + memset(&e_RABSetupItemCtxtSURes, 0, sizeof(E_RABSetupItemCtxtSURes_t)); + + initialResponseIEs_p->mme_ue_s1ap_id = mme_UE_S1AP_ID; + initialResponseIEs_p->eNB_UE_S1AP_ID = eNB_UE_S1AP_ID; + + e_RABSetupItemCtxtSURes.e_RAB_ID = eRAB_id; + e_RABSetupItemCtxtSURes.transportLayerAddress.buf = (uint8_t *)&ipv4_local; + e_RABSetupItemCtxtSURes.transportLayerAddress.size = 4; + + e_RABSetupItemCtxtSURes.gTP_TEID.buf = (uint8_t *)&teid; + e_RABSetupItemCtxtSURes.gTP_TEID.size = 4; + + ASN_SEQUENCE_ADD( + &initialResponseIEs_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes, + &e_RABSetupItemCtxtSURes); + + return s1ap_eNB_encode_initial_context_setup_response(initialResponseIEs_p, + buffer, length); +} + +int recv_callback(uint32_t assocId, + uint32_t stream, + uint8_t *buffer, + uint32_t length) +{ + s1ap_message message; + uint8_t *buffer2; + uint32_t len; + int j; + + if (s1ap_eNB_decode_pdu(&message, buffer, length) < 0) { + fprintf(stderr, "s1ap_eNB_decode_pdu returned status < 0\n"); + free(buffer); + return -1; + } + + if (message.procedureCode == ProcedureCode_id_S1Setup + && message.direction == S1AP_PDU_PR_successfulOutcome) { + for (j = 0; j < nb_ue; j++) { + s1ap_test_generate_initial_ue_message(j, &buffer2, &len); + if (sctp_send_msg(assocId, j % 64 + 1, buffer2, len) < 0) { + fprintf(stderr, + "sctp_send_msg returned status < 0\nSomething bad happened on SCTP layer\n"); + free(buffer2); + break; + } + free(buffer2); + } + } else if (message.procedureCode == ProcedureCode_id_InitialContextSetup + && message.direction == S1AP_PDU_PR_initiatingMessage) { + fprintf(stdout, "Received InitialContextSetup request\n"); + s1ap_test_generate_initial_setup_resp( + message.msg.initialContextSetupRequestIEs.eNB_UE_S1AP_ID, + message.msg.initialContextSetupRequestIEs.mme_ue_s1ap_id, + 0x5, + 0x1, + &buffer2, + &len); + if (sctp_send_msg(assocId, stream, buffer2, len) < 0) { + fprintf(stderr, + "sctp_send_msg returned status < 0\nSomething bad happened on SCTP layer\n"); + free(buffer2); + } + free(buffer2); + } else { + fprintf(stderr, "Received unexpected message %d %d\n", message.procedureCode, + message.direction); + free(buffer); + return -1; + } + + free(buffer); + + return 0; +} + +int sctp_connected(void *args, + uint32_t assocId, + uint32_t instreams, + uint32_t outstreams) +{ + uint8_t *buffer; + uint32_t len; + + fprintf(stdout, "New association %d\n", assocId); + + s1ap_test_generate_s1_setup_request(assocId * nb_eNB, &buffer, &len); + + if (sctp_send_msg(assocId, 0, buffer, len) < 0) { + free(buffer); + fprintf(stderr, + "sctp_send_msg returned status < 0. Something bad happened on SCTP layer\n"); + exit(0); + } + free(buffer); + + connected_eNB++; + return 0; +} + +int main(int argc, char *argv[]) +{ + asn_enc_rval_t retVal; + + int i; + + SupportedTAs_Item_t ta; + PLMNidentity_t plmnIdentity; + + asn_debug = 0; + asn1_xer_print = 0; + + if (argc > 1) { + nb_eNB = atoi(argv[1]); + if (argc > 2) { + nb_ue = atoi(argv[2]); + } + } + + for (i = 0; i < nb_eNB; i++) { + sctp_connect_to_remote_host(ip_addr, 36412, 18, NULL, sctp_connected, + recv_callback); + } + while (1) { + sleep(1); + } + + +// generateUplinkNASTransport(&buffer, &len); +// sctp_send_msg(assoc[0], 0, buffer, len); +// s1ap_mme_decode_pdu(buffer, len); + + sctp_terminate(); + + return(0); +} \ No newline at end of file diff --git a/openair-cn/TEST/oaisim_mme_s1ap_test.c b/openair-cn/TEST/oaisim_mme_s1ap_test.c new file mode 100644 index 0000000000..efda980e1b --- /dev/null +++ b/openair-cn/TEST/oaisim_mme_s1ap_test.c @@ -0,0 +1,180 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdint.h> +#include <string.h> + +#include "s1ap_common.h" +#include "s1ap_eNB_decoder.h" +#include "s1ap_mme_decoder.h" +#include "s1ap_eNB_encoder.h" + +#define MAX_BUF_LENGTH (1024) + +typedef struct { + char *procedure_name; + uint8_t buffer[MAX_BUF_LENGTH]; + uint32_t buf_len; +} s1ap_test_t; + +s1ap_test_t s1ap_test[] = { +// { +// .procedure_name = "Downlink NAS transport", +// .buffer = { +// 0x00, 0x0B, 0x40, 0x21, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, +// 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, +// 0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x0A, 0x09, 0x27, 0xAB, +// 0x1F, 0x7C, 0xEC, 0x01, 0x02, 0x01, 0xD9 +// }, +// .buf_len = 37, +// }, + { + .procedure_name = "Uplink NAS transport", + .buffer = { + 0x00, 0x0D, 0x40, 0x41, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x14, 0x13, 0x27, 0xD3, + 0x77, 0xED, 0x4C, 0x01, 0x02, 0x01, 0xDA, 0x28, 0x08, 0x03, + 0x69, 0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x00, 0x64, 0x40, + 0x08, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x00, 0x20, 0x40, 0x00, + 0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04, + }, + .buf_len = 69, + }, + { + .procedure_name = "UE capability info indication", + .buffer = { + 0x00, 0x16, 0x40, 0x37, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x4A, 0x40, 0x20, 0x1F, 0x00, 0xE8, + 0x01, 0x01, 0xA8, 0x13, 0x80, 0x00, 0x20, 0x83, 0x13, 0x05, + 0x0B, 0x8B, 0xFC, 0x2E, 0x2F, 0xF0, 0xB8, 0xBF, 0xAF, 0x87, + 0xFE, 0x40, 0x44, 0x04, 0x07, 0x0C, 0xA7, 0x4A, 0x80, + }, + .buf_len = 59, + }, + { + .procedure_name = "Initial Context Setup Request", + .buffer = { + 0x00, 0x09, 0x00, 0x80, 0xD4, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, + 0x03, 0x40, 0x01, 0xB3, 0x00, 0x42, 0x00, 0x0A, 0x18, 0x08, + 0xF0, 0xD1, 0x80, 0x60, 0x02, 0xFA, 0xF0, 0x80, 0x00, 0x18, + 0x00, 0x80, 0x81, 0x00, 0x00, 0x34, 0x00, 0x7C, 0x45, 0x00, + 0x09, 0x3D, 0x0F, 0x80, 0x0A, 0x05, 0x00, 0x02, 0x03, 0x78, + 0x48, 0x86, 0x6D, 0x27, 0xC7, 0x97, 0x8E, 0xA1, 0x02, 0x07, + 0x42, 0x01, 0x49, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04, + 0x00, 0x48, 0x52, 0x01, 0xC1, 0x01, 0x09, 0x1B, 0x03, 0x69, + 0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x06, 0x6D, 0x6E, 0x63, + 0x30, 0x39, 0x32, 0x06, 0x6D, 0x63, 0x63, 0x32, 0x30, 0x38, + 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0x0A, 0x80, 0x00, + 0x24, 0x5D, 0x01, 0x00, 0x30, 0x10, 0x23, 0x93, 0x1F, 0x93, + 0x96, 0xFE, 0xFE, 0x74, 0x4B, 0xFF, 0xFF, 0x00, 0xC5, 0x00, + 0x6C, 0x00, 0x32, 0x0B, 0x84, 0x34, 0x01, 0x08, 0x5E, 0x04, + 0xFE, 0xFE, 0xC5, 0x6C, 0x50, 0x0B, 0xF6, 0x02, 0xF8, 0x29, + 0x80, 0x00, 0x01, 0xF0, 0x00, 0x70, 0x8A, 0x53, 0x12, 0x64, + 0x01, 0x01, 0x00, 0x6B, 0x00, 0x05, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + .buf_len = 217, + }, + { + .procedure_name = "Initial context setup response", + .buffer = { + 0x20, 0x09, 0x00, 0x26, 0x00, 0x00, 0x03, 0x00, 0x00, 0x40, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x40, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x33, 0x40, 0x0F, 0x00, 0x00, 0x32, + 0x40, 0x0A, 0x0A, 0x1F, 0x0A, 0x05, 0x02, 0x05, 0x00, 0x0F, + 0x7A, 0x03, + }, + .buf_len = 42, + } +}; + +static int compare_buffer(uint8_t *buffer, uint32_t length_buffer, + uint8_t *pattern, + uint32_t length_pattern) +{ + int i; + if (length_buffer != length_pattern) { + printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern, + length_buffer); + return -1; + } + for (i = 0; i < length_buffer; i++) { + if (pattern[i] != buffer[i]) { + printf("Mismatch fount in bytes %d\nExpecting 0x%02x, got 0x%02x\n", + i, pattern[i], buffer[i]); + } + } + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + asn1_xer_print = 2; + if (argc > 1) { + asn_debug = 1; + } + + for (i = 0; i < sizeof(s1ap_test) / sizeof(s1ap_test_t); i++) { + struct s1ap_message_s message; + uint8_t *buffer; + uint32_t length; + memset(&message, 0, sizeof(struct s1ap_message_s)); + printf("Trying to decode %s procedure with asn1c decoder\n", + s1ap_test[i].procedure_name); + if (s1ap_mme_decode_pdu(&message, s1ap_test[i].buffer, + s1ap_test[i].buf_len) < 0) { + if (s1ap_eNB_decode_pdu(&message, s1ap_test[i].buffer, + s1ap_test[i].buf_len) < 0) { + printf("Failed to decode this message\n"); + } else { + printf("Succesfully decoded %s with eNB decoder\n", s1ap_test[i].procedure_name); + } + } else { + printf("Succesfully decoded %s with MME decoder\n", s1ap_test[i].procedure_name); + } + printf("Trying to encode %s procedure with asn1c encoder\n", + s1ap_test[i].procedure_name); + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + printf("Failed to encode this message on MME side, trying eNB side\n"); + } else { + compare_buffer(buffer, length, s1ap_test[i].buffer, s1ap_test[i].buf_len); + free(buffer); + } + } + return 0; +} diff --git a/openair-cn/TEST/oaisim_mme_sctp_test.c b/openair-cn/TEST/oaisim_mme_sctp_test.c new file mode 100644 index 0000000000..691bef250b --- /dev/null +++ b/openair-cn/TEST/oaisim_mme_sctp_test.c @@ -0,0 +1,88 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netinet/sctp.h> +#include <arpa/inet.h> + +#include "sctp_primitives_client.h" + +#include "s1ap_common.h" +#include "s1ap_eNB.h" +#include "s1ap_mme.h" +#include "s1ap_ies_defs.h" + +#include "s1ap_eNB_encoder.h" +#include "s1ap_eNB_decoder.h" + +int recv_callback(uint32_t assocId, + uint32_t stream, + uint8_t *buffer, + uint32_t length) +{ + + free(buffer); + + return 0; +} + +int sctp_connected(void *args, + uint32_t assocId, + uint32_t instreams, + uint32_t outstreams) +{ + + return 0; +} + +int main(int argc, char *argv[]) +{ + asn_enc_rval_t retVal; + + int i; + + for (i = 0; i < nb_eNB; i++) { + sctp_connect_to_remote_host(ip_addr, 36412, NULL, sctp_connected, recv_callback); + } + while (1) { + sleep(1); + } + + sctp_terminate(); + + return(0); +} \ No newline at end of file diff --git a/openair-cn/TEST/test_aes128_cmac_encrypt.c b/openair-cn/TEST/test_aes128_cmac_encrypt.c new file mode 100644 index 0000000000..6864a9b103 --- /dev/null +++ b/openair-cn/TEST/test_aes128_cmac_encrypt.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +#include <openssl/aes.h> +#include <openssl/cmac.h> +#include <openssl/evp.h> + +static CMAC_CTX *ctx; + +static +void test_cmac(const uint8_t *key, unsigned key_length, const uint8_t *message, + unsigned length, const uint8_t *expect, unsigned expected_length) +{ + size_t size; + uint8_t result[16]; + + ctx = CMAC_CTX_new(); + + CMAC_Init(ctx, key, key_length, EVP_aes_128_cbc(), NULL); + CMAC_Update(ctx, message, length); + CMAC_Final(ctx, result, &size); + + CMAC_CTX_free(ctx); + + if (compare_buffer(result, size, expect, expected_length) != 0) { + fail("test_cmac"); + } +} + +void doit (void) +{ + /* SP300-38B #D.1 */ + + /* Example 1 */ + test_cmac( + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL(""), + HL("bb1d6929e95937287fa37d129b756746")); + /* Example 2 */ + test_cmac( + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL("6bc1bee22e409f96e93d7e117393172a"), + HL("070a16b46b4d4144f79bdd9dd04a287c")); + /* Example 3 */ + test_cmac( + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411"), + HL("dfa66747de9ae63030ca32611497c827")); + /* Example 4 */ + test_cmac( + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + HL("51f0bebf7e3b9d92fc49741779363cfe")); +} diff --git a/openair-cn/TEST/test_aes128_ctr_decrypt.c b/openair-cn/TEST/test_aes128_ctr_decrypt.c new file mode 100644 index 0000000000..3f49518d4e --- /dev/null +++ b/openair-cn/TEST/test_aes128_ctr_decrypt.c @@ -0,0 +1,60 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +#include <nettle/nettle-meta.h> +#include <nettle/aes.h> +#include <nettle/ctr.h> + +static +void test_uncipher_ctr(const struct nettle_cipher *cipher, const uint8_t *key, + unsigned key_length, const uint8_t *cipheredtext, + unsigned length, const uint8_t *cleartext, const uint8_t *ictr) +{ + void *ctx = malloc(cipher->context_size); + uint8_t *data = malloc(length); + uint8_t *ctr = malloc(cipher->block_size); + + cipher->set_encrypt_key(ctx, key_length, key); + memcpy(ctr, ictr, cipher->block_size); + + ctr_crypt(ctx, cipher->encrypt, + cipher->block_size, ctr, + length, data, cipheredtext); + + if (compare_buffer(data, length, cleartext, length) != 0) + { + fail("Fail: test_uncipher_ctr\n"); + } + + free(ctx); + free(data); + free(ctr); +} + +void doit (void) +{ + /* From NIST spec 800-38a on AES modes, + * + * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf + * + * F.5 CTR Example Vectors + */ + /* F.5.1 CTR-AES128.Encrypt */ + test_uncipher_ctr(&nettle_aes128, + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + H("874d6191b620e3261bef6864990db6ce" + "9806f66b7970fdff8617187bb9fffdff" + "5ae4df3edbd5d35e5b4f09020db03eab" + "1e031dda2fbe03d1792170a0f3009cee"), + H("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")); +} diff --git a/openair-cn/TEST/test_aes128_ctr_encrypt.c b/openair-cn/TEST/test_aes128_ctr_encrypt.c new file mode 100644 index 0000000000..3a375f4f19 --- /dev/null +++ b/openair-cn/TEST/test_aes128_ctr_encrypt.c @@ -0,0 +1,59 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +#include <nettle/nettle-meta.h> +#include <nettle/aes.h> +#include <nettle/ctr.h> + +static void test_cipher_ctr(const struct nettle_cipher *cipher, const uint8_t *key, + unsigned key_length, const uint8_t *cleartext, unsigned length, + const uint8_t *ciphertext, const uint8_t *ictr) +{ + void *ctx = malloc(cipher->context_size); + uint8_t *data = malloc(length); + uint8_t *ctr = malloc(cipher->block_size); + + cipher->set_encrypt_key(ctx, key_length, key); + memcpy(ctr, ictr, cipher->block_size); + + ctr_crypt(ctx, cipher->encrypt, + cipher->block_size, ctr, + length, data, cleartext); + + if (compare_buffer(data, length, ciphertext, length) != 0) + { + fail("Fail: test_cipher_ctr"); + } + + free(ctx); + free(data); + free(ctr); +} + +void doit (void) +{ + /* From NIST spec 800-38a on AES modes, + * + * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38A.pdf + * + * F.5 CTR Example Vectors + */ + /* F.5.1 CTR-AES128.Encrypt */ + test_cipher_ctr(&nettle_aes128, + HL("2b7e151628aed2a6abf7158809cf4f3c"), + HL("6bc1bee22e409f96e93d7e117393172a" + "ae2d8a571e03ac9c9eb76fac45af8e51" + "30c81c46a35ce411e5fbc1191a0a52ef" + "f69f2445df4f9b17ad2b417be66c3710"), + H("874d6191b620e3261bef6864990db6ce" + "9806f66b7970fdff8617187bb9fffdff" + "5ae4df3edbd5d35e5b4f09020db03eab" + "1e031dda2fbe03d1792170a0f3009cee"), + H("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff")); +} diff --git a/openair-cn/TEST/test_kdf.c b/openair-cn/TEST/test_kdf.c new file mode 100644 index 0000000000..f87fac3ddb --- /dev/null +++ b/openair-cn/TEST/test_kdf.c @@ -0,0 +1,104 @@ +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "test_util.h" +#include "secu_defs.h" + +static +void do_kdf(uint8_t *key, unsigned key_length, uint8_t *data, unsigned data_length, + uint8_t *exp, unsigned exp_length) +{ + uint8_t *result; + + kdf(data, data_length, key, key_length, &result, 32); + if (compare_buffer(result, exp_length, exp, exp_length) != 0) { + fail("Fail: kdf\n"); + } +} + +void +doit (void) +{ + /* RFC 4231 */ + + /* Test case 1 #4.2 */ + do_kdf(HL("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b" + "0b0b0b0b"), + HL("4869205468657265"), + HL("b0344c61d8db38535ca8afceaf0bf12b" + "881dc200c9833da726e9376c2e32cff7")); + /* Test case 2 #4.3 */ + do_kdf(HL("4a656665"), + HL("7768617420646f2079612077616e7420" + "666f72206e6f7468696e673f"), + HL("5bdcc146bf60754e6a042426089575c7" + "5a003f089d2739839dec58b964ec3843")); + /* Test case 3 #4.4 */ + do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaa"), + HL("dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddddddddddddddddddddddddddddddd" + "dddd"), + HL("773ea91e36800e46854db8ebd09181a7" + "2959098b3ef8c122d9635514ced565fe")); + /* Test case 4 #4.5 */ + do_kdf(HL("0102030405060708090a0b0c0d0e0f10" + "111213141516171819"), + HL("cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + "cdcd"), + HL("82558a389a443c0ea4cc819899f2083a" + "85f0faa3e578f8077a2e3ff46729665b")); + /* Test case 5 #4.6 */ + do_kdf(HL("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c" + "0c0c0c0c"), + HL("546573742057697468205472756e6361" + "74696f6e"), + HL("a3b6167473100ee06e0c796c2955552b")); + /* Test case 6 #4.7 */ + do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa"), + HL("54657374205573696e67204c61726765" + "72205468616e20426c6f636b2d53697a" + "65204b6579202d2048617368204b6579" + "204669727374"), + HL("60e431591ee0b67f0d8a26aacbf5b77f" + "8e0bc6213728c5140546040f0ee37f54")); + /* Test case 6 #4.7 */ + do_kdf(HL("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + "aaaaaa"), + HL("54686973206973206120746573742075" + "73696e672061206c6172676572207468" + "616e20626c6f636b2d73697a65206b65" + "7920616e642061206c61726765722074" + "68616e20626c6f636b2d73697a652064" + "6174612e20546865206b6579206e6565" + "647320746f2062652068617368656420" + "6265666f7265206265696e6720757365" + "642062792074686520484d414320616c" + "676f726974686d2e"), + HL("9b09ffa71b942fcb27635fbcd5b0e944" + "bfdc63644f0713938a7f51535c3a35e2")); +} diff --git a/openair-cn/TEST/test_s1ap.c b/openair-cn/TEST/test_s1ap.c new file mode 100644 index 0000000000..88f9d8560e --- /dev/null +++ b/openair-cn/TEST/test_s1ap.c @@ -0,0 +1,183 @@ + +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "s1ap_common.h" +#include "s1ap_eNB_decoder.h" +#include "s1ap_mme_decoder.h" +#include "s1ap_eNB_encoder.h" +#include "s1ap_mme_encoder.h" + +#define MAX_BUF_LENGTH (1024) + +typedef enum { + MME, + ENB +} entity_t; + +typedef struct { + char *procedure_name; + uint8_t buffer[MAX_BUF_LENGTH]; + uint32_t buf_len; + entity_t originating; +} s1ap_test_t; + +s1ap_test_t s1ap_test[] = { + { + .procedure_name = "Downlink NAS transport", + .buffer = { + 0x00, 0x0B, 0x40, 0x21, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x0A, 0x09, 0x27, 0xAB, + 0x1F, 0x7C, 0xEC, 0x01, 0x02, 0x01, 0xD9 + }, + .buf_len = 37, + .originating = MME, + }, + { + .procedure_name = "Uplink NAS transport", + .buffer = { + 0x00, 0x0D, 0x40, 0x41, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x14, 0x13, 0x27, 0xD3, + 0x77, 0xED, 0x4C, 0x01, 0x02, 0x01, 0xDA, 0x28, 0x08, 0x03, + 0x69, 0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x00, 0x64, 0x40, + 0x08, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x00, 0x20, 0x40, 0x00, + 0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04, + }, + .buf_len = 69, + .originating = ENB, + }, + { + .procedure_name = "UE capability info indication", + .buffer = { + 0x00, 0x16, 0x40, 0x37, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x4A, 0x40, 0x20, 0x1F, 0x00, 0xE8, + 0x01, 0x01, 0xA8, 0x13, 0x80, 0x00, 0x20, 0x83, 0x13, 0x05, + 0x0B, 0x8B, 0xFC, 0x2E, 0x2F, 0xF0, 0xB8, 0xBF, 0xAF, 0x87, + 0xFE, 0x40, 0x44, 0x04, 0x07, 0x0C, 0xA7, 0x4A, 0x80, + }, + .buf_len = 59, + .originating = ENB, + }, + { + .procedure_name = "Initial Context Setup Request", + .buffer = { + 0x00, 0x09, 0x00, 0x80, 0xD4, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, + 0x03, 0x40, 0x01, 0xB3, 0x00, 0x42, 0x00, 0x0A, 0x18, 0x08, + 0xF0, 0xD1, 0x80, 0x60, 0x02, 0xFA, 0xF0, 0x80, 0x00, 0x18, + 0x00, 0x80, 0x81, 0x00, 0x00, 0x34, 0x00, 0x7C, 0x45, 0x00, + 0x09, 0x3D, 0x0F, 0x80, 0x0A, 0x05, 0x00, 0x02, 0x03, 0x78, + 0x48, 0x86, 0x6D, 0x27, 0xC7, 0x97, 0x8E, 0xA1, 0x02, 0x07, + 0x42, 0x01, 0x49, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04, + 0x00, 0x48, 0x52, 0x01, 0xC1, 0x01, 0x09, 0x1B, 0x03, 0x69, + 0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x06, 0x6D, 0x6E, 0x63, + 0x30, 0x39, 0x32, 0x06, 0x6D, 0x63, 0x63, 0x32, 0x30, 0x38, + 0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0x0A, 0x80, 0x00, + 0x24, 0x5D, 0x01, 0x00, 0x30, 0x10, 0x23, 0x93, 0x1F, 0x93, + 0x96, 0xFE, 0xFE, 0x74, 0x4B, 0xFF, 0xFF, 0x00, 0xC5, 0x00, + 0x6C, 0x00, 0x32, 0x0B, 0x84, 0x34, 0x01, 0x08, 0x5E, 0x04, + 0xFE, 0xFE, 0xC5, 0x6C, 0x50, 0x0B, 0xF6, 0x02, 0xF8, 0x29, + 0x80, 0x00, 0x01, 0xF0, 0x00, 0x70, 0x8A, 0x53, 0x12, 0x64, + 0x01, 0x01, 0x00, 0x6B, 0x00, 0x05, 0x18, 0x00, 0x0C, 0x00, + 0x00, 0x00, 0x49, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + }, + .buf_len = 217, + .originating = MME, + }, + { + .procedure_name = "Initial Context Setup Response", + .buffer = { + 0x20, 0x09, 0x00, 0x26, 0x00, 0x00, 0x03, 0x00, 0x00, 0x40, + 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x40, 0x03, + 0x40, 0x01, 0xB3, 0x00, 0x33, 0x40, 0x0F, 0x00, 0x00, 0x32, + 0x40, 0x0A, 0x0A, 0x1F, 0x0A, 0x05, 0x02, 0x05, 0x00, 0x0F, + 0x7A, 0x03, + }, + .buf_len = 42, + .originating = ENB, + } +}; + +static int compare_buffer(uint8_t *buffer, uint32_t length_buffer, + uint8_t *pattern, uint32_t length_pattern) +{ + int i; + if (length_buffer != length_pattern) { + printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern, + length_buffer); + hexprint(buffer, length_buffer); + return -1; + } + for (i = 0; i < length_buffer; i++) { + if (pattern[i] != buffer[i]) { + hexprint(buffer, length_buffer); + printf("Mismatch fount in byte %d\nExpecting 0x%02x, got 0x%02x\n", + i, pattern[i], buffer[i]); + return -1; + } + } + return 0; +} + +void doit (void) +{ + int i; + + break_on_error = 1; + +// asn1_xer_print = 1; +// asn_debug = 1; + + for (i = 0; i < sizeof(s1ap_test) / sizeof(s1ap_test_t); i++) { + struct s1ap_message_s message; + uint8_t *buffer; + uint32_t length; + + memset(&message, 0, sizeof(struct s1ap_message_s)); + + if (s1ap_test[i].originating == ENB) { + /* eNB originated procedure -> USE MME decoder */ + if (s1ap_mme_decode_pdu(&message, s1ap_test[i].buffer, + s1ap_test[i].buf_len) < 0) { + fail("Failed to decode %s\n", s1ap_test[i].procedure_name); + } else { + success("Decoded %s correctly\n", s1ap_test[i].procedure_name); + } + } else { + /* MME originated procedure -> USE eNB decoder */ + if (s1ap_eNB_decode_pdu(&message, s1ap_test[i].buffer, + s1ap_test[i].buf_len) < 0) { + fail("Failed to decode %s\n", s1ap_test[i].procedure_name); + } else { + success("Decoded %s correctly\n", s1ap_test[i].procedure_name); + } + } + + if (s1ap_test[i].originating == ENB) { + /* eNB originated procedure -> USE eNB encoder */ + if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) { + fail("Failed to decode %s\n", s1ap_test[i].procedure_name); + } else { + success("Encoded %s correctly\n", s1ap_test[i].procedure_name); + } + } else { + /* MME originated procedure -> USE mme encoder */ + if (s1ap_mme_encode_pdu(&message, &buffer, &length) < 0) { + fail("Failed to encode %s\n", s1ap_test[i].procedure_name); + } else { + success("Encoded %s correctly\n", s1ap_test[i].procedure_name); + } + } + if (compare_buffer(buffer, length, s1ap_test[i].buffer, s1ap_test[i].buf_len) < 0) { + fail("Mismatch in buffers\n"); + } + } +} diff --git a/openair-cn/TEST/test_secu.c b/openair-cn/TEST/test_secu.c new file mode 100644 index 0000000000..9d250be255 --- /dev/null +++ b/openair-cn/TEST/test_secu.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +typedef struct { + uint8_t kasme[32]; + uint8_t kenb_exp[16]; + uint32_t nas_count; +} test_secu_t; + +const test_secu_t kenb_test_vector[] = { + { + .kasme = { + + }, + .kenb_exp = { + + }, + .nas_count = 0x001FB39C; + } +}; + +void doit (void) +{ + int i; + + for (i = 0; i < sizeof(kenb_test_vector) / sizeof(test_secu_t); i++) { + uint8_t kenb[32]; + + derive_keNB(kenb_test_vector[i].kasme, kenb_test_vector[i].nas_count, kenb); + + if (compare_buffer(kenb_test_vector[i].kenb, 32, kenb, 32) == 0) { + success("kenb derivation"); + } else { + fail("kenb derivation"); + } + } +} diff --git a/openair-cn/TEST/test_secu_kenb.c b/openair-cn/TEST/test_secu_kenb.c new file mode 100644 index 0000000000..3c823a5dba --- /dev/null +++ b/openair-cn/TEST/test_secu_kenb.c @@ -0,0 +1,43 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +static +void do_derive_kenb(uint32_t nas_count, const uint8_t *kasme, const unsigned length, + const uint8_t *kenb_exp) +{ + uint8_t *kenb; + + derive_keNB(kasme, nas_count, &kenb); + if (compare_buffer(kenb_exp, length, kenb, length) != 0) { + fail("Fail: kenb derivation\n"); + } + free(kenb); +} + +void doit (void) +{ + do_derive_kenb(0xDB1A3569, + HL("238E457E0F758BADBCA8D34BB2612C10428D426757CB5553B2B184FA64BFC549"), + H("8EB1BF0083BD79281EF7034BF677E9EC529F196E15287514A2D122ACF713B8E8")); + do_derive_kenb(0x001FB39C, + HL("564CB4D2007E4F293B67D9B29392A64ADD4C776B133D895AF6499AA6882AAB62"), + H("009010688F85855E218339DE6C5BD7B6394958DA12DDFBF7559E978CE43408F1")); + do_derive_kenb(0x00000012, + HL("FA77E41F693C2A6E71455CB8687E6E6058EF91E2F5ABD1BD3C496179481F308C"), + H("0AFE81266DE52B8C8F1C3F4FE799BE883F364B018E7368C41F14DD6D050E13E1")); + do_derive_kenb(0xFE56A1D3, + HL("FA77E41F693C2A6E71455CB8687E6E6058EF91E2F5ABD1BD3C496179481F308C"), + H("3622874B06C683586A009DEC81DBE28BDD8E3E6E67A2C22C31630EC97641828E")); + do_derive_kenb(0xFE56A1D3, + HL("70D7071AA016A087F9D888AD51F3A83E2C83443AB27843B35BD1B4923615091C"), + H("E59BE6F0FBEFA1207DA3FF05D0F82014100E7A63A11EEBFE4F8AA92E7CF8B847")); + do_derive_kenb(0xAABBCCDD, + HL("70D7071AA016A087F9D888AD51F3A83E2C83443AB27843B35BD1B4923615091C"), + H("158781A2FDF2CE53ABFA186D22EB751DECB8273471DC792B5016C9016947D1AE")); +} diff --git a/openair-cn/TEST/test_secu_knas.c b/openair-cn/TEST/test_secu_knas.c new file mode 100644 index 0000000000..eb63257238 --- /dev/null +++ b/openair-cn/TEST/test_secu_knas.c @@ -0,0 +1,70 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +static +void derive_knas_keys(algorithm_type_dist_t atd, uint8_t *kasme, unsigned length, + uint8_t *knas_enc_exp, uint8_t *knas_int_exp) +{ + uint8_t *knas_enc; + uint8_t *knas_int; + + derive_key_nas_enc(atd, kasme, &knas_enc); + derive_key_nas_int(atd, kasme, &knas_int); + + /* Compare both keys with expected */ + if (compare_buffer(knas_enc, 32, knas_enc_exp, 32) != 0) { + fail("Fail: knas_enc derivation\n"); + } + if (compare_buffer(knas_int, 32, knas_int_exp, 32) != 0) { + fail("Fail: knas_int derivation\n"); + } + + free(knas_enc); + free(knas_int); +} + +void doit(void) +{ + derive_knas_keys(EIA0_ALG_ID, + HL("70D7071AA016A087F9D888AD51F3A83E2C83443AB27843B35BD1B4923615091C"), + H("64BA839B29C451085C552F4DE9D278B263CB5BDD7FC21A38120637B2A9E5CD39"), + H("A66A2D198AF2A8D6A5FF2FAA51676037DF204187C61EDD3AAA70F3B7D8B59E8B")); + derive_knas_keys(EIA1_128_ALG_ID, + HL("70D7071AA016A087F9D888AD51F3A83E2C83443AB27843B35BD1B4923615091C"), + H("DF8FEBA477891617C42FB16F750E572C9E59ED7564879150F6BB0DAEF5932E89"), + H("EA1158BA3F387BC96C967BC32FB43F65AE172A3267343479CAA826034A90A250")); + derive_knas_keys(EIA2_128_ALG_ID, + HL("70D7071AA016A087F9D888AD51F3A83E2C83443AB27843B35BD1B4923615091C"), + H("99D63BD2D43AF81EBB7599F7E8F8B3E81CF7897F31D6270C19C4836070FE11F0"), + H("FC7A3850D19AE29EC7000B9DF98787F11A4329FD23FD3A93C9D2D92D853EC9DB")); + derive_knas_keys(EIA0_ALG_ID, + HL("9EA141DA4B24CDEBC8F5FB3F61A0511216681F121199B23EBCFACC75B358BE43"), + H("1E48E1B5EDF98DEDF339DE686544AA1088C8E5616EDB706201837AA106D37691"), + H("C83DC420F97AA42D1B8488FA5D8F74865D833416D5851556100B41FEC8E38139")); + derive_knas_keys(EIA1_128_ALG_ID, + HL("9EA141DA4B24CDEBC8F5FB3F61A0511216681F121199B23EBCFACC75B358BE43"), + H("207700CD92B4635B439E40176F92F7ADA824B9D699ABE15F86F3346C25343A33"), + H("FAA39E382611CDFED52042E72AF8CECDF92CCD799141857B77B6901741E486B2")); + derive_knas_keys(EIA2_128_ALG_ID, + HL("9EA141DA4B24CDEBC8F5FB3F61A0511216681F121199B23EBCFACC75B358BE43"), + H("2A6854D25282FFD738FA8BBCFDCE853C0C4DFB9F559DCBB71D5120DB2CAC66A6"), + H("5EDCAE62A35BC42399C55F64ECAE7B17524BED1ED1601218D2772E55DDFAD959")); + derive_knas_keys(EIA0_ALG_ID, + HL("546A79BC6D1613A72A4D631EE0351D66036B2A0C44A3831BE6D365E24F023013"), + H("7F684F909A5910DED6E4B4CE02AC92DF4690EB3788068600E9CB2C3EF8F0956E"), + H("51F3B142D357371726873FAC5E853CE0EEEFC52A695DE45FA6F4A23D20C13155")); + derive_knas_keys(EIA1_128_ALG_ID, + HL("546A79BC6D1613A72A4D631EE0351D66036B2A0C44A3831BE6D365E24F023013"), + H("B6B222E9C07C56D15176C8E95EC1805561492682E4B9CD7228237A6C78702347"), + H("4DC5ABF6896DA460473288D16DE83C480388C6FD9E803C7EA88090F311354A15")); + derive_knas_keys(EIA2_128_ALG_ID, + HL("546A79BC6D1613A72A4D631EE0351D66036B2A0C44A3831BE6D365E24F023013"), + H("7BD2A0864452D3D9EDE3B2E38A9958777F231AC4F4B9AF3FC8CE0E1EAAB425A7"), + H("89E8049EBE9374F238B0F3278EEA47D9BF8877111D99D6378FFF66FEBB06F3F8")); +} diff --git a/openair-cn/TEST/test_secu_knas_encrypt_eea2.c b/openair-cn/TEST/test_secu_knas_encrypt_eea2.c new file mode 100644 index 0000000000..c2c1916a14 --- /dev/null +++ b/openair-cn/TEST/test_secu_knas_encrypt_eea2.c @@ -0,0 +1,142 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +static +void eea2_encrypt(uint8_t direction, uint32_t count, + uint8_t bearer, uint8_t *key, uint32_t key_length, uint8_t *message, + uint32_t length, uint8_t *expected) +{ + nas_stream_cipher_t *nas_cipher; + uint8_t *result; + uint32_t zero_bits = length & 7; + uint32_t byte_length = length >> 3; + + if (zero_bits > 0) + byte_length += 1; + + nas_cipher = calloc(1, sizeof(nas_stream_cipher_t)); + + nas_cipher->direction = direction; + nas_cipher->count = count; + nas_cipher->key = key; + nas_cipher->key_length = key_length; + nas_cipher->bearer = bearer; + nas_cipher->blength = length; + nas_cipher->message = message; + + if (nas_stream_encrypt_eea2(nas_cipher, &result) != 0) + fail("Fail: nas_stream_encrypt_eea2\n"); + if (compare_buffer(result, byte_length, expected, byte_length) != 0) { + fail("Fail: eea2_encrypt\n"); + } + + free(nas_cipher); + free(result); +} + + +void doit (void) +{ + /* Test suite from 3GPP TS33.401 #Appendix C.1 */ + + /* Test set 1 #C.1.1 */ + eea2_encrypt( + 1, 0x398a59b4, 0x15, HL("d3c5d592327fb11c4035c6680af8c6d1"), + H("981ba6824c1bfb1ab485472029b71d808ce33e2cc3c0b5fc1f3de8a6dc66b1f0"), + 253, + H("e9fed8a63d155304d71df20bf3e82214b20ed7dad2f233dc3c22d7bdeeed8e78") + ); + /* Test set 2 #C.1.2 */ + eea2_encrypt( + 1, 0xc675a64b, 0x0c, HL("2bd6459f82c440e0952c49104805ff48"), + H("7ec61272743bf1614726446a6c38ced166f6ca76eb5430044286346cef130f92" + "922b03450d3a9975e5bd2ea0eb55ad8e1b199e3ec4316020e9a1b285e7627953" + "59b7bdfd39bef4b2484583d5afe082aee638bf5fd5a606193901a08f4ab41aab" + "9b134880"), + 798, + H("5961605353c64bdca15b195e288553a910632506d6200aa790c4c806c99904cf" + "2445cc50bb1cf168a49673734e081b57e324ce5259c0e78d4cd97b870976503c" + "0943f2cb5ae8f052c7b7d392239587b8956086bcab18836042e2e6ce42432a17" + "105c53d0") + ); + /* Test set 3 #C.1.3 */ + eea2_encrypt( + 0, 0x544d49cd, 0x04, HL("0a8b6bd8d9b08b08d64e32d1817777fb"), + H("fd40a41d370a1f65745095687d47ba1d36d2349e23f644392c8ea9c49d40c132" + "71aff264d0f24800"), + 310, + H("75750d37b4bba2a4dedb34235bd68c6645acdaaca48138a3b0c471e2a7041a57" + "6423d2927287f000") + ); + /* Test set 4 #C.1.4 */ + eea2_encrypt( + 1, 0x72d8c671, 0x10, HL("aa1f95aea533bcb32eb63bf52d8f831a"), + H("fb1b96c5c8badfb2e8e8edfde78e57f2ad81e74103fc430a534dcc37afcec70e" + "1517bb06f27219dae49022ddc47a068de4c9496a951a6b09edbdc864c7adbd74" + "0ac50c022f3082bafd22d78197c5d508b977bca13f32e652e74ba728576077ce" + "628c535e87dc6077ba07d29068590c8cb5f1088e082cfa0ec961302d69cf3d44"), + 1022, + H("dfb440acb3773549efc04628aeb8d8156275230bdc690d94b00d8d95f28c4b56" + "307f60f4ca55eba661ebba72ac808fa8c49e26788ed04a5d606cb418de74878b" + "9a22f8ef29590bc4eb57c9faf7c41524a885b8979c423f2f8f8e0592a9879201" + "be7ff9777a162ab810feb324ba74c4c156e04d39097209653ac33e5a5f2d8864") + ); + /* Test set 5 #C.1.5 */ + eea2_encrypt( + 1, 0xc675a64b, 0x0c, HL("9618ae46891f86578eebe90ef7a1202e"), + H("8daa17b1ae050529c6827f28c0ef6a1242e93f8b314fb18a77f790ae049fedd6" + "12267fecaefc450174d76d9f9aa7755a30cd90a9a5874bf48eaf70eea3a62a25" + "0a8b6bd8d9b08b08d64e32d1817777fb544d49cd49720e219dbf8bbed33904e1" + "fd40a41d370a1f65745095687d47ba1d36d2349e23f644392c8ea9c49d40c132" + "71aff264d0f24841d6465f0996ff84e65fc517c53efc3363c38492a8"), + 1245, + H("919c8c33d66789703d05a0d7ce82a2aeac4ee76c0f4da050335e8a84e7897ba5" + "df2f36bd513e3d0c8578c7a0fcf043e03aa3a39fbaad7d15be074faa5d9029f7" + "1fb457b647834714b0e18f117fca10677945096c8c5f326ba8d6095eb29c3e36" + "cf245d1622aafe921f7566c4f5d644f2f1fc0ec684ddb21349747622e209295d" + "27ff3f95623371d49b147c0af486171f22cd04b1cbeb2658223e6938") + ); + /* Test set 6 #C.1.6 */ + eea2_encrypt( + 0, 0xaca4f50f, 0x0b, HL("54f4e2e04c83786eec8fb5abe8e36566"), + H("40981ba6824c1bfb4286b299783daf442c099f7ab0f58d5c8e46b104f08f01b4" + "1ab485472029b71d36bd1a3d90dc3a41b46d51672ac4c9663a2be063da4bc8d2" + "808ce33e2cccbfc634e1b259060876a0fbb5a437ebcc8d31c19e4454318745e3" + "fa16bb11adae248879fe52db2543e53cf445d3d828ce0bf5c560593d97278a59" + "762dd0c2c9cd68d4496a792508614014b13b6aa51128c18cd6a90b87978c2ff1" + "cabe7d9f898a411bfdb84f68f6727b1499cdd30df0443ab4a66653330bcba110" + "5e4cec034c73e605b4310eaaadcfd5b0ca27ffd89d144df4792759427c9cc1f8" + "cd8c87202364b8a687954cb05a8d4e2d99e73db160deb180ad0841e96741a5d5" + "9fe4189f15420026fe4cd12104932fb38f735340438aaf7eca6fd5cfd3a195ce" + "5abe65272af607ada1be65a6b4c9c0693234092c4d018f1756c6db9dc8a6d80b" + "888138616b681262f954d0e7711748780d92291d86299972db741cfa4f37b8b5" + "6cdb18a7ca8218e86e4b4b716a4d04371fbec262fc5ad0b3819b187b97e55b1a" + "4d7c19ee24c8b4d7723cfedf045b8acae4869517d80e50615d9035d5d9c5a40a" + "f602280b542597b0cb18619eeb35925759d195e100e8e4aa0c38a3c2abe0f3d8" + "ff04f3c33c295069c23694b5bbeacdd542e28e8a94edb9119f412d054be1fa72" + "00b09000"), + 3861, + H("5cb72c6edc878f1566e10253afc364c9fa540d914db94cbee275d0917ca6af0d" + "77acb4ef3bbe1a722b2ef5bd1d4b8e2aa5024ec1388a201e7bce7920aec61589" + "5f763a5564dcc4c482a2ee1d8bfecc4498eca83fbb75f9ab530e0dafbede2fa5" + "895b82991b6277c529e0f2529d7f79606be96706296dedfa9d7412b616958cb5" + "63c678c02825c30d0aee77c4c146d2765412421a808d13cec819694c75ad572e" + "9b973d948b81a9337c3b2a17192e22c2069f7ed1162af44cdea817603665e807" + "ce40c8e0dd9d6394dc6e31153fe1955c47afb51f2617ee0c5e3b8ef1ad7574ed" + "343edc2743cc94c990e1f1fd264253c178dea739c0befeebcd9f9b76d49c1015" + "c9fecf50e53b8b5204dbcd3eed863855dabcdcc94b31e318021568855c8b9e52" + "a981957a112827f978ba960f1447911b317b5511fbcc7fb13ac153db74251117" + "e4861eb9e83bffffc4eb7755579038e57924b1f78b3e1ad90bab2a07871b72db" + "5eef96c334044966db0c37cafd1a89e5646a3580eb6465f121dce9cb88d85b96" + "cf23ccccd4280767bee8eeb23d8652461db6493103003baf89f5e18261ea43c8" + "4a92ebffffe4909dc46c5192f825f770600b9602c557b5f8b431a79d45977dd9" + "c41b863da9e142e90020cfd074d6927b7ab3b6725d1a6f3f98b9c9daa8982aff" + "06782800") + ); +} diff --git a/openair-cn/TEST/test_secu_knas_encrypt_eia2.c b/openair-cn/TEST/test_secu_knas_encrypt_eia2.c new file mode 100644 index 0000000000..359476ec31 --- /dev/null +++ b/openair-cn/TEST/test_secu_knas_encrypt_eia2.c @@ -0,0 +1,178 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +static +void eia2_encrypt(uint8_t direction, uint32_t count, + uint8_t bearer, uint8_t *key, uint32_t key_length, uint8_t *message, + uint32_t length, uint8_t *expected, uint32_t length_expected) +{ + nas_stream_cipher_t nas_cipher; + uint8_t result[4]; + + nas_cipher.direction = direction; + nas_cipher.count = count; + nas_cipher.key = key; + nas_cipher.key_length = key_length; + nas_cipher.bearer = bearer; + nas_cipher.blength = length; + nas_cipher.message = message; + + if (nas_stream_encrypt_eia2(&nas_cipher, result) != 0) { + fail("Fail: nas_stream_encrypt_eia2\n"); + } + if (compare_buffer(result, 4, expected, length_expected) != 0) { + fail("Fail: eia2_encrypt\n"); + } +} + +void doit (void) +{ + /* Test suite from 3GPP TS33.401 #Appendix C.2 + * For EPS implementation verification, byte alignment test data sets + * (2, 5 and 8) can be used, as EPS RRC and EPS NAS messages are byte aligned. + * The non byte aligned test data sets may be used to verify implementations + * that support non byte aligned messages. + */ + + /* Test set 2 #C.2.2 */ + eia2_encrypt( + 1, 0x398a59b4, 0x1a, HL("d3c5d592327fb11c4035c6680af8c6d1"), + H("484583d5afe082ae"), + 64, + HL("b93787e6") + ); + /* Test set 5 #C.2.5 */ + eia2_encrypt( + 1, 0x36af6144, 0x0f, HL("83fd23a244a74cf358da3019f1722635"), + H("35c68716633c66fb750c266865d53c11ea05b1e9fa49c8398d48e1efa5909d39" + "47902837f5ae96d5a05bc8d61ca8dbef1b13a4b4abfe4fb1006045b674bb5472" + "9304c382be53a5af05556176f6eaa2ef1d05e4b083181ee674cda5a485f74d7a"), + 768, + HL("e657e182") + ); + /* Test set 8 #C.2.8 */ + eia2_encrypt( + 1, 0x296f393c, 0x0b, HL("b3120ffdb2cf6af4e73eaf2ef4ebec69"), + H("00000000000000000101010101010101e0958045f3a0bba4e3968346f0a3b8a7" + "c02a018ae640765226b987c913e6cbf083570016cf83efbc61c082513e21561a" + "427c009d28c298eface78ed6d56c2d4505ad032e9c04dc60e73a81696da665c6" + "c48603a57b45ab33221585e68ee3169187fb0239528632dd656c807ea3248b7b" + "46d002b2b5c7458eb85b9ce95879e0340859055e3b0abbc3eace8719caa80265" + "c97205d5dc4bcc902fe1839629ed71328a0f0449f588557e6898860e042aecd8" + "4b2404c212c9222da5bf8a89ef6797870cf50771a60f66a2ee62853657addf04" + "cdde07fa414e11f12b4d81b9b4e8ac538ea30666688d881f6c348421992f31b9" + "4f8806ed8fccff4c9123b89642527ad613b109bf75167485f1268bf884b4cd23" + "d29a0934925703d634098f7767f1be7491e708a8bb949a3873708aef4a36239e" + "50cc08235cd5ed6bbe578668a17b58c1171d0b90e813a9e4f58a89d719b11042" + "d6360b1b0f52deb730a58d58faf46315954b0a872691475977dc88c0d733feff" + "54600a0cc1d0300aaaeb94572c6e95b01ae90de04f1dce47f87e8fa7bebf77e1" + "dbc20d6ba85cb9143d518b285dfa04b698bf0cf7819f20fa7a288eb0703d995c" + "59940c7c66de57a9b70f82379b70e2031e450fcfd2181326fcd28d8823baaa80" + "df6e0f443559647539fd8907c0ffd9d79c130ed81c9afd9b7e848c9fed38443d" + "5d380e53fbdb8ac8c3d3f06876054f122461107de92fea09c6f6923a188d53af" + "e54a10f60e6e9d5a03d996b5fbc820f8a637116a27ad04b444a0932dd60fbd12" + "671c11e1c0ec73e789879faa3d42c64d20cd1252742a3768c25a901585888ece" + "e1e612d9936b403b0775949a66cdfd99a29b1345baa8d9d5400c91024b0a6073" + "63b013ce5de9ae869d3b8d95b0570b3c2d391422d32450cbcfae96652286e96d" + "ec1214a9346527980a8192eac1c39a3aaf6f15351da6be764df89772ec0407d0" + "6e4415befae7c92580df9bf507497c8f2995160d4e218daacb02944abf83340c" + "e8be1686a960faf90e2d90c55cc6475babc3171a80a363174954955d7101dab1" + "6ae8179167e21444b443a9eaaa7c91de36d118c39d389f8dd4469a846c9a262b" + "f7fa18487a79e8de11699e0b8fdf557cb48719d453ba713056109b93a218c896" + "75ac195fb4fb06639b3797144955b3c9327d1aec003d42ecd0ea98abf19ffb4a" + "f3561a67e77c35bf15c59c2412da881db02b1bfbcebfac5152bc99bc3f1d15f7" + "71001b7029fedb028f8b852bc4407eb83f891c9ca733254fdd1e9edb56919ce9" + "fea21c174072521c18319a54b5d4efbebddf1d8b69b1cbf25f489fcc98137254" + "7cf41d008ef0bca1926f934b735e090b3b251eb33a36f82ed9b29cf4cb944188" + "fa0e1e38dd778f7d1c9d987b28d132dfb9731fa4f4b416935be49de30516af35" + "78581f2f13f561c0663361941eab249a4bc123f8d15cd711a956a1bf20fe6eb7" + "8aea2373361da0426c79a530c3bb1de0c99722ef1fde39ac2b00a0a8ee7c800a" + "08bc2264f89f4effe627ac2f0531fb554f6d21d74c590a70adfaa390bdfbb3d6" + "8e46215cab187d2368d5a71f5ebec081cd3b20c082dbe4cd2faca28773795d6b" + "0c10204b659a939ef29bbe1088243624429927a7eb576dd3a00ea5e01af5d475" + "83b2272c0c161a806521a16ff9b0a722c0cf26b025d5836e2258a4f7d4773ac8" + "01e4263bc294f43def7fa8703f3a4197463525887652b0b2a4a2a7cf87f00914" + "871e25039113c7e1618da34064b57a43c463249fb8d05e0f26f4a6d84972e7a9" + "054824145f91295cdbe39a6f920facc659712b46a54ba295bbe6a90154e91b33" + "985a2bcd420ad5c67ec9ad8eb7ac6864db272a516bc94c2839b0a8169a6bf58e" + "1a0c2ada8c883b7bf497a49171268ed15ddd2969384e7ff4bf4aab2ec9ecc652" + "9cf629e2df0f08a77a65afa12aa9b505df8b287ef6cc91493d1caa39076e28ef" + "1ea028f5118de61ae02bb6aefc3343a050292f199f401857b2bead5e6ee2a1f1" + "91022f9278016f047791a9d18da7d2a6d27f2e0e51c2f6ea30e8ac49a0604f4c" + "13542e85b68381b9fdcfa0ce4b2d341354852d360245c536b612af71f3e77c90" + "95ae2dbde504b265733dabfe10a20fc7d6d32c21ccc72b8b3444ae663d65922d" + "17f82caa2b865cd88913d291a65899026ea1328439723c198c36b0c3c8d085bf" + "af8a320fde334b4a4919b44c2b95f6e8ecf73393f7f0d2a40e60b1d406526b02" + "2ddc331810b1a5f7c347bd53ed1f105d6a0d30aba477e178889ab2ec55d558de" + "ab2630204336962b4db5b663b6902b89e85b31bc6af50fc50accb3fb9b57b663" + "297031378db47896d7fbaf6c600add2c67f936db037986db856eb49cf2db3f7d" + "a6d23650e438f1884041b013119e4c2ae5af37cccdfb68660738b58b3c59d1c0" + "248437472aba1f35ca1fb90cd714aa9f635534f49e7c5bba81c2b6b36fdee21c" + "a27e347f793d2ce944edb23c8c9b914be10335e350feb5070394b7a4a15c0ca1" + "20283568b7bfc254fe838b137a2147ce7c113a3a4d65499d9e86b87dbcc7f03b" + "bd3a3ab1aa243ece5ba9bcf25f82836cfe473b2d83e7a7201cd0b96a72451e86" + "3f6c3ba664a6d073d1f7b5ed990865d978bd3815d06094fc9a2aba5221c22d5a" + "b996389e3721e3af5f05beddc2875e0dfaeb39021ee27a41187cbb45ef40c3e7" + "3bc03989f9a30d12c54ba7d2141da8a875493e65776ef35f97debc2286cc4af9" + "b4623eee902f840c52f1b8ad658939aef71f3f72b9ec1de21588bd35484ea444" + "36343ff95ead6ab1d8afb1b2a303df1b71e53c4aea6b2e3e9372be0d1bc99798" + "b0ce3cc10d2a596d565dba82f88ce4cff3b33d5d24e9c0831124bf1ad54b7925" + "32983dd6c3a8b7d0"), + 16448, + HL("ebd5ccb0") + ); + /* Test set 1 #C.2.1 */ +#if defined(EIA2_NON_BYTE_ALIGNED_SUPPORTED) + eia2_encrypt( + 0, 0x38a6f056, 0x18, HL("2bd6459f82c5b300952c49104881ff48"), + H("3332346263393840"), + 58, + HL("118c6eb8") + ); + /* Test set 3 #C.2.3 */ + eia2_encrypt( + 1, 0x36af6144, 0x18, HL("7e5e94431e11d73828d739cc6ced4573"), + H("b3d3c9170a4e1632f60f861013d22d84b726b6a278d802d1eeaf1321ba5929dc"), + 254, + HL("1f60b01d") + ); + /* Test set 4 #C.2.4 */ + eia2_encrypt( + 0, 0xc7590ea9, 0x17, HL("d3419be821087acd02123a9248033359"), + H("bbb057038809496bcff86d6fbc8ce5b135a06b166054f2d565be8ace75dc851e" + "0bcdd8f07141c495872fb5d8c0c66a8b6da556663e4e461205d84580bee5bc7e"), + 511, + HL("6846a2f0") + ); + /* Test set 6 #C.2.6 */ + eia2_encrypt( + 0, 0x36af6144, 0x18, HL("6832a65cff4473621ebdd4ba26a921fe"), + H("d3c53839626820717765667620323837636240981ba6824c1bfb1ab485472029" + "b71d808ce33e2cc3c0b5fc1f3de8a6dc"), + 768, + HL("f0668c1e") + ); + /* Test set 7 #C.2.7 */ + eia2_encrypt( + 1, 0x7827fab2, 0x05, HL("5d0a80d8134ae19677824b671e838af4"), + H("70dedf2dc42c5cbd3a96f8a0b11418b3608d5733604a2cd36aabc70ce3193bb5" + "153be2d3c06dfdb2d16e9c357158be6a41d6b861e491db3fbfeb518efcf048d7" + "d58953730ff30c9ec470ffcd663dc34201c36addc0111c35b38afee7cfdb582e" + "3731f8b4baa8d1a89c06e81199a9716227be344efcb436ddd0f096c064c3b5e2" + "c399993fc77394f9e09720a811850ef23b2ee05d9e6173609d86e1c0c18ea51a" + "012a00bb413b9cb8188a703cd6bae31cc67b34b1b00019e6a2b2a690f02671fe" + "7c9ef8dec0094e533763478d58d2c5f5b827a0148c5948a96931acf84f465a64" + "e62ce74007e991e37ea823fa0fb21923b79905b733b631e6c7d6860a3831ac35" + "1a9c730c52ff72d9d308eedbab21fde143a0ea17e23edc1f74cbb3638a2033aa" + "a15464eaa733385dbbeb6fd73509b857e6a419dca1d8907af977fbac4dfa35ec"), + 2558, + HL("f4cc8fa3") + ); +#endif +} diff --git a/openair-cn/TEST/test_secu_knas_stream_int.c b/openair-cn/TEST/test_secu_knas_stream_int.c new file mode 100644 index 0000000000..021af0b4dc --- /dev/null +++ b/openair-cn/TEST/test_secu_knas_stream_int.c @@ -0,0 +1,144 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> + +#include "test_util.h" + +#include "secu_defs.h" + +#define H(x) decode_hex_dup(x) +#define HL(x) decode_hex_dup(x), decode_hex_length(x) + +static void eea2_encrypt(uint8_t direction, uint32_t count, + uint8_t bearer, uint8_t *key, uint32_t key_length, uint8_t *message, + uint32_t length, uint8_t *expected) +{ + nas_stream_cipher_t *nas_cipher; + uint8_t *result; + uint32_t zero_bits = length & 7; + uint32_t byte_length = length >> 3; + + if (zero_bits > 0) + byte_length += 1; + + nas_cipher = calloc(1, sizeof(nas_stream_cipher_t)); + + nas_cipher->direction = direction; + nas_cipher->count = count; + nas_cipher->key = key; + nas_cipher->key_length = key_length; + nas_cipher->bearer = bearer; + nas_cipher->blength = length; + nas_cipher->message = message; + + if (nas_stream_cipher_eea2(nas_cipher, &result) != 0) + fail("Fail: nas_stream_cipher_eea2\n"); + if (compare_buffer(result, byte_length, expected, byte_length) != 0) { + fail("Fail: eea2_encrypt\n"); + } + + free(nas_cipher); + free(result); +} + + +void doit (void) +{ + /* Test suite from 3GPP TS33.401 #Appendix C.1 */ + + /* Test set 1 #C.1.1 */ + eea2_encrypt( + 1, 0x398a59b4, 0x15, HL("d3c5d592327fb11c4035c6680af8c6d1"), + H("981ba6824c1bfb1ab485472029b71d808ce33e2cc3c0b5fc1f3de8a6dc66b1f0"), + 253, + H("e9fed8a63d155304d71df20bf3e82214b20ed7dad2f233dc3c22d7bdeeed8e78") + ); + /* Test set 2 #C.1.2 */ + eea2_encrypt( + 1, 0xc675a64b, 0x0c, HL("2bd6459f82c440e0952c49104805ff48"), + H("7ec61272743bf1614726446a6c38ced166f6ca76eb5430044286346cef130f92" + "922b03450d3a9975e5bd2ea0eb55ad8e1b199e3ec4316020e9a1b285e7627953" + "59b7bdfd39bef4b2484583d5afe082aee638bf5fd5a606193901a08f4ab41aab" + "9b134880"), + 798, + H("5961605353c64bdca15b195e288553a910632506d6200aa790c4c806c99904cf" + "2445cc50bb1cf168a49673734e081b57e324ce5259c0e78d4cd97b870976503c" + "0943f2cb5ae8f052c7b7d392239587b8956086bcab18836042e2e6ce42432a17" + "105c53d0") + ); + /* Test set 3 #C.1.3 */ + eea2_encrypt( + 0, 0x544d49cd, 0x04, HL("0a8b6bd8d9b08b08d64e32d1817777fb"), + H("fd40a41d370a1f65745095687d47ba1d36d2349e23f644392c8ea9c49d40c132" + "71aff264d0f24800"), + 310, + H("75750d37b4bba2a4dedb34235bd68c6645acdaaca48138a3b0c471e2a7041a57" + "6423d2927287f000") + ); + /* Test set 4 #C.1.4 */ + eea2_encrypt( + 1, 0x72d8c671, 0x10, HL("aa1f95aea533bcb32eb63bf52d8f831a"), + H("fb1b96c5c8badfb2e8e8edfde78e57f2ad81e74103fc430a534dcc37afcec70e" + "1517bb06f27219dae49022ddc47a068de4c9496a951a6b09edbdc864c7adbd74" + "0ac50c022f3082bafd22d78197c5d508b977bca13f32e652e74ba728576077ce" + "628c535e87dc6077ba07d29068590c8cb5f1088e082cfa0ec961302d69cf3d44"), + 1022, + H("dfb440acb3773549efc04628aeb8d8156275230bdc690d94b00d8d95f28c4b56" + "307f60f4ca55eba661ebba72ac808fa8c49e26788ed04a5d606cb418de74878b" + "9a22f8ef29590bc4eb57c9faf7c41524a885b8979c423f2f8f8e0592a9879201" + "be7ff9777a162ab810feb324ba74c4c156e04d39097209653ac33e5a5f2d8864") + ); + /* Test set 5 #C.1.5 */ + eea2_encrypt( + 1, 0xc675a64b, 0x0c, HL("9618ae46891f86578eebe90ef7a1202e"), + H("8daa17b1ae050529c6827f28c0ef6a1242e93f8b314fb18a77f790ae049fedd6" + "12267fecaefc450174d76d9f9aa7755a30cd90a9a5874bf48eaf70eea3a62a25" + "0a8b6bd8d9b08b08d64e32d1817777fb544d49cd49720e219dbf8bbed33904e1" + "fd40a41d370a1f65745095687d47ba1d36d2349e23f644392c8ea9c49d40c132" + "71aff264d0f24841d6465f0996ff84e65fc517c53efc3363c38492a8"), + 1245, + H("919c8c33d66789703d05a0d7ce82a2aeac4ee76c0f4da050335e8a84e7897ba5" + "df2f36bd513e3d0c8578c7a0fcf043e03aa3a39fbaad7d15be074faa5d9029f7" + "1fb457b647834714b0e18f117fca10677945096c8c5f326ba8d6095eb29c3e36" + "cf245d1622aafe921f7566c4f5d644f2f1fc0ec684ddb21349747622e209295d" + "27ff3f95623371d49b147c0af486171f22cd04b1cbeb2658223e6938") + ); + /* Test set 6 #C.1.6 */ + eea2_encrypt( + 0, 0xaca4f50f, 0x0b, HL("54f4e2e04c83786eec8fb5abe8e36566"), + H("40981ba6824c1bfb4286b299783daf442c099f7ab0f58d5c8e46b104f08f01b4" + "1ab485472029b71d36bd1a3d90dc3a41b46d51672ac4c9663a2be063da4bc8d2" + "808ce33e2cccbfc634e1b259060876a0fbb5a437ebcc8d31c19e4454318745e3" + "fa16bb11adae248879fe52db2543e53cf445d3d828ce0bf5c560593d97278a59" + "762dd0c2c9cd68d4496a792508614014b13b6aa51128c18cd6a90b87978c2ff1" + "cabe7d9f898a411bfdb84f68f6727b1499cdd30df0443ab4a66653330bcba110" + "5e4cec034c73e605b4310eaaadcfd5b0ca27ffd89d144df4792759427c9cc1f8" + "cd8c87202364b8a687954cb05a8d4e2d99e73db160deb180ad0841e96741a5d5" + "9fe4189f15420026fe4cd12104932fb38f735340438aaf7eca6fd5cfd3a195ce" + "5abe65272af607ada1be65a6b4c9c0693234092c4d018f1756c6db9dc8a6d80b" + "888138616b681262f954d0e7711748780d92291d86299972db741cfa4f37b8b5" + "6cdb18a7ca8218e86e4b4b716a4d04371fbec262fc5ad0b3819b187b97e55b1a" + "4d7c19ee24c8b4d7723cfedf045b8acae4869517d80e50615d9035d5d9c5a40a" + "f602280b542597b0cb18619eeb35925759d195e100e8e4aa0c38a3c2abe0f3d8" + "ff04f3c33c295069c23694b5bbeacdd542e28e8a94edb9119f412d054be1fa72" + "00b09000"), + 3861, + H("5cb72c6edc878f1566e10253afc364c9fa540d914db94cbee275d0917ca6af0d" + "77acb4ef3bbe1a722b2ef5bd1d4b8e2aa5024ec1388a201e7bce7920aec61589" + "5f763a5564dcc4c482a2ee1d8bfecc4498eca83fbb75f9ab530e0dafbede2fa5" + "895b82991b6277c529e0f2529d7f79606be96706296dedfa9d7412b616958cb5" + "63c678c02825c30d0aee77c4c146d2765412421a808d13cec819694c75ad572e" + "9b973d948b81a9337c3b2a17192e22c2069f7ed1162af44cdea817603665e807" + "ce40c8e0dd9d6394dc6e31153fe1955c47afb51f2617ee0c5e3b8ef1ad7574ed" + "343edc2743cc94c990e1f1fd264253c178dea739c0befeebcd9f9b76d49c1015" + "c9fecf50e53b8b5204dbcd3eed863855dabcdcc94b31e318021568855c8b9e52" + "a981957a112827f978ba960f1447911b317b5511fbcc7fb13ac153db74251117" + "e4861eb9e83bffffc4eb7755579038e57924b1f78b3e1ad90bab2a07871b72db" + "5eef96c334044966db0c37cafd1a89e5646a3580eb6465f121dce9cb88d85b96" + "cf23ccccd4280767bee8eeb23d8652461db6493103003baf89f5e18261ea43c8" + "4a92ebffffe4909dc46c5192f825f770600b9602c557b5f8b431a79d45977dd9" + "c41b863da9e142e90020cfd074d6927b7ab3b6725d1a6f3f98b9c9daa8982aff" + "06782800") + ); +} diff --git a/openair-cn/TEST/test_util.c b/openair-cn/TEST/test_util.c new file mode 100644 index 0000000000..1272fb0eaf --- /dev/null +++ b/openair-cn/TEST/test_util.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2004-2012 Free Software Foundation, Inc. + * + * Author: Simon Josefsson + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdarg.h> +#include <ctype.h> + +#include "test_util.h" + +int debug = 0; +int error_count = 0; +int break_on_error = 0; + +/* -1 means invalid */ +static const signed char hex_digits[0x100] = +{ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +void +fail (const char *format, ...) +{ + char str[1024]; + va_list arg_ptr; + + va_start (arg_ptr, format); + vsnprintf ( str, sizeof(str), format, arg_ptr); + va_end (arg_ptr); + fputs(str, stderr); + error_count++; + if (break_on_error) + exit (1); +} + +void +success (const char *format, ...) +{ + char str[1024]; + va_list arg_ptr; + + va_start (arg_ptr, format); + vsnprintf ( str, sizeof(str), format, arg_ptr); + va_end (arg_ptr); + fputs(str, stderr); +} + +void +escapeprint (const char *str, size_t len) +{ + size_t i; + + printf (" (length %d bytes):\n\t", (int) len); + for (i = 0; i < len; i++) + { + if (((str[i] & 0xFF) >= 'A' && (str[i] & 0xFF) <= 'Z') || + ((str[i] & 0xFF) >= 'a' && (str[i] & 0xFF) <= 'z') || + ((str[i] & 0xFF) >= '0' && (str[i] & 0xFF) <= '9') + || (str[i] & 0xFF) == ' ' || (str[i] & 0xFF) == '.') + printf ("%c", (str[i] & 0xFF)); + else + printf ("\\x%02X", (str[i] & 0xFF)); + if ((i + 1) % 16 == 0 && (i + 1) < len) + printf ("'\n\t'"); + } + printf ("\n"); +} + +void +hexprint (const void *_str, size_t len) +{ + size_t i; + const char* str = _str; + + printf ("\t;; "); + for (i = 0; i < len; i++) + { + printf ("%02x ", (str[i] & 0xFF)); + if ((i + 1) % 8 == 0) + printf (" "); + if ((i + 1) % 16 == 0 && i + 1 < len) + printf ("\n\t;; "); + } + printf ("\n"); +} + +void +binprint (const void *_str, size_t len) +{ + size_t i; + const char* str = _str; + + printf ("\t;; "); + for (i = 0; i < len; i++) + { + printf ("%d%d%d%d%d%d%d%d ", + (str[i] & 0xFF) & 0x80 ? 1 : 0, + (str[i] & 0xFF) & 0x40 ? 1 : 0, + (str[i] & 0xFF) & 0x20 ? 1 : 0, + (str[i] & 0xFF) & 0x10 ? 1 : 0, + (str[i] & 0xFF) & 0x08 ? 1 : 0, + (str[i] & 0xFF) & 0x04 ? 1 : 0, + (str[i] & 0xFF) & 0x02 ? 1 : 0, (str[i] & 0xFF) & 0x01 ? 1 : 0); + if ((i + 1) % 3 == 0) + printf (" "); + if ((i + 1) % 6 == 0 && i + 1 < len) + printf ("\n\t;; "); + } + printf ("\n"); +} + +int +compare_buffer(const uint8_t *buffer, const uint32_t length_buffer, + const uint8_t *pattern, const uint32_t length_pattern) +{ + int i; + if (length_buffer != length_pattern) { + printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern, + length_buffer); + hexprint(buffer, length_buffer); + return -1; + } + for (i = 0; i < length_buffer; i++) { + if (pattern[i] != buffer[i]) { + printf("Expecting:\n"); + hexprint(pattern, length_pattern); + printf("Received:\n"); + hexprint(buffer, length_buffer); + printf("Mismatch fount in byte %d\nExpecting 0x%02x, got 0x%02x\n", + i, pattern[i], buffer[i]); + return -1; + } + } + return 0; +} + +unsigned +decode_hex_length(const char *h) +{ + const unsigned char *hex = (const unsigned char *) h; + unsigned count; + unsigned i; + + for (count = i = 0; hex[i]; i++) + { + if (isspace(hex[i])) + continue; + if (hex_digits[hex[i]] < 0) + abort(); + count++; + } + + if (count % 2) + abort(); + return count / 2; +} + +int +decode_hex(uint8_t *dst, const char *h) +{ + const unsigned char *hex = (const unsigned char *) h; + unsigned i = 0; + + for (;;) + { + int high, low; + + while (*hex && isspace(*hex)) + hex++; + + if (!*hex) + return 1; + + high = hex_digits[*hex++]; + if (high < 0) + return 0; + + while (*hex && isspace(*hex)) + hex++; + + if (!*hex) + return 0; + + low = hex_digits[*hex++]; + if (low < 0) + return 0; + + dst[i++] = (high << 4) | low; + } +} + +uint8_t * +decode_hex_dup(const char *hex) +{ + uint8_t *p; + unsigned length = decode_hex_length(hex); + + p = malloc(length * sizeof(uint8_t)); + + if (decode_hex(p, hex)) + return p; + else + { + free(p); + return NULL; + } +} + +int +main (int argc, char *argv[]) +{ + do + if (strcmp (argv[argc - 1], "-v") == 0 || + strcmp (argv[argc - 1], "--verbose") == 0) + debug = 1; + else if (strcmp (argv[argc - 1], "-b") == 0 || + strcmp (argv[argc - 1], "--break-on-error") == 0) + break_on_error = 1; + else if (strcmp (argv[argc - 1], "-h") == 0 || + strcmp (argv[argc - 1], "-?") == 0 || + strcmp (argv[argc - 1], "--help") == 0) + { + printf ("Usage: %s [-vbh?] [--verbose] [--break-on-error] [--help]\n", + argv[0]); + return 1; + } + while (argc-- > 1); + + doit (); + + if (debug || error_count > 0) + printf ("Self test `%s' finished with %d errors\n", argv[0], error_count); + + return error_count ? 1 : 0; +} diff --git a/openair-cn/TEST/test_util.h b/openair-cn/TEST/test_util.h new file mode 100644 index 0000000000..9036680f24 --- /dev/null +++ b/openair-cn/TEST/test_util.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2004-2012 Free Software Foundation, Inc. + * + * Author: Simon Josefsson + * + * This file is part of GnuTLS. + * + * GnuTLS is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * GnuTLS is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GnuTLS; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef TEST_UTIL_H +#define TEST_UTIL_H + +#include <string.h> +#include <stdarg.h> + +#ifndef __attribute__ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +#define __attribute__(Spec) /* empty */ +#endif +#endif + +extern int debug; +extern int error_count; +extern int break_on_error; + +extern void fail (const char *format, ...) + __attribute__ ((format (printf, 1, 2))); +extern void success (const char *format, ...) + __attribute__ ((format (printf, 1, 2))); + +extern void escapeprint (const char *str, size_t len); +extern void hexprint (const void *str, size_t len); +extern void binprint (const void *str, size_t len); + +extern uint8_t * decode_hex_dup(const char *hex); +extern int decode_hex(uint8_t *dst, const char *h); +extern unsigned decode_hex_length(const char *h); + +#define H(x) decode_hex_dup(x) +#define HL(x) decode_hex_dup(x), decode_hex_length(x) + +extern int +compare_buffer(const uint8_t *buffer, const uint32_t length_buffer, + const uint8_t *pattern, const uint32_t length_pattern); + +/* This must be implemented elsewhere. */ +extern void doit (void); + +#endif /* TEST_UTIL_H_ */ diff --git a/openair-cn/UDP/Makefile.am b/openair-cn/UDP/Makefile.am new file mode 100644 index 0000000000..00fe86cbd7 --- /dev/null +++ b/openair-cn/UDP/Makefile.am @@ -0,0 +1,11 @@ +noinst_LTLIBRARIES = libudpserver.la +libudpserver_la_LDFLAGS = -all-static + +AM_CFLAGS = \ + @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE \ + -I$(top_srcdir)/UTILS + +libudpserver_la_SOURCES = \ + udp_primitives_server.h udp_primitives_server.c \ No newline at end of file diff --git a/openair-cn/UDP/Makefile.eNB b/openair-cn/UDP/Makefile.eNB new file mode 100644 index 0000000000..b135ceb476 --- /dev/null +++ b/openair-cn/UDP/Makefile.eNB @@ -0,0 +1,43 @@ +libudp_OBJECTS = \ + udp_primitives_client.o + +-include .deps/*.d + +.PHONY = depdir + +CFLAGS = \ + -I../UTILS \ + -I$(OPENAIR2_DIR) \ + -I$(OPENAIR2_DIR)/COMMON \ + -I$(OPENAIR2_DIR)/GTPV1U \ + -I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/include \ + -I$(OPENAIR2_DIR)/GTPV1U/nw-gtpv1u/shared \ + -I$(OPENAIR2_DIR)/UTIL \ + -DUPDATE_RELEASE_9 \ + -DENB_MODE \ + -DENABLE_USE_MME \ + -DUSER_MODE \ + -O2 \ + -g \ + -Wall \ + -Werror=implicit-function-declaration + +$(libudp_OBJECTS): %.o : %.c + @echo "Compiling $<" + @$(CC) -c $(CFLAGS) -o $@ $< + @if ! test -d ".deps/" ; then mkdir -p .deps; fi + @$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d + @mv -f .deps/$*.d .deps/$*.d.tmp + @sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d + @sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d + @rm -f .deps/$*.d.tmp + +libudp.a: $(libudp_OBJECTS) + @echo Creating UDP archive + @$(AR) rcvs $@ $(libudp_OBJECTS) + +clean: + rm -f $(libudp_OBJECTS) + rm -rf .deps/ + rm -f libudp.a \ No newline at end of file diff --git a/openair-cn/UDP/udp_primitives_client.c b/openair-cn/UDP/udp_primitives_client.c new file mode 100644 index 0000000000..89846468b0 --- /dev/null +++ b/openair-cn/UDP/udp_primitives_client.c @@ -0,0 +1,161 @@ +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> + +#include <sys/types.h> +#include <sys/socket.h> + +#include <netinet/in.h> + +#include <arpa/inet.h> + +#include "udp_primitives_client.h" + +#include "UTIL/LOG/log.h" + +#define IPV4_ADDR "%u.%u.%u.%u" +#define IPV4_ADDR_FORMAT(aDDRESS) \ + (uint8_t)((aDDRESS) & 0x000000ff), \ + (uint8_t)(((aDDRESS) & 0x0000ff00) >> 8 ), \ + (uint8_t)(((aDDRESS) & 0x00ff0000) >> 16), \ + (uint8_t)(((aDDRESS) & 0xff000000) >> 24) + +static void *udp_recv_thread(void *arg_p); + +int udp_create_connection(char *ip_addr, uint16_t port, + udp_data_t *udp_data_p, + udp_recv_callback recv_callback, + void *arg_p) +{ + + udp_data_t *udp_desc; + int sd; + struct sockaddr_in sin; + + LOG_I(UDP, "Initializing UDP for local address %s with port %d\n", + ip_addr, port); + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) <= 0) { + LOG_E(UDP, "Failed to create new socket: (%s:%d)\n", + strerror(errno), errno); + return -1; + } + + memset(&sin, 0, sizeof(struct sockaddr_in)); + + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + if (ip_addr == NULL) { + sin.sin_addr.s_addr = inet_addr(INADDR_ANY); + } else { + sin.sin_addr.s_addr = inet_addr(ip_addr); + } + + if (bind(sd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)) < 0) { + LOG_E(UDP, "Failed to bind socket: (%s:%d)\n", + strerror(errno), errno); + close(sd); + return -1; + } + + /* Create a new descriptor for this connection */ + udp_desc = malloc(sizeof(udp_data_t)); + memset(udp_desc, 0, sizeof(udp_data_t)); + + udp_desc->sd = sd; + udp_desc->recv_callback = recv_callback; + udp_desc->arg_p = arg_p; + + memcpy(udp_data_p, udp_desc, sizeof(udp_data_t)); + + if (pthread_create(&udp_desc->recv_thread, NULL, udp_recv_thread, + (void *)udp_desc) < 0) { + LOG_E(UDP, "Failed to create new thread: (%s:%d)\n", + strerror(errno), errno); + close(sd); + free(udp_desc); + return -1; + } + + LOG_I(UDP, "Initializing UDP for local address %s with port %d: DONE\n", + ip_addr, port); + + return sd; +} + +int udp_send_to(int sd, uint16_t port, uint32_t address, const uint8_t *buffer, + uint32_t length) +{ + struct sockaddr_in to; + socklen_t to_length; + + if (sd <= 0 || ((buffer == NULL) && (length > 0))) { + LOG_E(UDP, "udp_send_to: bad param\n"); + return -1; + } + + memset(&to, 0, sizeof(struct sockaddr_in)); + to_length = sizeof(to); + + to.sin_family = AF_INET; + to.sin_port = htons(port); + to.sin_addr.s_addr = address; + + if (sendto(sd, (void *)buffer, (size_t)length, 0, (struct sockaddr *)&to, + to_length) < 0) { + LOG_E(UDP, + "[SD %d] Failed to send data to "IPV4_ADDR" on port %d, buffer size %u\n", + sd, IPV4_ADDR_FORMAT(address), port, length); + return -1; + } + LOG_I(UDP, "[SD %d] Successfully sent to "IPV4_ADDR + " on port %d, buffer size %u, buffer address %x\n", + sd, IPV4_ADDR_FORMAT(address), port, length, buffer); + return 0; +} + +static void *udp_recv_thread(void *arg_p) +{ + udp_data_t *udp_desc; + udp_desc = (udp_data_t *)arg_p; + uint8_t buffer[4096]; + + LOG_D(UDP, "Starting receiver thread\n"); + + while(1) { + int n; + + struct sockaddr_in from; + socklen_t from_len; + + n = recvfrom(udp_desc->sd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&from, &from_len); + + if (n < 0) { + LOG_E(UDP, "Recvfrom failed: (%s:%d)\n", + strerror(errno), errno); + } else if (n == 0) { + LOG_I(UDP, "Peer %s on port %d has performed a shutdown\n", + inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + break; + } else { + /* Normal read, notify the upper layer of incoming data */ + LOG_D(UDP, "Received UDP message of length %u from %s:%u\n", + n, inet_ntoa(from.sin_addr), ntohs(from.sin_port)); + if (udp_desc->recv_callback) { + udp_desc->recv_callback(from.sin_port, from.sin_addr.s_addr, buffer, n, + udp_desc->arg_p); + } else { + LOG_W(UDP, "No recv callback associated to this socket (%d), exiting\n", + udp_desc->sd); + break; + } + } + } + LOG_I(UDP, "Receiver thread exiting\n"); + free(udp_desc); + return NULL; +} diff --git a/openair-cn/UDP/udp_primitives_client.h b/openair-cn/UDP/udp_primitives_client.h new file mode 100644 index 0000000000..91e5e374d6 --- /dev/null +++ b/openair-cn/UDP/udp_primitives_client.h @@ -0,0 +1,54 @@ +#include <pthread.h> +#include <stdint.h> + +#ifndef UDP_PRIMITIVES_CLIENT_H_ +#define UDP_PRIMITIVES_CLIENT_H_ + +/** \brief UDP recv callback prototype. Will be called every time a payload is + * received on socket. + * \param port Port on which data had been received + * \param address Sender Ipv4 address + * \param buffer Pointer to data (should be freed by user) + * \param length Length of message received + * \param arg_p User provided argument (transparent for wrappers) + * @returns Execution result + */ +typedef int (*udp_recv_callback)(uint16_t port, + uint32_t address, + uint8_t *buffer, + uint32_t length, + void *arg_p); + +typedef struct { + udp_recv_callback recv_callback; + pthread_t recv_thread; + int sd; + void *arg_p; +} udp_data_t; + +/** \brief Create new datagram connection-less socket and create new thread + * for data in downstream. + * \param ip_addr Local IPv4 address to use + * \param port Local port to use + * \param udp_data_p + * \param recv_callback Pointer to data (should be freed by user) + * \param arg_p Optionnal argument to pass to recv_callback + * @returns < 0 on failure or socket descriptor on success + */ +int udp_create_connection(char *ip_addr, uint16_t port, + udp_data_t *udp_data_p, + udp_recv_callback recv_callback, + void *arg_p); + +/** \brief Send buffer to remote peer. + * \param sd socket descriptor to use + * \param port remote port + * \param address remote address + * \param buffer Data buffer to send + * \param length Buffer length + * @returns < 0 on failure or socket descriptor on success + */ +int udp_send_to(int sd, uint16_t port, uint32_t address, + const uint8_t *buffer, uint32_t length); + +#endif /* UDP_PRIMITIVES_CLIENT_H_ */ diff --git a/openair-cn/UDP/udp_primitives_server.c b/openair-cn/UDP/udp_primitives_server.c new file mode 100644 index 0000000000..57d80c58fe --- /dev/null +++ b/openair-cn/UDP/udp_primitives_server.c @@ -0,0 +1,286 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <pthread.h> + +#include "intertask_interface.h" +#include "udp_primitives_server.h" + +#include "assertions.h" +#include "conversions.h" + +#define UDP_DEBUG(x, args...) do { fprintf(stdout, "[UDP] [D]"x, ##args); } while(0) +#define UDP_ERROR(x, args...) do { fprintf(stderr, "[UDP] [E]"x, ##args); } while(0) + +void *udp_receiver_thread(void *args_p); + +struct udp_socket_desc_s { + int sd; /* Socket descriptor to use */ + + pthread_t listener_thread; /* Thread affected to recv */ + + char *local_address; /* Local ipv4 address to use */ + uint16_t local_port; /* Local port to use */ + + task_id_t task_id; /* Task who has requested the new endpoint */ + + STAILQ_ENTRY(udp_socket_desc_s) entries; +}; + +static STAILQ_HEAD(udp_socket_list_s, udp_socket_desc_s) udp_socket_list; +static pthread_mutex_t udp_socket_list_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* @brief Retrieve the descriptor associated with the task_id + */ +static +struct udp_socket_desc_s *udp_get_socket_desc(task_id_t task_id) +{ + struct udp_socket_desc_s *udp_sock_p = NULL; + + UDP_DEBUG("Looking for task %d\n", task_id); + + STAILQ_FOREACH(udp_sock_p, &udp_socket_list, entries) { + if (udp_sock_p->task_id == task_id) { + UDP_DEBUG("Found matching task desc\n"); + break; + } + } + return udp_sock_p; +} + +static +int udp_create_socket(int port, char *address, task_id_t task_id) +{ + struct sockaddr_in addr; + int sd; + + struct udp_socket_desc_s *thread_arg = NULL; + + UDP_DEBUG("Creating new listen socket on address "IPV4_ADDR" and port %u\n", + IPV4_ADDR_FORMAT(inet_addr(address)), port); + + /* Create UDP socket */ + if ((sd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { + /* Socket creation has failed... */ + UDP_ERROR("Socket creation failed (%s)\n", strerror(errno)); + return sd; + } + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + addr.sin_addr.s_addr = inet_addr(address); + if (bind(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in)) < 0) { + /* Bind failed */ + UDP_ERROR("Socket bind failed (%s) for address "IPV4_ADDR" and port %u\n", + strerror(errno), IPV4_ADDR_FORMAT(inet_addr(address)), port); + close(sd); + return -1; + } + + thread_arg = calloc(1, sizeof(struct udp_socket_desc_s)); + + DevAssert(thread_arg != NULL); + + thread_arg->sd = sd; + thread_arg->local_address = address; + thread_arg->local_port = port; + thread_arg->task_id = task_id; + + if (pthread_create(&thread_arg->listener_thread, NULL, + &udp_receiver_thread, (void *)thread_arg) < 0) { + UDP_ERROR("Pthred_create failed (%s)\n", strerror(errno)); + return -1; + } + return sd; +} + +void *udp_receiver_thread(void *arg_p) +{ + uint8_t buffer[1024]; + + struct udp_socket_desc_s *udp_sock_p = (struct udp_socket_desc_s *)arg_p; + + UDP_DEBUG("Inserting new descriptor for task %d, sd %d\n", + udp_sock_p->task_id, udp_sock_p->sd); + pthread_mutex_lock(&udp_socket_list_mutex); + STAILQ_INSERT_TAIL(&udp_socket_list, udp_sock_p, entries); + pthread_mutex_unlock(&udp_socket_list_mutex); + + while (1) { + int n; + socklen_t from_len; + struct sockaddr_in addr; + + from_len = (socklen_t)sizeof(struct sockaddr_in); + + if ((n = recvfrom(udp_sock_p->sd, buffer, sizeof(buffer), 0, + (struct sockaddr *)&addr, &from_len)) < 0) { + UDP_ERROR("Recvfrom failed %s\n", strerror(errno)); + break; + } else { + MessageDef *message_p = NULL; + udp_data_ind_t *udp_data_ind_p; + uint8_t *forwarded_buffer = NULL; + + forwarded_buffer = calloc(n, sizeof(uint8_t)); + + memcpy(forwarded_buffer, buffer, n); + + message_p = alloc_new_message(TASK_UDP, UDP_DATA_IND); + + DevAssert(message_p != NULL); + + udp_data_ind_p = &message_p->msg.udp_data_ind; + + udp_data_ind_p->buffer = forwarded_buffer; + udp_data_ind_p->buffer_length = n; + udp_data_ind_p->peer_port = htons(addr.sin_port); + udp_data_ind_p->peer_address = addr.sin_addr.s_addr; + + UDP_DEBUG("Msg of length %d received from %s:%u\n", + n, inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); + if (send_msg_to_task(udp_sock_p->task_id, INSTANCE_DEFAULT, message_p) < 0) { + UDP_DEBUG("Failed to send message %d to task %d\n", + UDP_DATA_IND, udp_sock_p->task_id); + break; + } + } + } + close(udp_sock_p->sd); + udp_sock_p->sd = -1; + + pthread_mutex_lock(&udp_socket_list_mutex); + STAILQ_REMOVE(&udp_socket_list, udp_sock_p, udp_socket_desc_s, entries); + pthread_mutex_unlock(&udp_socket_list_mutex); + + return NULL; +} + +static void *udp_intertask_interface(void *args_p) +{ + intertask_interface_mark_task_ready(TASK_UDP); + while(1) { + MessageDef *received_message_p = NULL; + receive_msg(TASK_UDP, &received_message_p); + DevAssert(received_message_p != NULL); + + switch (received_message_p->header.messageId) { + case UDP_INIT: { + udp_init_t *udp_init_p; + udp_init_p = &received_message_p->msg.udp_init; + udp_create_socket(udp_init_p->port, udp_init_p->address, + received_message_p->header.originTaskId); + } break; + case UDP_DATA_REQ: { + int udp_sd = -1; + ssize_t bytes_written; + + struct udp_socket_desc_s *udp_sock_p = NULL; + udp_data_req_t *udp_data_req_p; + struct sockaddr_in peer_addr; + + udp_data_req_p = &received_message_p->msg.udp_data_req; + + memset(&peer_addr, 0, sizeof(struct sockaddr_in)); + + peer_addr.sin_family = AF_INET; + peer_addr.sin_port = htons(udp_data_req_p->peer_port); + peer_addr.sin_addr.s_addr = udp_data_req_p->peer_address; + + pthread_mutex_lock(&udp_socket_list_mutex); + udp_sock_p = udp_get_socket_desc(received_message_p->header.originTaskId); + + if (udp_sock_p == NULL) { + UDP_ERROR("Failed to retrieve the udp socket descriptor " + "associated with task %d\n", received_message_p->header.originTaskId); + pthread_mutex_unlock(&udp_socket_list_mutex); + if (udp_data_req_p->buffer) { + free(udp_data_req_p->buffer); + } + goto on_error; + } + udp_sd = udp_sock_p->sd; + pthread_mutex_unlock(&udp_socket_list_mutex); + + UDP_DEBUG("[%d] Sending message of size %u to "IPV4_ADDR" and port %u\n", + udp_sd, udp_data_req_p->buffer_length, + IPV4_ADDR_FORMAT(udp_data_req_p->peer_address), + udp_data_req_p->peer_port); + + bytes_written = sendto(udp_sd, udp_data_req_p->buffer, + udp_data_req_p->buffer_length, 0, + (struct sockaddr *)&peer_addr, + sizeof(struct sockaddr_in)); + + if (bytes_written != udp_data_req_p->buffer_length) { + UDP_ERROR("There was an error while writing to socket " + "(%d:%s)\n", errno, strerror(errno)); + } + } break; + case MESSAGE_TEST: { + } break; + default: { + UDP_DEBUG("Unkwnon message ID %s:%d\n", + get_message_name(received_message_p->header.messageId), + received_message_p->header.messageId); + } break; + } +on_error: + free(received_message_p); + received_message_p = NULL; + } + return NULL; +} + +int udp_init(const mme_config_t *mme_config_p) +{ + UDP_DEBUG("Initializing UDP task interface\n"); + + STAILQ_INIT(&udp_socket_list); + + if (intertask_interface_create_task(TASK_UDP, &udp_intertask_interface, + NULL) < 0) { + UDP_ERROR("udp pthread_create (%s)\n", strerror(errno)); + return -1; + } + UDP_DEBUG("Initializing UDP task interface: DONE\n"); + return 0; +} diff --git a/openair-cn/UDP/udp_primitives_server.h b/openair-cn/UDP/udp_primitives_server.h new file mode 100644 index 0000000000..a75f25287b --- /dev/null +++ b/openair-cn/UDP/udp_primitives_server.h @@ -0,0 +1,41 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "mme_config.h" + +#ifndef UDP_PRIMITIVES_SERVER_H_ +#define UDP_PRIMITIVES_SERVER_H_ + +/** \brief UDP task init function. + @returns -1 on error, 0 otherwise. + **/ +int udp_init(const mme_config_t *mme_config); + +#endif /* UDP_PRIMITIVES_SERVER_H_ */ diff --git a/openair-cn/UTILS/CONF/enb_default.conf b/openair-cn/UTILS/CONF/enb_default.conf new file mode 100755 index 0000000000..679f5616b1 --- /dev/null +++ b/openair-cn/UTILS/CONF/enb_default.conf @@ -0,0 +1,12 @@ +# ------- Interfaces definitions +ENB_INTERFACE_NAME_FOR_S1_MME = "eth0"; +ENB_IP_ADDRESS_FOR_S1_MME = "192.168.12.30"; +ENB_IP_NETMASK_FOR_S1_MME = 24; + +ENB_INTERFACE_NAME_FOR_S1U = "eth2"; +ENB_IP_ADDRESS_FOR_S1U = "192.168.14.30"; +ENB_IP_NETMASK_FOR_S1U = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.12.175"; +MME_IP_NETMASK_FOR_S1_MME = 24; diff --git a/openair-cn/UTILS/CONF/enb_orcus.conf b/openair-cn/UTILS/CONF/enb_orcus.conf new file mode 100644 index 0000000000..cb362cfdea --- /dev/null +++ b/openair-cn/UTILS/CONF/enb_orcus.conf @@ -0,0 +1,12 @@ +# ------- Interfaces definitions +ENB_INTERFACE_NAME_FOR_S1_MME = "eth2"; +ENB_IP_ADDRESS_FOR_S1_MME = "192.168.14.30"; +ENB_IP_NETMASK_FOR_S1_MME = 24; + +ENB_INTERFACE_NAME_FOR_S1U = "eth2"; +ENB_IP_ADDRESS_FOR_S1U = "192.168.14.30"; +ENB_IP_NETMASK_FOR_S1U = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.14.162"; +MME_IP_NETMASK_FOR_S1_MME = 24; diff --git a/openair-cn/UTILS/CONF/epc_nord.conf b/openair-cn/UTILS/CONF/epc_nord.conf new file mode 100644 index 0000000000..fc0130215d --- /dev/null +++ b/openair-cn/UTILS/CONF/epc_nord.conf @@ -0,0 +1,73 @@ +S6A_CONF = "../objs/UTILS/CONF/s6a.conf"; + +REALM = "eur"; + +# Define the limits of the system in terms of served eNB and served UE. +# When the limits will be reached, overload procedure will take place. + +MAXENB = 10; +MAXUE = 100; + +RELATIVE_CAPACITY = 10; + +# Display statistics about whole system (expressed in seconds) +MME_STATISTIC_TIMER = 10; + +# max queue size per task +ITTI_QUEUE_SIZE = 2000000; + +# ------- SCTP definitions +# Number of streams to use in input/output + +SCTP_INSTREAMS = 32; +SCTP_OUTSTREAMS = 32; + +# ------- S1AP definitions + +# outcome drop timer value (seconds) +S1AP_OUTCOME_TIMER = 10; + +# ------- MME served GUMMEI +# MME code DEFAULT = 0 +# size = 8 bits +# maximum of 256 values, comma separated +MME_CODE = 30,56,1,8; + +# MME GROUP ID DEFAULT = 0 +# size = 16 bits +# maximum of 65535 values, comma separated +MME_GID = 3,4,5,30,8,9,50021; + +# TA (mcc.mnc:tracking area code) DEFAULT = 208.34:0 +# max values = 999.999:65535 +# maximum of 32 values, comma separated +PLMN = 208.38:0,209.130:4,208.35:8; + +# ------- Interfaces definitions +SGW_INTERFACE_NAME_FOR_S11 = "eth0"; +SGW_IP_ADDRESS_FOR_S11 = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S11 = 24; + +SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP = "eth0"; +SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S1U_S12_S4_UP = 24; + +SGW_INTERFACE_NAME_FOR_S5_S8_UP = "upsgw1"; +SGW_IP_ADDRESS_FOR_S5_S8_UP = "192.168.5.2"; +SGW_IP_NETMASK_FOR_S5_S8_UP = 24; + +PGW_INTERFACE_NAME_FOR_S5_S8 = "uppgw0"; +PGW_IP_ADDRESS_FOR_S5_S8 = "192.168.5.1"; +PGW_IP_NETMASK_FOR_S5_S8 = 24; + +PGW_INTERFACE_NAME_FOR_SGI = "eth0"; +PGW_IP_ADDR_FOR_SGI = "192.168.14.162"; +PGW_IP_NETMASK_FOR_SGI = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.12.30"; +MME_IP_NETMASK_FOR_S1_MME = 24; + +MME_INTERFACE_NAME_FOR_S11_MME = "eth2"; +MME_IP_ADDRESS_FOR_S11_MME = "192.168.14.30"; +MME_IP_NETMASK_FOR_S11_MME = 24; diff --git a/openair-cn/UTILS/CONF/epc_orcus.conf b/openair-cn/UTILS/CONF/epc_orcus.conf new file mode 100644 index 0000000000..8b3a860688 --- /dev/null +++ b/openair-cn/UTILS/CONF/epc_orcus.conf @@ -0,0 +1,73 @@ +S6A_CONF = "../objs/UTILS/CONF/s6a.conf"; + +REALM = "eur"; + +# Define the limits of the system in terms of served eNB and served UE. +# When the limits will be reached, overload procedure will take place. + +MAXENB = 10; +MAXUE = 100; + +RELATIVE_CAPACITY = 10; + +# Display statistics about whole system (expressed in seconds) +MME_STATISTIC_TIMER = 10; + +# max queue size per task +ITTI_QUEUE_SIZE = 2000000; + +# ------- SCTP definitions +# Number of streams to use in input/output + +SCTP_INSTREAMS = 32; +SCTP_OUTSTREAMS = 32; + +# ------- S1AP definitions + +# outcome drop timer value (seconds) +S1AP_OUTCOME_TIMER = 10; + +# ------- MME served GUMMEI +# MME code DEFAULT = 0 +# size = 8 bits +# maximum of 256 values, comma separated +MME_CODE = 30,56,1,8; + +# MME GROUP ID DEFAULT = 0 +# size = 16 bits +# maximum of 65535 values, comma separated +MME_GID = 3,4,5,30,8,9,50021; + +# TA (mcc.mnc:tracking area code) DEFAULT = 208.34:0 +# max values = 999.999:65535 +# maximum of 32 values, comma separated +PLMN = 208.38:0,209.130:4,208.35:8; + +# ------- Interfaces definitions +SGW_INTERFACE_NAME_FOR_S11 = "eth0"; +SGW_IP_ADDRESS_FOR_S11 = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S11 = 24; + +SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP = "eth0"; +SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S1U_S12_S4_UP = 24; + +SGW_INTERFACE_NAME_FOR_S5_S8_UP = "upsgw1"; +SGW_IP_ADDRESS_FOR_S5_S8_UP = "192.168.5.2"; +SGW_IP_NETMASK_FOR_S5_S8_UP = 24; + +PGW_INTERFACE_NAME_FOR_S5_S8 = "uppgw0"; +PGW_IP_ADDRESS_FOR_S5_S8 = "192.168.5.1"; +PGW_IP_NETMASK_FOR_S5_S8 = 24; + +PGW_INTERFACE_NAME_FOR_SGI = "eth0"; +PGW_IP_ADDR_FOR_SGI = "192.168.14.162"; +PGW_IP_NETMASK_FOR_SGI = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.14.162"; +MME_IP_NETMASK_FOR_S1_MME = 24; + +MME_INTERFACE_NAME_FOR_S11_MME = "eth0"; +MME_IP_ADDRESS_FOR_S11_MME = "192.168.14.162"; +MME_IP_NETMASK_FOR_S11_MME = 24; diff --git a/openair-cn/UTILS/CONF/mme_default.conf b/openair-cn/UTILS/CONF/mme_default.conf new file mode 100644 index 0000000000..807b304be8 --- /dev/null +++ b/openair-cn/UTILS/CONF/mme_default.conf @@ -0,0 +1,73 @@ +S6A_CONF = "../objs/UTILS/CONF/s6a.conf"; + +REALM = "eur"; + +# Define the limits of the system in terms of served eNB and served UE. +# When the limits will be reached, overload procedure will take place. + +MAXENB = 10; +MAXUE = 100; + +RELATIVE_CAPACITY = 10; + +# Display statistics about whole system (expressed in seconds) +MME_STATISTIC_TIMER = 10; + +# max queue size per task +ITTI_QUEUE_SIZE = 2000000; + +# ------- SCTP definitions +# Number of streams to use in input/output + +SCTP_INSTREAMS = 32; +SCTP_OUTSTREAMS = 32; + +# ------- S1AP definitions + +# outcome drop timer value (seconds) +S1AP_OUTCOME_TIMER = 10; + +# ------- MME served GUMMEI +# MME code DEFAULT = 0 +# size = 8 bits +# maximum of 256 values, comma separated +MME_CODE = 30,56,1,8; + +# MME GROUP ID DEFAULT = 0 +# size = 16 bits +# maximum of 65535 values, comma separated +MME_GID = 3,4,5,30,8,9,50021; + +# TA (mcc.mnc:tracking area code) DEFAULT = 208.34:0 +# max values = 999.999:65535 +# maximum of 32 values, comma separated +PLMN = 208.38:0,209.130:4,208.35:8; + +# ------- Interfaces definitions +SGW_INTERFACE_NAME_FOR_S11 = "eth0"; +SGW_IP_ADDRESS_FOR_S11 = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S11 = 24; + +SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP = "eth0"; +SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP = "192.168.14.162"; +SGW_IP_NETMASK_FOR_S1U_S12_S4_UP = 24; + +SGW_INTERFACE_NAME_FOR_S5_S8_UP = "upsgw1"; +SGW_IP_ADDRESS_FOR_S5_S8_UP = "192.168.5.2"; +SGW_IP_NETMASK_FOR_S5_S8_UP = 24; + +PGW_INTERFACE_NAME_FOR_S5_S8 = "uppgw0"; +PGW_IP_ADDRESS_FOR_S5_S8 = "192.168.5.1"; +PGW_IP_NETMASK_FOR_S5_S8 = 24; + +PGW_INTERFACE_NAME_FOR_SGI = "eth0"; +PGW_IP_ADDR_FOR_SGI = "192.168.14.162"; +PGW_IP_NETMASK_FOR_SGI = 24; + +MME_INTERFACE_NAME_FOR_S1_MME = "eth0"; +MME_IP_ADDRESS_FOR_S1_MME = "192.168.12.175"; +MME_IP_NETMASK_FOR_S1_MME = 24; + +MME_INTERFACE_NAME_FOR_S11_MME = "eth0"; +MME_IP_ADDRESS_FOR_S11_MME = "192.168.12.175"; +MME_IP_NETMASK_FOR_S11_MME = 24; diff --git a/openair-cn/UTILS/CONF/s6a.conf.in b/openair-cn/UTILS/CONF/s6a.conf.in new file mode 100644 index 0000000000..cc092dfabc --- /dev/null +++ b/openair-cn/UTILS/CONF/s6a.conf.in @@ -0,0 +1,61 @@ +# -------- Local --------- + +# Uncomment if the framework cannot resolv it. +Identity = "@HOSTNAME@.eur"; +Realm = "eur"; + +# TLS configuration (see previous section) +TLS_Cred = "/usr/local/etc/freeDiameter/user.cert.pem", + "/usr/local/etc/freeDiameter/user.key.pem"; +TLS_CA = "/usr/local/etc/freeDiameter/cacert.pem"; + +# Disable use of TCP protocol (only listen and connect in SCTP) +# Default : TCP enabled +No_TCP; +#No_SCTP; + +# Limit the number of SCTP streams +SCTP_streams = 15; + +NoRelay; +TLS_old_method; +AppServThreads = 1; + +# -------- Extensions --------- + +# Uncomment (and create rtd.conf) to specify routing table for this peer. +#LoadExtension = "rt_default.fdx" : "rtd.conf"; + +# Uncomment (and create acl.conf) to allow incoming connections from other peers. +#LoadExtension = "acl_wl.fdx" : "acl.conf"; + +# Uncomment to display periodic state information +#LoadExtension = "dbg_monitor.fdx"; + +# Uncomment to enable an interactive Python interpreter session. +# (see doc/dbg_interactive.py.sample for more information) +#LoadExtension = "dbg_interactive.fdx"; + +# Load the RFC4005 dictionary objects +#LoadExtension = "dict_nasreq.fdx"; + +LoadExtension = "dict_nas_mipv6.fdx"; +LoadExtension = "dict_s6a.fdx"; + +# Load RFC4072 dictionary objects +#LoadExtension = "dict_eap.fdx"; + +# Load the Diameter EAP server extension (requires diameap.conf) +#LoadExtension = "app_diameap.fdx" : "diameap.conf"; + +# Load the Accounting Server extension (requires app_acct.conf) +#LoadExtension = "app_acct.fdx" : "app_acct.conf"; + +# -------- Peers --------- + +# The framework will actively attempt to establish and maintain a connection +# with the peers listed here. +# For only accepting incoming connections, see the acl_wl.fx extension. + +# ConnectPeer = "hss.test.fr" { ConnectTo = "192.168.56.101"; No_IPv6; No_TCP; Port = 3868; Realm = "test.fr"; }; +# ConnectPeer = "hss.test.fr" { ConnectTo = "192.168.56.1"; No_TLS; }; diff --git a/openair-cn/UTILS/HASHTABLE/Makefile.am b/openair-cn/UTILS/HASHTABLE/Makefile.am new file mode 100755 index 0000000000..0aae3786d0 --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/Makefile.am @@ -0,0 +1,9 @@ +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON + +noinst_LTLIBRARIES = libhashtable.la +libhashtable_la_LDFLAGS = -all-static +libhashtable_la_SOURCES = \ + hashtable.c hashtable.h \ + obj_hashtable.c obj_hashtable.h + \ No newline at end of file diff --git a/openair-cn/UTILS/HASHTABLE/Makefile.eNB b/openair-cn/UTILS/HASHTABLE/Makefile.eNB new file mode 100755 index 0000000000..dec659563a --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/Makefile.eNB @@ -0,0 +1,34 @@ +all: libhashtable.a + +libhashtable_OBJECTS = \ + hashtable.o \ + obj_hashtable.o \ + + +CFLAGS = \ + -DUSER_MODE \ + -DENABLE_USE_MME \ + -g \ + -O2 \ + -Wall \ + -Werror=implicit-function-declaration + +-include .deps/*.d + +$(libhashtable_OBJECTS): %.o : %.c + $(CC) -c $(CFLAGS) -o $@ $< + @if ! test -d ".deps" ; then mkdir -p .deps/; fi + @$(CC) -MM $(CFLAGS) $*.c > .deps/$*.d + @mv -f .deps/$*.d .deps/$*.d.tmp + @sed -e 's|.*:|$*.o:|' < .deps/$*.d.tmp > .deps/$*.d + @sed -e 's/.*://' -e 's/\\$$//' < .deps/$*.d.tmp | fmt -1 | \ + sed -e 's/^ *//' -e 's/$$/:/' >> .deps/$*.d + @rm -f .deps/$*.d.tmp + +libhashtable.a: $(libhashtable_OBJECTS) + $(AR) rcvs $@ $(libhashtable_OBJECTS) + +clean: + rm -f libhashtable.a + rm -rf .deps/ + rm -f $(libhashtable_OBJECTS) \ No newline at end of file diff --git a/openair-cn/UTILS/HASHTABLE/hashtable.c b/openair-cn/UTILS/HASHTABLE/hashtable.c new file mode 100755 index 0000000000..85207852df --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/hashtable.c @@ -0,0 +1,280 @@ +/* from: http://en.literateprograms.org/Hash_table_%28C%29#chunk%20def:node + * + */ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "hashtable.h" + + +//------------------------------------------------------------------------------------------------------------------------------- +char* hashtble_rc_code2string(hashtbl_rc_t rcP) +//------------------------------------------------------------------------------------------------------------------------------- +{ + switch (rcP) { + case HASH_TABLE_OK: return "HASH_TABLE_OK";break; + case HASH_TABLE_INSERT_OVERWRITTEN_DATA: return "HASH_TABLE_INSERT_OVERWRITTEN_DATA";break; + case HASH_TABLE_KEY_NOT_EXISTS: return "HASH_TABLE_KEY_NOT_EXISTS";break; + case HASH_TABLE_KEY_ALREADY_EXISTS: return "HASH_TABLE_KEY_ALREADY_EXISTS";break; + case HASH_TABLE_BAD_PARAMETER_HASHTABLE: return "HASH_TABLE_BAD_PARAMETER_HASHTABLE";break; + default: return "UNKNOWN hashtbl_rc_t"; + + } + +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Default hash function + * def_hashfunc() is the default used by hashtbl_create() when the user didn't specify one. + * This is a simple/naive hash function which adds the key's ASCII char values. It will probably generate lots of collisions on large hash tables. + */ + +static hash_size_t def_hashfunc(const uint64_t keyP) +{ + return (hash_size_t)keyP; +} + +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Initialisation + * hashtbl_create() sets up the initial structure of the hash table. The user specified size will be allocated and initialized to NULL. + * The user can also specify a hash function. If the hashfunc argument is NULL, a default hash function is used. + * If an error occurred, NULL is returned. All other values in the returned hash_table_t pointer should be released with hashtbl_destroy(). + */ +hash_table_t *hashtbl_create(hash_size_t sizeP, hash_size_t (*hashfuncP)(const uint64_t ), void (*freefuncP)(void*)) +{ + hash_table_t *hashtbl; + + if(!(hashtbl=malloc(sizeof(hash_table_t)))) return NULL; + + if(!(hashtbl->nodes=calloc(sizeP, sizeof(hash_node_t*)))) { + free(hashtbl); + return NULL; + } + + hashtbl->size=sizeP; + + if(hashfuncP) hashtbl->hashfunc=hashfuncP; + else hashtbl->hashfunc=def_hashfunc; + + if(freefuncP) hashtbl->freefunc=freefuncP; + else hashtbl->freefunc=free; + + return hashtbl; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Cleanup + * The hashtbl_destroy() walks through the linked lists for each possible hash value, and releases the elements. It also releases the nodes array and the hash_table_t. + */ +hashtbl_rc_t hashtbl_destroy(hash_table_t *hashtblP) +{ + hash_size_t n; + hash_node_t *node, *oldnode; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + + for(n=0; n<hashtblP->size; ++n) { + node=hashtblP->nodes[n]; + while(node) { + oldnode=node; + node=node->next; + if (oldnode->data) { + hashtblP->freefunc(oldnode->data); + } + free(oldnode); + } + } + free(hashtblP->nodes); + free(hashtblP); + return HASH_TABLE_OK; +} +//------------------------------------------------------------------------------------------------------------------------------- +hashtbl_rc_t hashtbl_is_key_exists (hash_table_t *hashtblP, const uint64_t keyP) +//------------------------------------------------------------------------------------------------------------------------------- +{ + hash_node_t *node; + hash_size_t hash; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + + hash=hashtblP->hashfunc(keyP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + return HASH_TABLE_OK; + } + node=node->next; + } + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +hashtbl_rc_t hashtbl_apply_funct_on_elements (hash_table_t *hashtblP, void functP(uint64_t keyP, void* dataP, void* parameterP), void* parameterP) +//------------------------------------------------------------------------------------------------------------------------------- +{ + hash_node_t *node = NULL; + unsigned int i = 0; + unsigned int num_elements = 0; + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + while ((num_elements < hashtblP->num_elements) && (i < hashtblP->size)) { + if (hashtblP->nodes[i] != NULL) { + node=hashtblP->nodes[i]; + while(node) { + num_elements += 1; + functP(node->key, node->data, parameterP); + node=node->next; + } + } + i += 1; + } + return HASH_TABLE_OK; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Adding a new element + * To make sure the hash value is not bigger than size, the result of the user provided hash function is used modulo size. + */ +hashtbl_rc_t hashtbl_insert(hash_table_t *hashtblP, const uint64_t keyP, void *dataP) +{ + hash_node_t *node; + hash_size_t hash; + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP)%hashtblP->size; + + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + if (node->data) { + hashtblP->freefunc(node->data); + } + node->data=dataP; + return HASH_TABLE_INSERT_OVERWRITTEN_DATA; + } + node=node->next; + } + if(!(node=malloc(sizeof(hash_node_t)))) return -1; + node->key=keyP; + node->data=dataP; + if (hashtblP->nodes[hash]) { + node->next=hashtblP->nodes[hash]; + } else { + node->next = NULL; + } + hashtblP->nodes[hash]=node; + hashtblP->num_elements += 1; + return HASH_TABLE_OK; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * To remove an element from the hash table, we just search for it in the linked list for that hash value, + * and remove it if it is found. If it was not found, it is an error and -1 is returned. + */ +hashtbl_rc_t hashtbl_remove(hash_table_t *hashtblP, const uint64_t keyP) +{ + hash_node_t *node, *prevnode=NULL; + hash_size_t hash; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key != keyP) { + if(prevnode) prevnode->next=node->next; + else hashtblP->nodes[hash]=node->next; + if (node->data) { + hashtblP->freefunc(node->data); + } + free(node); + hashtblP->num_elements -= 1; + return HASH_TABLE_OK; + } + prevnode=node; + node=node->next; + } + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Searching for an element is easy. We just search through the linked list for the corresponding hash value. + * NULL is returned if we didn't find it. + */ +hashtbl_rc_t hashtbl_get(hash_table_t *hashtblP, const uint64_t keyP, void** dataP) +{ + hash_node_t *node; + hash_size_t hash; + + if (hashtblP == NULL) { + *dataP = NULL; + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP)%hashtblP->size; +/* fprintf(stderr, "hashtbl_get() key=%s, hash=%d\n", key, hash);*/ + + node=hashtblP->nodes[hash]; + + while(node) { + if(node->key == keyP) { + *dataP = node->data; + return HASH_TABLE_OK; + } + node=node->next; + } + *dataP = NULL; + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Resizing + * The number of elements in a hash table is not always known when creating the table. + * If the number of elements grows too large, it will seriously reduce the performance of most hash table operations. + * If the number of elements are reduced, the hash table will waste memory. That is why we provide a function for resizing the table. + * Resizing a hash table is not as easy as a realloc(). All hash values must be recalculated and each element must be inserted into its new position. + * We create a temporary hash_table_t object (newtbl) to be used while building the new hashes. + * This allows us to reuse hashtbl_insert() and hashtbl_remove(), when moving the elements to the new table. + * After that, we can just free the old table and copy the elements from newtbl to hashtbl. + */ + +hashtbl_rc_t hashtbl_resize(hash_table_t *hashtblP, hash_size_t sizeP) +{ + hash_table_t newtbl; + hash_size_t n; + hash_node_t *node,*next; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + + newtbl.size = sizeP; + newtbl.hashfunc = hashtblP->hashfunc; + + if(!(newtbl.nodes=calloc(sizeP, sizeof(hash_node_t*)))) return -1; + + for(n=0; n<hashtblP->size; ++n) { + for(node=hashtblP->nodes[n]; node; node=next) { + next = node->next; + hashtbl_insert(&newtbl, node->key, node->data); + // Lionel GAUTHIER: BAD CODE TO BE REWRITTEN + hashtbl_remove(hashtblP, node->key); + + } + } + + free(hashtblP->nodes); + hashtblP->size=newtbl.size; + hashtblP->nodes=newtbl.nodes; + + return HASH_TABLE_OK; +} + + + diff --git a/openair-cn/UTILS/HASHTABLE/hashtable.h b/openair-cn/UTILS/HASHTABLE/hashtable.h new file mode 100755 index 0000000000..0c5d8ed4e0 --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/hashtable.h @@ -0,0 +1,46 @@ +#ifndef _HASH_TABLE_H_ +#define _HASH_TABLE_H_ +#include<stdlib.h> +#include <stdint.h> +#include <stddef.h> + +typedef size_t hash_size_t; + +typedef enum hashtbl_return_code_e { + HASH_TABLE_OK = 0, + HASH_TABLE_INSERT_OVERWRITTEN_DATA = 1, + HASH_TABLE_KEY_NOT_EXISTS = 2, + HASH_TABLE_KEY_ALREADY_EXISTS = 3, + HASH_TABLE_BAD_PARAMETER_HASHTABLE = 4, + HASH_TABLE_CODE_MAX +} hashtbl_rc_t; + + +typedef struct hash_node_s { + uint64_t key; + void *data; + struct hash_node_s *next; +} hash_node_t; + +typedef struct hash_table_s { + hash_size_t size; + hash_size_t num_elements; + struct hash_node_s **nodes; + hash_size_t (*hashfunc)(const uint64_t); + void (*freefunc)(void*); +} hash_table_t; + +char* hashtble_rc_code2string(hashtbl_rc_t rcP); +hash_table_t *hashtbl_create (hash_size_t size, hash_size_t (*hashfunc)(const uint64_t ), void (*freefunc)(void*)); +hashtbl_rc_t hashtbl_destroy(hash_table_t *hashtbl); +hashtbl_rc_t hashtbl_is_key_exists (hash_table_t *hashtbl, const uint64_t key); +hashtbl_rc_t hashtbl_apply_funct_on_elements (hash_table_t *hashtblP, void funct(uint64_t keyP, void* dataP, void* parameterP), void* parameterP); +hashtbl_rc_t hashtbl_insert (hash_table_t *hashtbl, const uint64_t key, void *data); +hashtbl_rc_t hashtbl_remove (hash_table_t *hashtbl, const uint64_t key); +hashtbl_rc_t hashtbl_get (hash_table_t *hashtbl, const uint64_t key, void **dataP); +hashtbl_rc_t hashtbl_resize (hash_table_t *hashtbl, hash_size_t size); + + + +#endif + diff --git a/openair-cn/UTILS/HASHTABLE/obj_hashtable.c b/openair-cn/UTILS/HASHTABLE/obj_hashtable.c new file mode 100755 index 0000000000..b1a46ab676 --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/obj_hashtable.c @@ -0,0 +1,238 @@ +/* from: http://en.literateprograms.org/Hash_table_%28C%29#chunk%20def:node + * + */ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include "obj_hashtable.h" +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Default hash function + * def_hashfunc() is the default used by hashtbl_create() when the user didn't specify one. + * This is a simple/naive hash function which adds the key's ASCII char values. It will probably generate lots of collisions on large hash tables. + */ + +static hash_size_t def_hashfunc(const void *keyP, int key_sizeP) +{ + hash_size_t hash=0; + + while(key_sizeP) hash^=((unsigned char*)keyP)[key_sizeP --]; + + return hash; +} + +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Initialisation + * hashtbl_create() sets up the initial structure of the hash table. The user specified size will be allocated and initialized to NULL. + * The user can also specify a hash function. If the hashfunc argument is NULL, a default hash function is used. + * If an error occurred, NULL is returned. All other values in the returned obj_hash_table_t pointer should be released with hashtbl_destroy(). + */ +obj_hash_table_t *obj_hashtbl_create(hash_size_t sizeP, hash_size_t (*hashfuncP)(const void*, int ), void (*freekeyfuncP)(void*), void (*freedatafuncP)(void*)) +{ + obj_hash_table_t *hashtbl; + + if(!(hashtbl=malloc(sizeof(obj_hash_table_t)))) return NULL; + + if(!(hashtbl->nodes=calloc(sizeP, sizeof(obj_hash_node_t*)))) { + free(hashtbl); + return NULL; + } + + hashtbl->size=sizeP; + + if(hashfuncP) hashtbl->hashfunc=hashfuncP; + else hashtbl->hashfunc=def_hashfunc; + + if(freekeyfuncP) hashtbl->freekeyfunc=freekeyfuncP; + else hashtbl->freekeyfunc=free; + + if(freedatafuncP) hashtbl->freedatafunc=freedatafuncP; + else hashtbl->freedatafunc=free; + + return hashtbl; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Cleanup + * The hashtbl_destroy() walks through the linked lists for each possible hash value, and releases the elements. It also releases the nodes array and the obj_hash_table_t. + */ +hashtbl_rc_t obj_hashtbl_destroy(obj_hash_table_t *hashtblP) +{ + hash_size_t n; + obj_hash_node_t *node, *oldnode; + + for(n=0; n<hashtblP->size; ++n) { + node=hashtblP->nodes[n]; + while(node) { + oldnode=node; + node=node->next; + hashtblP->freekeyfunc(oldnode->key); + hashtblP->freedatafunc(oldnode->data); + free(oldnode); + } + } + free(hashtblP->nodes); + free(hashtblP); + return HASH_TABLE_OK; +} +//------------------------------------------------------------------------------------------------------------------------------- +hashtbl_rc_t obj_hashtbl_is_key_exists (obj_hash_table_t *hashtblP, void* keyP, int key_sizeP) +//------------------------------------------------------------------------------------------------------------------------------- +{ + obj_hash_node_t *node; + hash_size_t hash; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + return HASH_TABLE_OK; + } + node=node->next; + } + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Adding a new element + * To make sure the hash value is not bigger than size, the result of the user provided hash function is used modulo size. + */ +hashtbl_rc_t obj_hashtbl_insert(obj_hash_table_t *hashtblP, void* keyP, int key_sizeP, void *dataP) +{ + obj_hash_node_t *node; + hash_size_t hash; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + if (node->data) { + hashtblP->freedatafunc(node->data); + } + node->data=dataP; + // waste of memory here (keyP is lost) we should free it now + return HASH_TABLE_INSERT_OVERWRITTEN_DATA; + } + node=node->next; + } + if(!(node=malloc(sizeof(obj_hash_node_t)))) return -1; + node->key=keyP; + node->data=dataP; + if (hashtblP->nodes[hash]) { + node->next=hashtblP->nodes[hash]; + } else { + node->next = NULL; + } + hashtblP->nodes[hash]=node; + return HASH_TABLE_OK; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * To remove an element from the hash table, we just search for it in the linked list for that hash value, + * and remove it if it is found. If it was not found, it is an error and -1 is returned. + */ +hashtbl_rc_t obj_hashtbl_remove(obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP) +{ + obj_hash_node_t *node, *prevnode=NULL; + hash_size_t hash; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + + hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + if(prevnode) { + prevnode->next=node->next; + } else { + hashtblP->nodes[hash]=node->next; + } + hashtblP->freekeyfunc(node->key); + hashtblP->freedatafunc(node->data); + free(node); + return HASH_TABLE_OK; + } + prevnode=node; + node=node->next; + } + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Searching for an element is easy. We just search through the linked list for the corresponding hash value. + * NULL is returned if we didn't find it. + */ +hashtbl_rc_t obj_hashtbl_get(obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP, void** dataP) +{ + obj_hash_node_t *node; + hash_size_t hash; + + if (hashtblP == NULL) { + *dataP = NULL; + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + hash=hashtblP->hashfunc(keyP, key_sizeP)%hashtblP->size; + node=hashtblP->nodes[hash]; + while(node) { + if(node->key == keyP) { + *dataP = node->data; + return HASH_TABLE_OK; + } + node=node->next; + } + *dataP = NULL; + return HASH_TABLE_KEY_NOT_EXISTS; +} +//------------------------------------------------------------------------------------------------------------------------------- +/* + * Resizing + * The number of elements in a hash table is not always known when creating the table. + * If the number of elements grows too large, it will seriously reduce the performance of most hash table operations. + * If the number of elements are reduced, the hash table will waste memory. That is why we provide a function for resizing the table. + * Resizing a hash table is not as easy as a realloc(). All hash values must be recalculated and each element must be inserted into its new position. + * We create a temporary obj_hash_table_t object (newtbl) to be used while building the new hashes. + * This allows us to reuse hashtbl_insert() and hashtbl_remove(), when moving the elements to the new table. + * After that, we can just free the old table and copy the elements from newtbl to hashtbl. + */ +hashtbl_rc_t obj_hashtbl_resize(obj_hash_table_t *hashtblP, hash_size_t sizeP) +{ + obj_hash_table_t newtbl; + hash_size_t n; + obj_hash_node_t *node,*next; + + if (hashtblP == NULL) { + return HASH_TABLE_BAD_PARAMETER_HASHTABLE; + } + + newtbl.size = sizeP; + newtbl.hashfunc = hashtblP->hashfunc; + + if(!(newtbl.nodes=calloc(sizeP, sizeof(obj_hash_node_t*)))) return -1; + + for(n=0; n<hashtblP->size; ++n) { + for(node=hashtblP->nodes[n]; node; node=next) { + next = node->next; + obj_hashtbl_insert(&newtbl, node->key, node->key_size, node->data); + //WARNING Lionel GAUTHIER: BAD CODE TO BE REWRITTEN + obj_hashtbl_remove(hashtblP, node->key, node->key_size); + } + } + + free(hashtblP->nodes); + hashtblP->size=newtbl.size; + hashtblP->nodes=newtbl.nodes; + + return HASH_TABLE_OK; +} + + + diff --git a/openair-cn/UTILS/HASHTABLE/obj_hashtable.h b/openair-cn/UTILS/HASHTABLE/obj_hashtable.h new file mode 100755 index 0000000000..45442edf41 --- /dev/null +++ b/openair-cn/UTILS/HASHTABLE/obj_hashtable.h @@ -0,0 +1,39 @@ +#ifndef _OBJ_HASH_TABLE_H_ +#define _OBJ_HASH_TABLE_H_ +#include<stdlib.h> +#include <stdint.h> +#include <stddef.h> + +#include "hashtable.h" + +typedef size_t hash_size_t; + + +typedef struct obj_hash_node_s { + int key_size; + void *key; + void *data; + struct obj_hash_node_s *next; +} obj_hash_node_t; + +typedef struct obj_hash_table_s { + hash_size_t size; + hash_size_t num_elements; + struct obj_hash_node_s **nodes; + hash_size_t (*hashfunc)(const void*, int); + void (*freekeyfunc)(void*); + void (*freedatafunc)(void*); +} obj_hash_table_t; + +obj_hash_table_t *obj_hashtbl_create (hash_size_t size, hash_size_t (*hashfunc)(const void*, int ), void (*freekeyfunc)(void*), void (*freedatafunc)(void*)); +hashtbl_rc_t obj_hashtbl_destroy(obj_hash_table_t *hashtblP); +hashtbl_rc_t obj_hashtbl_is_key_exists (obj_hash_table_t *hashtblP, void* keyP, int key_sizeP); +hashtbl_rc_t obj_hashtbl_insert (obj_hash_table_t *hashtblP, void* keyP, int key_sizeP, void *dataP); +hashtbl_rc_t obj_hashtbl_remove (obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP); +hashtbl_rc_t obj_hashtbl_get (obj_hash_table_t *hashtblP, const void* keyP, int key_sizeP, void ** dataP); +hashtbl_rc_t obj_hashtbl_resize (obj_hash_table_t *hashtblP, hash_size_t sizeP); + + + +#endif + diff --git a/openair-cn/UTILS/Makefile.am b/openair-cn/UTILS/Makefile.am new file mode 100644 index 0000000000..b7d173f8de --- /dev/null +++ b/openair-cn/UTILS/Makefile.am @@ -0,0 +1,21 @@ +SUBDIRS = . HASHTABLE + +AM_CFLAGS = @ADD_CFLAGS@ \ + -I$(top_srcdir)/COMMON \ + -I$(top_srcdir)/INTERTASK_INTERFACE + +AM_YFLAGS = -d + +noinst_LTLIBRARIES = libutils.la +libutils_la_LDFLAGS = -all-static +libutils_la_SOURCES = \ + assertions.h \ + backtrace.c backtrace.h \ + conversions.h conversions.c \ + enum_string.h enum_string.c \ + log.c log.h \ + mme_parser.y mme_scanner.l \ + mme_config.c mme_config.h \ + mme_default_values.h \ + queue.h tree.h \ + signals.c signals.h diff --git a/openair-cn/UTILS/assertions.h b/openair-cn/UTILS/assertions.h new file mode 100644 index 0000000000..572f10eae6 --- /dev/null +++ b/openair-cn/UTILS/assertions.h @@ -0,0 +1,85 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ +#include <stdio.h> +#include <stdlib.h> + +#if defined(ENB_MODE) +# define display_backtrace() +#else +# include "backtrace.h" +#endif + +#ifndef ASSERTIONS_H_ +#define ASSERTIONS_H_ + +#define DevCheck(cOND, vALUE1, vALUE2, vALUE3) \ +do { \ + if (!(cOND)) { \ + fprintf(stderr, "%s:%d:%s Assertion `"#cOND"` failed.\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + fprintf(stderr, #vALUE1": %d\n"#vALUE2": %d\n"#vALUE3": %d\n\n", \ + (int)vALUE1, (int)vALUE2, (int)vALUE3); \ + display_backtrace(); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +#define DevParam(vALUE1, vALUE2, vALUE3) \ + DevCheck(0 == 1, vALUE1, vALUE2, vALUE3) + +#define DevAssert(cOND) \ +do { \ + if (!(cOND)) { \ + fprintf(stderr, "%s:%d:%s Assertion `"#cOND"` failed.\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + display_backtrace(); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +#define DevMessage(mESSAGE) \ +do { \ + fprintf(stderr, "%s:%d:%s Execution interrupted: `"#mESSAGE"`.\n", \ + __FILE__, __LINE__, __FUNCTION__); \ + display_backtrace(); \ + exit(EXIT_FAILURE); \ +} while(0) + +#define CHECK_INIT_RETURN(fCT) \ +do { \ + int fct_ret; \ + if ((fct_ret = (fCT)) != 0) { \ + fprintf(stderr, "Function "#fCT" has failed\n" \ + "returning %d\n", fct_ret); \ + exit(EXIT_FAILURE); \ + } \ +} while(0) + +#endif /* ASSERTIONS_H_ */ diff --git a/openair-cn/UTILS/backtrace.c b/openair-cn/UTILS/backtrace.c new file mode 100644 index 0000000000..2ee9fce08f --- /dev/null +++ b/openair-cn/UTILS/backtrace.c @@ -0,0 +1,65 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <signal.h> +#include <execinfo.h> + +#include "backtrace.h" + +/* Obtain a backtrace and print it to stdout. */ +void display_backtrace(void) +{ + void *array[10]; + size_t size; + char **strings; + size_t i; + + size = backtrace(array, 10); + strings = backtrace_symbols(array, size); + + printf("Obtained %zd stack frames.\n", size); + + for (i = 0; i < size; i++) + printf("%s\n", strings[i]); + + free(strings); +} + +void backtrace_handle_signal(siginfo_t *info) +{ + display_backtrace(); + exit(EXIT_FAILURE); +} diff --git a/openair-cn/UTILS/backtrace.h b/openair-cn/UTILS/backtrace.h new file mode 100644 index 0000000000..6772b0f0a6 --- /dev/null +++ b/openair-cn/UTILS/backtrace.h @@ -0,0 +1,40 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <signal.h> + +#ifndef BACKTRACE_H_ +#define BACKTRACE_H_ + +void display_backtrace(void); + +void backtrace_handle_signal(siginfo_t *info); + +#endif /* BACKTRACE_H_ */ diff --git a/openair-cn/UTILS/conversions.c b/openair-cn/UTILS/conversions.c new file mode 100644 index 0000000000..2dd52c8d21 --- /dev/null +++ b/openair-cn/UTILS/conversions.c @@ -0,0 +1,74 @@ +#include <stdlib.h> +#include <stdint.h> +#include <ctype.h> + +#include "conversions.h" + +static const char hex_to_ascii_table[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', +}; + +static const signed char ascii_to_hex_table[0x100] = +{ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 +}; + +void hexa_to_ascii(uint8_t *from, char *to, size_t length) +{ + int i; + for(i = 0; i < length; i++) { + uint8_t upper = (from[i] & 0xf0) >> 4; + uint8_t lower = from[i] & 0x0f; + to[2 * i] = hex_to_ascii_table[upper]; + to[2 * i + 1] = hex_to_ascii_table[lower]; + } +} + +int ascii_to_hex(uint8_t *dst, const char *h) +{ + const unsigned char *hex = (const unsigned char *) h; + unsigned i = 0; + + for (;;) + { + int high, low; + + while (*hex && isspace(*hex)) + hex++; + + if (!*hex) + return 1; + + high = ascii_to_hex_table[*hex++]; + if (high < 0) + return 0; + + while (*hex && isspace(*hex)) + hex++; + + if (!*hex) + return 0; + + low = ascii_to_hex_table[*hex++]; + if (low < 0) + return 0; + + dst[i++] = (high << 4) | low; + } +} + diff --git a/openair-cn/UTILS/conversions.h b/openair-cn/UTILS/conversions.h new file mode 100644 index 0000000000..54ea2052ed --- /dev/null +++ b/openair-cn/UTILS/conversions.h @@ -0,0 +1,270 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "assertions.h" + +#ifndef CONVERSIONS_H_ +#define CONVERSIONS_H_ + +/* Endianness conversions for 16 and 32 bits integers from host to network order */ +#if (BYTE_ORDER == LITTLE_ENDIAN) +# define hton_int32(x) \ + (((x & 0x000000FF) << 24) | ((x & 0x0000FF00) << 8) | \ + ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24)) + +# define hton_int16(x) \ + (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8) + +# define ntoh_int32_buf(bUF) \ + ((*(bUF)) << 24) | ((*((bUF) + 1)) << 16) | ((*((bUF) + 2)) << 8) \ + | (*((bUF) + 3)) +#else +# define hton_int32(x) (x) +# define hton_int16(x) (x) +#endif + +#define BUFFER_TO_INT8(buf, x) (x = ((buf)[0])) + +#define INT8_TO_BUFFER(x, buf) ((buf)[0] = (x)) + +/* Convert an integer on 16 bits to the given bUFFER */ +#define INT16_TO_BUFFER(x, buf) \ +do { \ + (buf)[0] = (x) >> 8; \ + (buf)[1] = (x); \ +} while(0) + +/* Convert an array of char containing vALUE to x */ +#define BUFFER_TO_INT16(buf, x) \ +do { \ + x = ((buf)[0] << 8) | \ + ((buf)[1]); \ +} while(0) + +/* Convert an integer on 32 bits to the given bUFFER */ +#define INT32_TO_BUFFER(x, buf) \ +do { \ + (buf)[0] = (x) >> 24; \ + (buf)[1] = (x) >> 16; \ + (buf)[2] = (x) >> 8; \ + (buf)[3] = (x); \ +} while(0) + +/* Convert an array of char containing vALUE to x */ +#define BUFFER_TO_INT32(buf, x) \ +do { \ + x = ((buf)[0] << 24) | \ + ((buf)[1] << 16) | \ + ((buf)[2] << 8) | \ + ((buf)[3]); \ +} while(0) + +/* Convert an integer on 32 bits to an octet string from asn1c tool */ +#define INT32_TO_OCTET_STRING(x, asn) \ +do { \ + (asn)->buf = calloc(4, sizeof(uint8_t)); \ + INT32_TO_BUFFER(x, ((asn)->buf)); \ + (asn)->size = 4; \ +} while(0) + +#define INT32_TO_BIT_STRING(x, asn) \ +do { \ + INT32_TO_OCTET_STRING(x, asn); \ + (asn)->bits_unused = 0; \ +} while(0) + +#define INT16_TO_OCTET_STRING(x, asn) \ +do { \ + (asn)->buf = calloc(2, sizeof(uint8_t)); \ + (asn)->size = 2; \ + INT16_TO_BUFFER(x, (asn)->buf); \ +} while(0) + +#define INT8_TO_OCTET_STRING(x, asn) \ +do { \ + (asn)->buf = calloc(1, sizeof(uint8_t)); \ + (asn)->size = 1; \ + INT8_TO_BUFFER(x, (asn)->buf); \ +} while(0) + +#define MME_CODE_TO_OCTET_STRING INT8_TO_OCTET_STRING +#define M_TMSI_TO_OCTET_STRING INT32_TO_OCTET_STRING +#define MME_GID_TO_OCTET_STRING INT16_TO_OCTET_STRING + +#define OCTET_STRING_TO_INT8(asn, x) \ +do { \ + DevCheck((asn)->size == 1, (asn)->size, 0, 0); \ + BUFFER_TO_INT8((asn)->buf, x); \ +} while(0) + +#define OCTET_STRING_TO_INT16(asn, x) \ +do { \ + DevCheck((asn)->size == 2, (asn)->size, 0, 0); \ + BUFFER_TO_INT16((asn)->buf, x); \ +} while(0) + +#define OCTET_STRING_TO_INT32(asn, x) \ +do { \ + DevCheck((asn)->size == 4, (asn)->size, 0, 0); \ + BUFFER_TO_INT32((asn)->buf, x); \ +} while(0) + +#define BIT_STRING_TO_INT32(asn, x) \ +do { \ + DevCheck((asn)->bits_unused == 0, (asn)->bits_unused, 0, 0); \ + OCTET_STRING_TO_INT32(asn, x); \ +} while(0) + +#define BIT_STRING_TO_CELL_IDENTITY(asn, x) \ +do { \ + DevCheck((asn)->bits_unused == 4, (asn)->bits_unused, 4, 0); \ + x = ((asn)->buf[0] << 20) | ((asn)->buf[1] << 12) | \ + ((asn)->buf[2] << 4) | (asn)->buf[3]; \ +} while(0) + +#define MCC_HUNDREDS(vALUE) \ + ((vALUE) / 100) +/* When MNC is only composed of 2 digits, set the hundreds unit to 0xf */ +#define MNC_HUNDREDS(vALUE) \ + (((vALUE) / 100) == 0 ? 15 : (vALUE) / 100) +#define MCC_MNC_DECIMAL(vALUE) \ + (((vALUE) / 10) % 10) +#define MCC_MNC_DIGIT(vALUE) \ + ((vALUE) % 10) + +#define MCC_TO_BUFFER(mCC, bUFFER) \ +do { \ + DevAssert(bUFFER != NULL); \ + (bUFFER)[0] = MCC_HUNDREDS(mCC); \ + (bUFFER)[1] = MCC_MNC_DECIMAL(mCC); \ + (bUFFER)[2] = MCC_MNC_DIGIT(mCC); \ +} while(0) + +#define MCC_MNC_TO_PLMNID(mCC, mNC, oCTETsTRING) \ +do { \ + (oCTETsTRING)->buf = calloc(3, sizeof(uint8_t)); \ + (oCTETsTRING)->buf[0] = (MCC_MNC_DECIMAL(mCC) << 4) | MCC_HUNDREDS(mCC); \ + (oCTETsTRING)->buf[1] = (MNC_HUNDREDS(mNC) << 4) | MCC_MNC_DIGIT(mCC); \ + (oCTETsTRING)->buf[2] = (MCC_MNC_DIGIT(mNC) << 4) | MCC_MNC_DECIMAL(mNC); \ + (oCTETsTRING)->size = 3; \ +} while(0) + +#define MCC_MNC_TO_TBCD(mCC, mNC, tBCDsTRING) \ +do { \ + char _buf[3]; \ + _buf[0] = (MCC_MNC_DECIMAL(mCC) << 4) | MCC_HUNDREDS(mCC); \ + _buf[1] = (MNC_HUNDREDS(mNC) << 4) | MCC_MNC_DIGIT(mCC); \ + _buf[2] = (MCC_MNC_DIGIT(mNC) << 4) | MCC_MNC_DECIMAL(mNC); \ + OCTET_STRING_fromBuf(tBCDsTRING, _buf, 3); \ +} while(0) + +#define TBCD_TO_MCC_MNC(tBCDsTRING, mCC, mNC) \ +do { \ + int mNC_hundred; \ + DevAssert((tBCDsTRING)->size == 3); \ + mNC_hundred = (((tBCDsTRING)->buf[1] & 0xf0) >> 4); \ + if (mNC_hundred == 0xf) mNC_hundred = 0; \ + mCC = (((((tBCDsTRING)->buf[0]) & 0xf0) >> 4) * 10) + \ + ((((tBCDsTRING)->buf[0]) & 0x0f) * 100) + \ + (((tBCDsTRING)->buf[1]) & 0x0f); \ + mNC = (mNC_hundred * 100) + \ + ((((tBCDsTRING)->buf[2]) & 0xf0) >> 4) + \ + ((((tBCDsTRING)->buf[2]) & 0x0f) * 10); \ +} while(0) + +#define TBCD_TO_PLMN_T(tBCDsTRING, pLMN) \ +do { \ + DevAssert((tBCDsTRING)->size == 3); \ + (pLMN)->MCCdigit2 = (((tBCDsTRING)->buf[0] & 0xf0) >> 4); \ + (pLMN)->MCCdigit3 = ((tBCDsTRING)->buf[0] & 0x0f); \ + (pLMN)->MCCdigit1 = (tBCDsTRING)->buf[1] & 0x0f; \ + (pLMN)->MNCdigit3 = (((tBCDsTRING)->buf[1] & 0xf0) >> 4) == 0xF \ + ? 0 : (((tBCDsTRING)->buf[1] & 0xf0) >> 4); \ + (pLMN)->MNCdigit2 = (((tBCDsTRING)->buf[2] & 0xf0) >> 4); \ + (pLMN)->MNCdigit1 = ((tBCDsTRING)->buf[2] & 0x0f); \ +} while(0) + +#define PLMN_T_TO_TBCD(pLMN, tBCDsTRING) \ +do { \ + tBCDsTRING[0] = (pLMN.MCCdigit2 << 4) | pLMN.MCCdigit3; \ + tBCDsTRING[1] = ((pLMN.MNCdigit1 == 0 ? 0xF : pLMN.MNCdigit1) << 4) \ + | pLMN.MCCdigit1; \ + tBCDsTRING[2] = (pLMN.MNCdigit2 << 4) | pLMN.MNCdigit3; \ +} while(0) + +#define PLMN_T_TO_MCC_MNC(pLMN, mCC, mNC) \ +do { \ + mCC = pLMN.MCCdigit3 * 100 + pLMN.MCCdigit2 * 10 + pLMN.MCCdigit1; \ + mNC = (pLMN.MNCdigit3 == 0xF ? 0 : pLMN.MNCdigit3 * 100) \ + + pLMN.MNCdigit2 * 10 + pLMN.MNCdigit1; \ +} while(0) + +#define MACRO_ENB_ID_TO_BIT_STRING(mACRO, bITsTRING) \ +do { \ + (bITsTRING)->buf = calloc(3, sizeof(uint8_t)); \ + (bITsTRING)->buf[0] = ((mACRO) >> 12); \ + (bITsTRING)->buf[1] = (mACRO) >> 4; \ + (bITsTRING)->buf[2] = (mACRO) & 0x0f; \ + (bITsTRING)->size = 3; \ + (bITsTRING)->bits_unused = 4; \ +} while(0) + +#define MACRO_ENB_ID_TO_CELL_IDENTITY(mACRO, bITsTRING) \ +do { \ + (bITsTRING)->buf = calloc(4, sizeof(uint8_t)); \ + (bITsTRING)->buf[0] = 0; \ + (bITsTRING)->buf[1] = ((mACRO) >> 12); \ + (bITsTRING)->buf[2] = (mACRO) >> 4; \ + (bITsTRING)->buf[3] = (mACRO) & 0x0f; \ + (bITsTRING)->size = 4; \ + (bITsTRING)->bits_unused = 4; \ +} while(0) + +/* Used to format an uint32_t containing an ipv4 address */ +#define IPV4_ADDR "%u.%u.%u.%u" +#define IPV4_ADDR_FORMAT(aDDRESS) \ + (uint8_t)((aDDRESS) & 0x000000ff), \ + (uint8_t)(((aDDRESS) & 0x0000ff00) >> 8 ), \ + (uint8_t)(((aDDRESS) & 0x00ff0000) >> 16), \ + (uint8_t)(((aDDRESS) & 0xff000000) >> 24) + +#define IPV4_ADDR_DISPLAY_8(aDDRESS) \ + (aDDRESS)[0], (aDDRESS)[1], (aDDRESS)[2], (aDDRESS)[3] + +#define TAC_TO_ASN1 INT16_TO_OCTET_STRING +#define GTP_TEID_TO_ASN1 INT32_TO_OCTET_STRING +#define OCTET_STRING_TO_TAC OCTET_STRING_TO_INT16 + +inline +void hexa_to_ascii(uint8_t *from, char *to, size_t length); + +int ascii_to_hex(uint8_t *dst, const char *h); + +#endif /* CONVERSIONS_H_ */ diff --git a/openair-cn/UTILS/enum_string.c b/openair-cn/UTILS/enum_string.c new file mode 100644 index 0000000000..4cd088eb59 --- /dev/null +++ b/openair-cn/UTILS/enum_string.c @@ -0,0 +1,62 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "common_types.h" + +#include "enum_string.h" + +enum_to_string_t rat_to_string[NUMBER_OF_RAT_TYPE] = { + { RAT_WLAN, "WLAN" }, + { RAT_VIRTUAL, "VIRUTAL" }, + { RAT_UTRAN, "UTRAN" }, + { RAT_GERAN, "GERAN" }, + { RAT_GAN, "GAN" }, + { RAT_HSPA_EVOLUTION, "HSPA_EVOLUTION" }, + { RAT_EUTRAN, "E-UTRAN" }, + { RAT_CDMA2000_1X, "CDMA2000_1X" }, + { RAT_HRPD, "HRPD" }, + { RAT_UMB, "UMB" }, + { RAT_EHRPD, "EHRPD" }, +}; + +enum_to_string_t network_access_mode_to_string[NAM_MAX] = { + { NAM_PACKET_AND_CIRCUIT, "PACKET AND CIRCUIT" }, + { NAM_RESERVED, "RESERVED" }, + { NAM_ONLY_PACKET, "ONLY PACKET" }, +}; + +enum_to_string_t all_apn_conf_ind_to_string[ALL_APN_MAX] = { + { ALL_APN_CONFIGURATIONS_INCLUDED, "ALL APN CONFIGURATIONS INCLUDED" }, + { MODIFIED_ADDED_APN_CONFIGURATIONS_INCLUDED, "MODIFIED ADDED APN CONFIGURATIONS INCLUDED" }, +}; + +enum_to_string_t pdn_type_to_string[IP_MAX] = { + { IPv4, "IPv4" }, + { IPv6, "IPv6" }, + { IPv4_AND_v6, "IPv4 and IPv6" }, + { IPv4_OR_v6, "IPv4 or IPv6" }, +}; + +static int +compare_values(const void *m1, const void *m2) +{ + enum_to_string_t *mi1 = (enum_to_string_t *) m1; + enum_to_string_t *mi2 = (enum_to_string_t *) m2; + return (mi1->enum_value - mi2->enum_value); +} + +char *enum_to_string(int enum_val, enum_to_string_t *string_table, int nb_element) +{ + enum_to_string_t *res; + enum_to_string_t temp; + + temp.enum_value = enum_val; + res = bsearch(&temp, string_table, nb_element, + sizeof(enum_to_string_t), compare_values); + + if (res == NULL) { + return "UNKNOWN"; + } + return res->enum_value_name; +} diff --git a/openair-cn/UTILS/enum_string.h b/openair-cn/UTILS/enum_string.h new file mode 100644 index 0000000000..649a92b1f6 --- /dev/null +++ b/openair-cn/UTILS/enum_string.h @@ -0,0 +1,21 @@ +#ifndef ENUM_STRING_H_ +#define ENUM_STRING_H_ + +typedef struct { + int enum_value; + char *enum_value_name; +} enum_to_string_t; + +extern enum_to_string_t network_access_mode_to_string[NAM_MAX]; +extern enum_to_string_t rat_to_string[NUMBER_OF_RAT_TYPE]; +extern enum_to_string_t pdn_type_to_string[IP_MAX]; + +char *enum_to_string(int enum_val, enum_to_string_t *string_table, int nb_element); +#define ACCESS_MODE_TO_STRING(vAL) \ + enum_to_string((int)vAL, network_access_mode_to_string, \ + sizeof(network_access_mode_to_string) / sizeof(enum_to_string_t)) +#define PDN_TYPE_TO_STRING(vAL) \ + enum_to_string((int)vAL, pdn_type_to_string, \ + sizeof(pdn_type_to_string) / sizeof(enum_to_string_t)) + +#endif /* ENUM_STRING_H_ */ diff --git a/openair-cn/UTILS/log.c b/openair-cn/UTILS/log.c new file mode 100644 index 0000000000..aae0d4ab89 --- /dev/null +++ b/openair-cn/UTILS/log.c @@ -0,0 +1,51 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include "log.h" + +/* mme log */ +int log_enabled = 0; + +int log_init(const mme_config_t *mme_config_p, + log_specific_init_t specific_init) +{ + if (mme_config_p->verbosity_level == 1) { + log_enabled = 1; + } else if (mme_config_p->verbosity_level == 2) { + log_enabled = 1; + } else { + log_enabled = 0; + } + return specific_init(mme_config_p->verbosity_level); +} diff --git a/openair-cn/UTILS/log.h b/openair-cn/UTILS/log.h new file mode 100644 index 0000000000..83067a00ef --- /dev/null +++ b/openair-cn/UTILS/log.h @@ -0,0 +1,46 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include "mme_config.h" + +#ifndef LOG_H_ +#define LOG_H_ + +/* asn1c debug */ +extern int asn_debug; +extern int asn1_xer_print; +extern int fd_g_debug_lvl; + +typedef int (*log_specific_init_t)(int log_level); + +int log_init(const mme_config_t *mme_config, + log_specific_init_t specific_init); + +#endif /* LOG_H_ */ diff --git a/openair-cn/UTILS/mme_config.c b/openair-cn/UTILS/mme_config.c new file mode 100644 index 0000000000..5c96d83236 --- /dev/null +++ b/openair-cn/UTILS/mme_config.c @@ -0,0 +1,287 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +#include <arpa/inet.h> /* To provide inet_addr */ + +#include "mme_config.h" + +mme_config_t mme_config; + +static +void config_init(mme_config_t *mme_config_p) +{ + memset(mme_config_p, 0, sizeof(mme_config_t)); + + pthread_rwlock_init(&mme_config_p->rw_lock, NULL); + + mme_config_p->verbosity_level = 0; + mme_config_p->config_file = NULL; + mme_config_p->max_eNBs = MAX_NUMBER_OF_ENB; + mme_config_p->max_ues = MAX_NUMBER_OF_UE; + /* Timer configuration */ + mme_config_p->gtpv1u_config.port_number = GTPV1_U_PORT_NUMBER; + mme_config_p->s1ap_config.port_number = S1AP_PORT_NUMBER; + /* IP configuration */ + mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up = DEFAULT_SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP; + mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up = inet_addr(DEFAULT_SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP); + mme_config_p->ipv4.sgw_ip_netmask_for_S1u_S12_S4_up = DEFAULT_SGW_IP_NETMASK_FOR_S1U_S12_S4_UP; + + mme_config_p->ipv4.sgw_interface_name_for_S5_S8_up = DEFAULT_SGW_INTERFACE_NAME_FOR_S5_S8_UP; + mme_config_p->ipv4.sgw_ip_address_for_S5_S8_up = inet_addr(DEFAULT_SGW_IP_ADDRESS_FOR_S5_S8_UP); + mme_config_p->ipv4.sgw_ip_netmask_for_S5_S8_up = DEFAULT_SGW_IP_NETMASK_FOR_S5_S8_UP; + + mme_config_p->ipv4.pgw_interface_name_for_SGI = DEFAULT_PGW_INTERFACE_NAME_FOR_S5_S8; + mme_config_p->ipv4.pgw_ip_addr_for_SGI = inet_addr(DEFAULT_PGW_IP_ADDRESS_FOR_S5_S8); + mme_config_p->ipv4.pgw_ip_netmask_for_SGI = DEFAULT_PGW_IP_NETMASK_FOR_S5_S8; + + mme_config_p->ipv4.mme_interface_name_for_S1_MME = DEFAULT_MME_INTERFACE_NAME_FOR_S1_MME; + mme_config_p->ipv4.mme_ip_address_for_S1_MME = inet_addr(DEFAULT_MME_IP_ADDRESS_FOR_S1_MME); + mme_config_p->ipv4.mme_ip_netmask_for_S1_MME = DEFAULT_MME_IP_NETMASK_FOR_S1_MME; + + mme_config_p->ipv4.mme_interface_name_for_S11 = DEFAULT_MME_INTERFACE_NAME_FOR_S11; + mme_config_p->ipv4.mme_ip_address_for_S11 = inet_addr(DEFAULT_MME_IP_ADDRESS_FOR_S11); + mme_config_p->ipv4.mme_ip_netmask_for_S11 = DEFAULT_MME_IP_NETMASK_FOR_S11; + + mme_config_p->ipv4.sgw_interface_name_for_S11 = DEFAULT_SGW_INTERFACE_NAME_FOR_S11; + mme_config_p->ipv4.sgw_ip_address_for_S11 = inet_addr(DEFAULT_SGW_IP_ADDRESS_FOR_S11); + mme_config_p->ipv4.sgw_ip_netmask_for_S11 = DEFAULT_SGW_IP_NETMASK_FOR_S11; + + mme_config_p->s6a_config.conf_file = S6A_CONF_FILE; + mme_config_p->itti_config.queue_size = ITTI_QUEUE_SIZE_MAX; + + mme_config_p->sctp_config.in_streams = SCTP_IN_STREAMS; + mme_config_p->sctp_config.out_streams = SCTP_OUT_STREAMS; + + mme_config_p->relative_capacity = RELATIVE_CAPACITY; + + mme_config_p->mme_statistic_timer = MME_STATISTIC_TIMER_S; + + mme_config_p->gummei.nb_mme_gid = 1; + mme_config_p->gummei.mme_gid = calloc(1, sizeof(*mme_config_p->gummei.mme_gid)); + mme_config_p->gummei.mme_gid[0] = MMEGID; + mme_config_p->gummei.nb_mmec = 1; + mme_config_p->gummei.mmec = calloc(1, sizeof(*mme_config_p->gummei.mmec)); + mme_config_p->gummei.mmec[0] = MMEC; + + /* Set the TAI */ + mme_config_p->gummei.nb_plmns = 1; + mme_config_p->gummei.plmn_mcc = calloc(1, sizeof(*mme_config_p->gummei.plmn_mcc)); + mme_config_p->gummei.plmn_mnc = calloc(1, sizeof(*mme_config_p->gummei.plmn_mnc)); + mme_config_p->gummei.plmn_tac = calloc(1, sizeof(*mme_config_p->gummei.plmn_tac)); + + mme_config_p->gummei.plmn_mcc[0] = PLMN_MCC; + mme_config_p->gummei.plmn_mnc[0] = PLMN_MNC; + mme_config_p->gummei.plmn_tac[0] = PLMN_TAC; + + mme_config_p->s1ap_config.outcome_drop_timer_sec = S1AP_OUTCOME_TIMER_DEFAULT; +} + +static int config_parse_file(mme_config_t *mme_config_p) +{ + extern FILE *yyin; + int ret = -1; + + if (mme_config_p == NULL) + return ret; + if (mme_config_p->config_file == NULL) { + fprintf(stderr, "No Configuration file given... Attempting default values\n"); + return 0; + } + + yyin = fopen(mme_config_p->config_file, "r"); + if (!yyin) { + /* We failed to open the file */ + fprintf(stderr, "Unable to open the configuration file: %s (%d:%s)\n", + mme_config_p->config_file, errno, strerror(errno)); + return errno; + } + + /* Call the yacc parser */ + ret = yyparse(mme_config_p); + + /* Close the file descriptor */ + if (fclose(yyin) != 0) { + fprintf(stderr, "Unable to close the configuration file: %s (%d:%s)\n", + mme_config_p->config_file, errno, strerror(errno)); + return errno; + } + return ret; +} + +#define DISPLAY_ARRAY(size, format, args...) \ +do { \ + int i; \ + for (i = 0; i < size; i++) { \ + fprintf(stdout, format, args); \ + if ((i != (size - 1)) && ((i + 1) % 10 == 0)) \ + { \ + fprintf(stdout, "\n "); \ + } \ + } \ + if (i > 0) \ + fprintf(stdout, "\n"); \ +} while(0) + +static void config_display(mme_config_t *mme_config_p) +{ + fprintf(stdout, "==== EURECOM %s v%s ====\n", PACKAGE_NAME, PACKAGE_VERSION); + fprintf(stdout, "Configuration:\n"); + fprintf(stdout, "- File .............: %s\n", mme_config_p->config_file); + fprintf(stdout, "- Verbosity level ..: %d\n", mme_config_p->verbosity_level); + fprintf(stdout, "- Realm ............: %s\n", mme_config_p->realm); + fprintf(stdout, "- Max eNBs .........: %u\n", mme_config_p->max_eNBs); + fprintf(stdout, "- Max UEs ..........: %u\n", mme_config_p->max_ues); + fprintf(stdout, "- Relative capa ....: %u\n\n", mme_config_p->relative_capacity); + fprintf(stdout, "- Statistics timer .: %u (seconds)\n\n", mme_config_p->mme_statistic_timer); + fprintf(stdout, "- S1-U:\n"); + fprintf(stdout, " port number ....: %d\n", mme_config_p->gtpv1u_config.port_number); + fprintf(stdout, "- S1-MME:\n"); + fprintf(stdout, " port number ....: %d\n", mme_config_p->s1ap_config.port_number); + fprintf(stdout, "- IP:\n"); + fprintf(stdout, " s1-u iface .....: %s\n", mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up); + fprintf(stdout, " s1-u ip ........: %s/%d\n", + inet_ntoa(*((struct in_addr *)&mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up)), + mme_config_p->ipv4.sgw_ip_netmask_for_S1u_S12_S4_up); + fprintf(stdout, " sgi iface ......: %s\n", mme_config_p->ipv4.pgw_interface_name_for_SGI); + fprintf(stdout, " sgi ip .........: %s/%d\n", + inet_ntoa(*((struct in_addr *)&mme_config_p->ipv4.pgw_ip_addr_for_SGI)), + mme_config_p->ipv4.pgw_ip_netmask_for_SGI); + fprintf(stdout, " s1-MME iface ...: %s\n", mme_config_p->ipv4.mme_interface_name_for_S1_MME); + fprintf(stdout, " s1-MME ip ......: %s/%d\n", + inet_ntoa(*((struct in_addr *)&mme_config_p->ipv4.mme_ip_address_for_S1_MME)), + mme_config_p->ipv4.mme_ip_netmask_for_S1_MME); + fprintf(stdout, " s11 S-GW iface .: %s\n", mme_config_p->ipv4.sgw_interface_name_for_S11); + fprintf(stdout, " s11 S-GW ip ....: %s/%d\n", + inet_ntoa(*((struct in_addr *)&mme_config_p->ipv4.sgw_ip_address_for_S11)), + mme_config_p->ipv4.sgw_ip_netmask_for_S11); + fprintf(stdout, " s11 MME iface ..: %s\n", mme_config_p->ipv4.mme_interface_name_for_S11); + fprintf(stdout, " s11 S-GW ip ....: %s/%d\n", + inet_ntoa(*((struct in_addr *)&mme_config_p->ipv4.mme_ip_address_for_S11)), + mme_config_p->ipv4.mme_ip_netmask_for_S11); + fprintf(stdout, "- ITTI:\n"); + fprintf(stdout, " queue size .....: %u (bytes)\n", mme_config_p->itti_config.queue_size); + fprintf(stdout, "- SCTP:\n"); + fprintf(stdout, " in streams .....: %u\n", mme_config_p->sctp_config.in_streams); + fprintf(stdout, " out streams ....: %u\n", mme_config_p->sctp_config.out_streams); + fprintf(stdout, "- GUMMEI:\n"); + fprintf(stdout, " mme group ids ..:\n "); + DISPLAY_ARRAY(mme_config_p->gummei.nb_mme_gid, "| %u ", mme_config_p->gummei.mme_gid[i]); + fprintf(stdout, " mme codes ......:\n "); + DISPLAY_ARRAY(mme_config_p->gummei.nb_mmec, "| %u ", mme_config_p->gummei.mmec[i]); + fprintf(stdout, " plmns ..........: (mcc.mnc:tac)\n "); + DISPLAY_ARRAY(mme_config_p->gummei.nb_plmns, "| %3u.%3u:%u ", + mme_config_p->gummei.plmn_mcc[i], mme_config_p->gummei.plmn_mnc[i], + mme_config_p->gummei.plmn_tac[i]); + fprintf(stdout, "- S6A:\n"); + fprintf(stdout, " conf file ......: %s\n", mme_config_p->s6a_config.conf_file); +} + +static void usage(void) +{ + fprintf(stdout, "==== EURECOM %s v%s ====\n", PACKAGE_NAME, PACKAGE_VERSION); + fprintf(stdout, "Please report any bug to: %s\n\n", PACKAGE_BUGREPORT); + fprintf(stdout, "Usage: oaisim_mme [options]\n\n"); + fprintf(stdout, "Available options:\n"); + fprintf(stdout, "-h Print this help and return\n"); + fprintf(stdout, "-i<interface name>\n"); + fprintf(stdout, " Set the network card to use for IPv4 forwarding\n"); + fprintf(stdout, "-c<path>\n"); + fprintf(stdout, " Set the configuration file for mme\n"); + fprintf(stdout, " See template in UTILS/CONF\n"); + fprintf(stdout, "-V Print %s version and return\n", PACKAGE_NAME); + fprintf(stdout, "-v[1-2] Debug level:\n"); + fprintf(stdout, " 1 -> ASN1 XER printf on and ASN1 debug off\n"); + fprintf(stdout, " 2 -> ASN1 XER printf on and ASN1 debug on\n"); +} + +extern void +nwGtpv1uDisplayBanner(void); + +int config_parse_opt_line(int argc, char *argv[], mme_config_t *mme_config_p) +{ + int c; + config_init(mme_config_p); + /* Parsing command line */ + while ((c = getopt (argc, argv, "c:hi:v:V")) != -1) { + switch (c) { + case 'c': { + /* Store the given configuration file. If no file is given, + * then the default values will be used. + */ + int config_file_len = 0; + config_file_len = strlen(optarg); + mme_config_p->config_file = malloc(sizeof(char) * (config_file_len + 1)); + memcpy(mme_config_p->config_file, optarg, config_file_len); + mme_config_p->config_file[config_file_len] = '\0'; + } break; + case 'i': { + int interface_len = 0; + + /* Copying provided interface name to use for ipv4 forwarding */ + interface_len = strlen(optarg); + mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up = calloc(interface_len + 1, sizeof(char)); + memcpy(mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up, optarg, interface_len); + mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up[interface_len] = '\0'; + } break; + case 'v': { + mme_config_p->verbosity_level = atoi(optarg); + } break; + case 'V': { + fprintf(stdout, "==== EURECOM %s v%s ====\n" + "Please report any bug to: %s\n", PACKAGE_NAME, PACKAGE_VERSION, + PACKAGE_BUGREPORT); + exit(0); + nwGtpv1uDisplayBanner(); + } break; + case 'h': /* Fall through */ + default: + usage(); + exit(0); + } + } + /* Parse the configuration file using bison */ + if (config_parse_file(mme_config_p) != 0) { + return -1; + } + /* Display yhe configuration */ + config_display(mme_config_p); + return 0; +} diff --git a/openair-cn/UTILS/mme_config.h b/openair-cn/UTILS/mme_config.h new file mode 100644 index 0000000000..bb587356d8 --- /dev/null +++ b/openair-cn/UTILS/mme_config.h @@ -0,0 +1,127 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#include <pthread.h> +#include <stdint.h> + +#include "mme_default_values.h" + +#ifndef MME_CONFIG_H_ +#define MME_CONFIG_H_ + +typedef struct mme_config_s { + /* Reader/writer lock for this configuration */ + pthread_rwlock_t rw_lock; + + uint8_t verbosity_level; + + char *config_file; + char *realm; + int realm_length; + + uint32_t max_eNBs; + uint32_t max_ues; + + uint8_t relative_capacity; + + uint32_t mme_statistic_timer; + + struct { + uint16_t nb_mme_gid; + uint16_t *mme_gid; + + uint16_t nb_mmec; + uint8_t *mmec; + + uint8_t nb_plmns; + uint16_t *plmn_mcc; + uint16_t *plmn_mnc; + uint16_t *plmn_tac; + } gummei; + + struct { + uint16_t in_streams; + uint16_t out_streams; + } sctp_config; + struct { + uint16_t port_number; + } gtpv1u_config; + struct { + uint16_t port_number; + uint8_t outcome_drop_timer_sec; + } s1ap_config; + struct { + char *sgw_interface_name_for_S1u_S12_S4_up; + uint32_t sgw_ip_address_for_S1u_S12_S4_up; + int sgw_ip_netmask_for_S1u_S12_S4_up; + + char *sgw_interface_name_for_S5_S8_up; + uint32_t sgw_ip_address_for_S5_S8_up; + int sgw_ip_netmask_for_S5_S8_up; + + char *pgw_interface_name_for_S5_S8; + uint32_t pgw_ip_address_for_S5_S8; + int pgw_ip_netmask_for_S5_S8; + + char *pgw_interface_name_for_SGI; + uint32_t pgw_ip_addr_for_SGI; + int pgw_ip_netmask_for_SGI; + + char *mme_interface_name_for_S1_MME; + uint32_t mme_ip_address_for_S1_MME; + int mme_ip_netmask_for_S1_MME; + + char *mme_interface_name_for_S11; + uint32_t mme_ip_address_for_S11; + int mme_ip_netmask_for_S11; + + char *sgw_interface_name_for_S11; + uint32_t sgw_ip_address_for_S11; + int sgw_ip_netmask_for_S11; + } ipv4; + struct { + char *conf_file; + } s6a_config; + struct { + uint32_t queue_size; + } itti_config; +} mme_config_t; + +extern mme_config_t mme_config; + +int config_parse_opt_line(int argc, char *argv[], mme_config_t *mme_config); + +#define config_read_lock(mMEcONFIG) pthread_rwlock_rdlock(&(mMEcONFIG)->rw_lock) +#define config_write_lock(mMEcONFIG) pthread_rwlock_wrlock(&(mMEcONFIG)->rw_lock) +#define config_unlock(mMEcONFIG) pthread_rwlock_unlock(&(mMEcONFIG)->rw_lock) + +int yyparse(struct mme_config_s *mme_config_p); + +#endif /* MME_CONFIG_H_ */ diff --git a/openair-cn/UTILS/mme_default_values.h b/openair-cn/UTILS/mme_default_values.h new file mode 100644 index 0000000000..30e827e2c5 --- /dev/null +++ b/openair-cn/UTILS/mme_default_values.h @@ -0,0 +1,150 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2012 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#ifndef MME_DEFAULT_VALUES_H_ +#define MME_DEFAULT_VALUES_H_ + +/******************************************************************************* + * Timer Constants + ******************************************************************************/ +#define MME_TIMER_TIMEOUT_NS (1000) +#define MME_TIMER_TIMEOUT_S (0) +#define MME_STATISTIC_TIMER_S (60) + +/******************************************************************************* + * GTPV1 User Plane Constants + ******************************************************************************/ +#define GTPV1_U_PORT_NUMBER (2152) + +/******************************************************************************* + * S1AP Constants + ******************************************************************************/ + +#define S1AP_PORT_NUMBER (36412) ///< S1AP SCTP IANA ASSIGNED Port Number +#define S1AP_SCTP_PPID (18) ///< S1AP SCTP Payload Protocol Identifier (PPID) + +#define S1AP_OUTCOME_TIMER_DEFAULT (5) ///< S1AP Outcome drop timer (s) + +/******************************************************************************* + * S6A Constants + ******************************************************************************/ + +#define S6A_CONF_FILE "../S6A/freediameter/s6a.conf" + +/******************************************************************************* + * SCTP Constants + ******************************************************************************/ + +#define SCTP_RECV_BUFFER_SIZE (1 << 16) +#define SCTP_OUT_STREAMS (64) +#define SCTP_IN_STREAMS (64) +#define SCTP_MAX_ATTEMPTS (5) + +/******************************************************************************* + * MME global definitions + ******************************************************************************/ + +#define MAX_NUMBER_OF_ENB (2) +#define MAX_NUMBER_OF_UE (64) + +#define MMEC (0) +#define MMEGID (0) +#define PLMN_MCC (208) +#define PLMN_MNC (34) +#define PLMN_TAC (0) + +#define RELATIVE_CAPACITY (15) + +/******************************************************************************* + * Intertask Interface Constants + ******************************************************************************/ + +#define ITTI_QUEUE_SIZE_PER_TASK (5 * 1024 * 1024) /* Limit the queue size to 5M */ +#define ITTI_PORT (10007) +/* This is the queue size for signal dumper */ +#define ITTI_QUEUE_SIZE_MAX (1 * 1024 * 1024) /* 1 MBytes */ +#define ITTI_DUMP_MAX_CON (5) /* Max connections in parallel */ + +/******************************************************************************* + * IPv4 Constants + ******************************************************************************/ + +/* Default network card to use for IPV4 packets forwarding. + * up stands for user-plane. + * cp stands for control-plane + * + * +-----------+ +------+ +-----------+ + * | eNB +------+ | ovs | VLAN 1+------+ MME | + * | |cpenb0+------------------+cpmme0| | + * | +------+ |bridge| +------+ | + * | |upenb0+-------+ | | | + * +-----------+------+ | | | +-----------+ + * +---|--+ | + * | +-----------+ + * | | S+P-GW | + * | VLAN2 +------+ +--------+ + * +----------+upsgw0| |pgwsgi0 + + * +------+ +--------+ + * | | + * +-----------+ + */ + +#define DEFAULT_SGW_INTERFACE_NAME_FOR_S11 ("s11sgw") +#define DEFAULT_SGW_IP_ADDRESS_FOR_S11 ("192.168.10.1") +#define DEFAULT_SGW_IP_NETMASK_FOR_S11 24 + +#define DEFAULT_SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP ("upsgw0") +#define DEFAULT_SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP ("192.168.1.1") +#define DEFAULT_SGW_IP_NETMASK_FOR_S1U_S12_S4_UP 24 + +#define DEFAULT_SGW_INTERFACE_NAME_FOR_S5_S8_UP ("upsgw1") +#define DEFAULT_SGW_IP_ADDRESS_FOR_S5_S8_UP ("192.168.5.2") +#define DEFAULT_SGW_IP_NETMASK_FOR_S5_S8_UP 24 + +#define DEFAULT_PGW_INTERFACE_NAME_FOR_S5_S8 ("uppgw0") +#define DEFAULT_PGW_IP_ADDRESS_FOR_S5_S8 ("192.168.5.1") +#define DEFAULT_PGW_IP_NETMASK_FOR_S5_S8 24 + +#define DEFAULT_PGW_INTERFACE_NAME_FOR_SGI ("eth0") +#define DEFAULT_PGW_IP_ADDR_FOR_SGI ("192.168.14.17") +#define DEFAULT_PGW_IP_NETMASK_FOR_SGI 24 + +#define DEFAULT_MME_INTERFACE_NAME_FOR_S11 ("s11mme") ///< MME control plane interface +#define DEFAULT_MME_IP_ADDRESS_FOR_S11 ("192.168.10.2") ///< MME control plane IP address +#define DEFAULT_MME_IP_NETMASK_FOR_S11 24; + +#define DEFAULT_MME_INTERFACE_NAME_FOR_S1_MME ("cpmme0") ///< MME control plane interface +#define DEFAULT_MME_IP_ADDRESS_FOR_S1_MME ("192.168.11.1") ///< MME control plane IP address +#define DEFAULT_MME_IP_NETMASK_FOR_S1_MME 24; + +#define IPV4_UP_UE_SUBNET ("10.2.0.0") + + +#endif /* MME_DEFAULT_VALUES_H_ */ diff --git a/openair-cn/UTILS/mme_parser.y b/openair-cn/UTILS/mme_parser.y new file mode 100644 index 0000000000..2fcd78fa39 --- /dev/null +++ b/openair-cn/UTILS/mme_parser.y @@ -0,0 +1,548 @@ +/* For development only : */ +%debug +%error-verbose + +%parse-param {struct mme_config_s *mme_config_p} + +/* Keep track of location */ +%locations +%defines +%pure-parser + +%{ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "mme_config.h" +#include "mme_parser.h" + +void yyerror (YYLTYPE *llocp, struct mme_config_s *mme_config_p, const char *s); + +extern int yywrap(); +extern int yylex(); + +/* The Lex parser prototype */ +int fddlex(YYSTYPE *lvalp, YYLTYPE *llocp); +%} + +/* Values returned by lex for token */ +%union { + char *string; /* The string is allocated by strdup in lex.*/ + int integer; /* Store integer values */ +} + +%token LEX_ERROR + +%token <string> QSTRING +%token <integer> INTEGER + +%token S6A_CONF +%token MAX_UE +%token MAX_ENB +%token ITTI_QUEUE_SIZE +%token SCTP_INSTREAMS +%token SCTP_OUTSTREAMS +%token MME_CODE +%token MME_GID +%token PLMN_Y +%token REALM +%token RELATIVE_CAP +%token S1AP_OUTCOME_TIMER +%token MME_STATISTIC_TIMER +%token SGW_INTERFACE_NAME_FOR_S11 +%token SGW_IP_ADDRESS_FOR_S11 +%token SGW_IP_NETMASK_FOR_S11 +%token SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP +%token SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP +%token SGW_IP_NETMASK_FOR_S1U_S12_S4_UP +%token SGW_INTERFACE_NAME_FOR_S5_S8_UP +%token SGW_IP_ADDRESS_FOR_S5_S8_UP +%token SGW_IP_NETMASK_FOR_S5_S8_UP +%token PGW_INTERFACE_NAME_FOR_S5_S8 +%token PGW_IP_ADDRESS_FOR_S5_S8 +%token PGW_IP_NETMASK_FOR_S5_S8 +%token PGW_INTERFACE_NAME_FOR_SGI +%token PGW_IP_ADDR_FOR_SGI +%token PGW_IP_NETMASK_FOR_SGI +%token MME_INTERFACE_NAME_FOR_S1_MME +%token MME_IP_ADDRESS_FOR_S1_MME +%token MME_IP_NETMASK_FOR_S1_MME +%token MME_INTERFACE_NAME_FOR_S11_MME +%token MME_IP_ADDRESS_FOR_S11_MME +%token MME_IP_NETMASK_FOR_S11_MME + +%% +conffile: /* If options not provided, we will default values */ + | conffile s6aconf + | conffile maxenb + | conffile maxue + | conffile mmec + | conffile mmegid + | conffile plmn + | conffile realm + | conffile relative_capacity + | conffile itti_queue_size + | conffile s1ap_outcome_timer + | conffile mme_statistic_timer + | conffile sgw_interface_name_for_S11 + | conffile sgw_ip_address_for_S11 + | conffile sgw_ip_netmask_for_S11 + | conffile sgw_interface_name_for_S1u_S12_S4_up + | conffile sgw_ip_address_for_S1u_S12_S4_up + | conffile sgw_ip_netmask_for_S1u_S12_S4_up + | conffile sgw_interface_name_for_S5_S8_up + | conffile sgw_ip_address_for_S5_S8_up + | conffile sgw_ip_netmask_for_S5_S8_up + | conffile pgw_interface_name_for_S5_S8 + | conffile pgw_ip_address_for_S5_S8 + | conffile pgw_ip_netmask_for_S5_S8 + | conffile pgw_interface_name_for_SGI + | conffile pgw_ip_addr_for_SGI + | conffile pgw_ip_netmask_for_SGI + | conffile mme_interface_name_for_S1_MME + | conffile mme_ip_address_for_S1_MME + | conffile mme_ip_netmask_for_S1_MME + | conffile mme_interface_name_for_S11_MME + | conffile mme_ip_address_for_S11_MME + | conffile mme_ip_netmask_for_S11_MME + | conffile sctp_instreams + | conffile sctp_outstreams + | conffile errors + { + yyerror(&yylloc, mme_config_p, "An error occurred while parsing the configuration file"); + return EINVAL; + } + ; + +mme_statistic_timer: MME_STATISTIC_TIMER '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } + mme_config_p->mme_statistic_timer = $3; + } + ; + +s1ap_outcome_timer: S1AP_OUTCOME_TIMER '=' INTEGER ';' + { + /* 0 is not a valid value here */ + if ($3 <= 0 || $3 >= (1 << (8 * sizeof(mme_config_p->s1ap_config.outcome_drop_timer_sec)))) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } + mme_config_p->s1ap_config.outcome_drop_timer_sec = $3; + } + ; + +s6aconf: S6A_CONF '=' QSTRING ';' + { + mme_config_p->s6a_config.conf_file = $3; + } + ; + +maxenb: MAX_ENB '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } + mme_config_p->max_eNBs = (uint32_t)$3; + } + ; + +maxue: MAX_UE '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } + mme_config_p->max_ues = (uint32_t)$3; + } + ; + +mmec: MME_CODE '=' mmeclist ';' + ; + +mmeclist: + { + yyerror(&yylloc, mme_config_p, "Empty value is not allowed"); + return EINVAL; + } + | mmecvalue ',' mmeclist + | mmecvalue + ; + +mmecvalue: INTEGER + { + if (mme_config_p->gummei.nb_mmec == 256) { + yyerror(&yylloc, mme_config_p, "Reached maximum number of mmec"); + return EINVAL; + } + if ($1 >= 256) { + yyerror(&yylloc, mme_config_p, "Value exceed limit <= 255"); + return EINVAL; + } + mme_config_p->gummei.nb_mmec++; + mme_config_p->gummei.mmec = realloc(mme_config_p->gummei.mmec, + mme_config_p->gummei.nb_mmec * sizeof(uint8_t)); + mme_config_p->gummei.mmec[mme_config_p->gummei.nb_mmec-1] = (uint8_t)$1; + } + ; + +mmegid: MME_GID '=' mmegidlist ';' + ; + +mmegidlist: + { + yyerror(&yylloc, mme_config_p, "Empty value is not allowed"); + return EINVAL; + } + | mmegidvalue + | mmegidvalue ',' mmegidlist + ; + +mmegidvalue: INTEGER + { + if (mme_config_p->gummei.nb_mme_gid == 65535) { + yyerror(&yylloc, mme_config_p, "Reached maximum number of mmegid"); + return EINVAL; + } + if ($1 >= 65356) { + yyerror(&yylloc, mme_config_p, "Value exceed limit <= 65535"); + return EINVAL; + } + mme_config_p->gummei.nb_mme_gid++; + mme_config_p->gummei.mme_gid = realloc(mme_config_p->gummei.mme_gid, + mme_config_p->gummei.nb_mme_gid * sizeof(uint16_t)); + mme_config_p->gummei.mme_gid[mme_config_p->gummei.nb_mme_gid-1] = (uint16_t)$1; + } + ; + +realm: REALM '=' QSTRING ';' + { + mme_config_p->realm = $3; + mme_config_p->realm_length = strlen(mme_config_p->realm); + } + ; + +plmn: PLMN_Y '=' plmnlist ';' + ; + +plmnlist: + { + yyerror(&yylloc, mme_config_p, "Empty value is not allowed"); + return EINVAL; + } + | plmnvalue + | plmnvalue ',' plmnlist + ; + +plmnvalue: INTEGER '.' INTEGER ':' INTEGER + { + if (mme_config_p->gummei.nb_plmns == 32) { + yyerror(&yylloc, mme_config_p, "Reached maximum number of plmns"); + return EINVAL; + } + if ($1 > 999 || $3 > 999) { + yyerror(&yylloc, mme_config_p, "PLMN value exceed limit <= 999"); + return EINVAL; + } + if ($5 > 65535) { + yyerror(&yylloc, mme_config_p, "TAC value exceed limit <= 65535"); + return EINVAL; + } + mme_config_p->gummei.nb_plmns++; + mme_config_p->gummei.plmn_mcc = realloc(mme_config_p->gummei.plmn_mcc, + mme_config_p->gummei.nb_plmns * sizeof(uint16_t)); + mme_config_p->gummei.plmn_mnc = realloc(mme_config_p->gummei.plmn_mnc, + mme_config_p->gummei.nb_plmns * sizeof(uint16_t)); + mme_config_p->gummei.plmn_tac = realloc(mme_config_p->gummei.plmn_tac, + mme_config_p->gummei.nb_plmns * sizeof(uint16_t)); + mme_config_p->gummei.plmn_mcc[mme_config_p->gummei.nb_plmns-1] = (uint16_t)$1; + mme_config_p->gummei.plmn_mnc[mme_config_p->gummei.nb_plmns-1] = (uint16_t)$3; + mme_config_p->gummei.plmn_tac[mme_config_p->gummei.nb_plmns-1] = (uint16_t)$5; + } + ; + +relative_capacity: RELATIVE_CAP '=' INTEGER ';' + { + if ($3 >= 256 || $3 < 0) { + yyerror(&yylloc, mme_config_p, "Value exceed limit <= 255"); + return EINVAL; + } + mme_config_p->relative_capacity = $3; + } + ; + +itti_queue_size: ITTI_QUEUE_SIZE '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } + mme_config_p->itti_config.queue_size = (uint32_t)$3; + } + ; + +sctp_instreams: SCTP_INSTREAMS '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->sctp_config.in_streams = (uint16_t)$3; + } + ; + +sctp_outstreams: SCTP_OUTSTREAMS '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->sctp_config.out_streams = (uint16_t)$3; + } + ; + +sgw_interface_name_for_S11: SGW_INTERFACE_NAME_FOR_S11 '=' QSTRING ';' + { + mme_config_p->ipv4.sgw_interface_name_for_S11 = $3; + } + ; + +sgw_ip_address_for_S11: SGW_IP_ADDRESS_FOR_S11 '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.sgw_ip_address_for_S11 = inp.s_addr; + } + } + ; + +sgw_ip_netmask_for_S11: SGW_IP_NETMASK_FOR_S11 '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.sgw_ip_netmask_for_S11 = (uint16_t)$3; + } + ; + +sgw_interface_name_for_S1u_S12_S4_up: SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP '=' QSTRING ';' + { + mme_config_p->ipv4.sgw_interface_name_for_S1u_S12_S4_up = $3; + } + ; + +sgw_ip_address_for_S1u_S12_S4_up: SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.sgw_ip_address_for_S1u_S12_S4_up = inp.s_addr; + } + } + ; + +sgw_ip_netmask_for_S1u_S12_S4_up: SGW_IP_NETMASK_FOR_S1U_S12_S4_UP '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.sgw_ip_netmask_for_S1u_S12_S4_up = (uint16_t)$3; + } + ; + +sgw_interface_name_for_S5_S8_up: SGW_INTERFACE_NAME_FOR_S5_S8_UP '=' QSTRING ';' + { + mme_config_p->ipv4.sgw_interface_name_for_S5_S8_up = $3; + } + ; + +sgw_ip_address_for_S5_S8_up: SGW_IP_ADDRESS_FOR_S5_S8_UP '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.sgw_ip_address_for_S5_S8_up = inp.s_addr; + } + } + ; + +sgw_ip_netmask_for_S5_S8_up: SGW_IP_NETMASK_FOR_S5_S8_UP '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.sgw_ip_netmask_for_S5_S8_up = (uint16_t)$3; + } + ; + +pgw_interface_name_for_S5_S8: PGW_INTERFACE_NAME_FOR_S5_S8 '=' QSTRING ';' + { + mme_config_p->ipv4.pgw_interface_name_for_S5_S8 = $3; + } + ; + +pgw_ip_address_for_S5_S8: PGW_IP_ADDRESS_FOR_S5_S8 '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.pgw_ip_address_for_S5_S8 = inp.s_addr; + } + } + ; + +pgw_ip_netmask_for_S5_S8: PGW_IP_NETMASK_FOR_S5_S8 '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.pgw_ip_netmask_for_S5_S8 = (uint16_t)$3; + } + ; + +pgw_interface_name_for_SGI: PGW_INTERFACE_NAME_FOR_SGI '=' QSTRING ';' + { + mme_config_p->ipv4.pgw_interface_name_for_SGI = $3; + } + ; + +pgw_ip_addr_for_SGI: PGW_IP_ADDR_FOR_SGI '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.pgw_ip_addr_for_SGI = inp.s_addr; + } + } + ; + +pgw_ip_netmask_for_SGI: PGW_IP_NETMASK_FOR_SGI '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.pgw_ip_netmask_for_SGI = (uint16_t)$3; + } + ; + +mme_interface_name_for_S1_MME: MME_INTERFACE_NAME_FOR_S1_MME '=' QSTRING ';' + { + mme_config_p->ipv4.mme_interface_name_for_S1_MME = $3; + } + ; + +mme_ip_address_for_S1_MME: MME_IP_ADDRESS_FOR_S1_MME '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.mme_ip_address_for_S1_MME = inp.s_addr; + } + } + ; + +mme_ip_netmask_for_S1_MME: MME_IP_NETMASK_FOR_S1_MME '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.mme_ip_netmask_for_S1_MME = (uint16_t)$3; + } + ; + +mme_interface_name_for_S11_MME: MME_INTERFACE_NAME_FOR_S11_MME '=' QSTRING ';' + { + mme_config_p->ipv4.mme_interface_name_for_S11 = $3; + } + ; + +mme_ip_address_for_S11_MME: MME_IP_ADDRESS_FOR_S11_MME '=' QSTRING ';' + { + struct in_addr inp; + if ( inet_aton($3, &inp ) < 0 ) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else { + mme_config_p->ipv4.mme_ip_address_for_S11 = inp.s_addr; + } + } + ; + +mme_ip_netmask_for_S11_MME: MME_IP_NETMASK_FOR_S11_MME '=' INTEGER ';' + { + if ($3 <= 0) { + yyerror(&yylloc, mme_config_p, "Invalid value"); + return EINVAL; + } else if ($3 > UINT16_MAX) { + yyerror(&yylloc, mme_config_p, "Value exceed container"); + return EINVAL; + } + mme_config_p->ipv4.mme_ip_netmask_for_S11 = (uint16_t)$3; + } + ; + + + /* Lexical or syntax error */ +errors: LEX_ERROR + | error + ; +%% + +void yyerror(YYLTYPE *llocp, struct mme_config_s *mme_config_p, const char *str) +{ + fprintf(stderr, "Error in %s ( on line %i column %i -> line %i column %i) : %s\n", + mme_config_p->config_file, llocp->first_line, llocp->first_column, + llocp->last_line, llocp->last_column, str); +} diff --git a/openair-cn/UTILS/mme_scanner.l b/openair-cn/UTILS/mme_scanner.l new file mode 100644 index 0000000000..f8b5264ac9 --- /dev/null +++ b/openair-cn/UTILS/mme_scanner.l @@ -0,0 +1,128 @@ + +/* Lex configuration parser. + * + * This file defines the token for parsing the configuration file + * + * Note : This module is NOT thread-safe. All processing must be done from one thread only. + */ +%{ +#include <stdio.h> + +#include "mme_config.h" +/* Include yacc tokens definitions */ +#include "mme_parser.h" + +/* Update the column information */ +#ifdef DEBUG_LEX +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ + TRACE_DEBUG(FULL, \ + "(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n", \ + yylloc->first_line, yylloc->first_column, \ + yylloc->last_line, yylloc->last_column, \ + yy_act, yyleng, yytext); \ +} +#else /* DEBUG_LEX */ +#define YY_USER_ACTION { \ + yylloc->first_column = yylloc->last_column + 1; \ + yylloc->last_column = yylloc->first_column + yyleng - 1; \ +} +#endif + +#define YY_NO_INPUT +%} + +%option bison-bridge bison-locations +%option noyywrap +%option nounput + +/* Quoted string. Multilines do not match. */ +qstring \"[^\"\n]*\" + +%% + + /* List of patterns and actions */ + +<*>\n { + /* Update the line count */ + yylloc->first_line++; + yylloc->last_line++; + yylloc->last_column=0; +} + +<*>([[:space:]]{-}[\n])+ ; /* Eat all spaces, not new lines */ +<*>#.*$ ; /* Eat all comments */ + +{qstring} { + /* First copy the string without the quotes for use in the yacc parser */ + if ((yylval->string = strdup(yytext+1)) == NULL) { /* This allocates one useless tail char but... it's easier :D */ + return LEX_ERROR;/* on error, trig an error in yacc parser */ + } + yylval->string[yyleng-2] = '\0'; + + /* the yacc parser will check the string is valid */ + return QSTRING; +} + +[[:digit:]]+ { + /* Convert this to an integer value */ + int ret = sscanf(yytext, "%i", &yylval->integer); + if (ret != 1) { + /* No matching: an error occurred */ + fprintf(stderr, "Unable to convert the value '%s' to a valid number: %s\n", + yytext, strerror(errno)); + return LEX_ERROR; /* trig an error in yacc parser */ + /* Maybe we could REJECT instead of failing here? */ + } + return INTEGER; +} + + /* Full words tokens (keywords) */ +(?i:"MAXENB") { return MAX_ENB; } +(?i:"MAXUE") { return MAX_UE; } +(?i:"S6A_CONF") { return S6A_CONF; } +(?i:"ITTI_QUEUE_SIZE") { return ITTI_QUEUE_SIZE; } +(?i:"SCTP_INSTREAMS") { return SCTP_INSTREAMS; } +(?i:"SCTP_OUTSTREAMS") { return SCTP_OUTSTREAMS; } +(?i:"MME_CODE") { return MME_CODE; } +(?i:"MME_GID") { return MME_GID; } +(?i:"REALM") { return REALM; } +(?i:"PLMN") { return PLMN_Y; } +(?i:"RELATIVE_CAPACITY") { return RELATIVE_CAP; } +(?i:"S1AP_OUTCOME_TIMER") { return S1AP_OUTCOME_TIMER; } +(?i:"MME_STATISTIC_TIMER") { return MME_STATISTIC_TIMER; } +(?i:"SGW_INTERFACE_NAME_FOR_S11") { return SGW_INTERFACE_NAME_FOR_S11; } +(?i:"SGW_IP_ADDRESS_FOR_S11") { return SGW_IP_ADDRESS_FOR_S11; } +(?i:"SGW_IP_NETMASK_FOR_S11") { return SGW_IP_NETMASK_FOR_S11; } +(?i:"SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP") { return SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP; } +(?i:"SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP") { return SGW_IP_ADDRESS_FOR_S1U_S12_S4_UP; } +(?i:"SGW_IP_NETMASK_FOR_S1U_S12_S4_UP") { return SGW_IP_NETMASK_FOR_S1U_S12_S4_UP; } +(?i:"SGW_INTERFACE_NAME_FOR_S5_S8_UP") { return SGW_INTERFACE_NAME_FOR_S5_S8_UP; } +(?i:"SGW_IP_ADDRESS_FOR_S5_S8_UP") { return SGW_IP_ADDRESS_FOR_S5_S8_UP; } +(?i:"SGW_IP_NETMASK_FOR_S5_S8_UP") { return SGW_IP_NETMASK_FOR_S5_S8_UP; } +(?i:"PGW_INTERFACE_NAME_FOR_S5_S8") { return PGW_INTERFACE_NAME_FOR_S5_S8; } +(?i:"PGW_IP_ADDRESS_FOR_S5_S8") { return PGW_IP_ADDRESS_FOR_S5_S8; } +(?i:"PGW_IP_NETMASK_FOR_S5_S8") { return PGW_IP_NETMASK_FOR_S5_S8; } +(?i:"PGW_INTERFACE_NAME_FOR_SGI") { return PGW_INTERFACE_NAME_FOR_SGI; } +(?i:"PGW_IP_ADDR_FOR_SGI") { return PGW_IP_ADDR_FOR_SGI; } +(?i:"PGW_IP_NETMASK_FOR_SGI") { return PGW_IP_NETMASK_FOR_SGI; } +(?i:"MME_INTERFACE_NAME_FOR_S1_MME") { return MME_INTERFACE_NAME_FOR_S1_MME; } +(?i:"MME_IP_ADDRESS_FOR_S1_MME") { return MME_IP_ADDRESS_FOR_S1_MME; } +(?i:"MME_IP_NETMASK_FOR_S1_MME") { return MME_IP_NETMASK_FOR_S1_MME; } +(?i:"MME_INTERFACE_NAME_FOR_S11_MME") { return MME_INTERFACE_NAME_FOR_S11_MME; } +(?i:"MME_IP_ADDRESS_FOR_S11_MME") { return MME_IP_ADDRESS_FOR_S11_MME; } +(?i:"MME_IP_NETMASK_FOR_S11_MME") { return MME_IP_NETMASK_FOR_S11_MME; } + + /* Valid single characters for yyparse */ +<*>[.=,:;{}] { return yytext[0]; } + +<*>[[:alnum:]]+ | /* This rule is only useful to print a complete token in error messages */ + /* Unrecognized character */ +<*>. { + fprintf(stderr, "Unrecognized text on line %d col %d: '%s'.\n", + yylloc->first_line, yylloc->first_column, yytext); + return LEX_ERROR; +} + +%% diff --git a/openair-cn/UTILS/queue.h b/openair-cn/UTILS/queue.h new file mode 100644 index 0000000000..294d485110 --- /dev/null +++ b/openair-cn/UTILS/queue.h @@ -0,0 +1,592 @@ +/* + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)queue.h 8.5 (Berkeley) 8/20/94 + */ + +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * This file defines five types of data structures: singly-linked lists, + * lists, simple queues, tail queues, and circular queues. + * + * A singly-linked list is headed by a single forward pointer. The + * elements are singly linked for minimum space and pointer manipulation + * overhead at the expense of O(n) removal for arbitrary elements. New + * elements can be added to the list after an existing element or at the + * head of the list. Elements being removed from the head of the list + * should use the explicit macro for this purpose for optimum + * efficiency. A singly-linked list may only be traversed in the forward + * direction. Singly-linked lists are ideal for applications with large + * datasets and few or no removals or for implementing a LIFO queue. + * + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * A simple queue is headed by a pair of pointers, one the head of the + * list and the other to the tail of the list. The elements are singly + * linked to save space, so elements can only be removed from the + * head of the list. New elements can be added to the list after + * an existing element, at the head of the list, or at the end of the + * list. A simple queue may only be traversed in the forward direction. + * + * A tail queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or + * after an existing element, at the head of the list, or at the end of + * the list. A tail queue may be traversed in either direction. + * + * A circle queue is headed by a pair of pointers, one to the head of the + * list and the other to the tail of the list. The elements are doubly + * linked so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before or after + * an existing element, at the head of the list, or at the end of the list. + * A circle queue may be traversed in either direction, but has a more + * complex end of list detection. + * + * For details on the use of these macros, see the queue(3) manual page. + * SLIST LIST STAILQ TAILQ CIRCLEQ + * _HEAD + + + + + + * _HEAD_INITIALIZER + + + + + + * _ENTRY + + + + + + * _INIT + + + + + + * _EMPTY + + + + + + * _FIRST + + + + + + * _NEXT + + + + + + * _PREV - - - + + + * _LAST - - + + + + * _FOREACH + + + + + + * _FOREACH_REVERSE - - - + + + * _INSERT_HEAD + + + + + + * _INSERT_BEFORE - + - + + + * _INSERT_AFTER + + + + + + * _INSERT_TAIL - - + + + + * _REMOVE_HEAD + - + - - + * _REMOVE + + + + + + */ + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List functions. + */ +#define LIST_INIT(head) do { \ + (head)->lh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.le_next = (head)->lh_first) != NULL) \ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (/*CONSTCOND*/0) + +#define LIST_REMOVE(elm, field) do { \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ +} while (/*CONSTCOND*/0) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var); \ + (var) = ((var)->field.le_next)) + +/* + * List access methods. + */ +#define LIST_EMPTY(head) ((head)->lh_first == NULL) +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + + +/* + * Singly-linked List definitions. + */ +#define SLIST_HEAD(name, type) \ +struct name { \ + struct type *slh_first; /* first element */ \ +} + +#define SLIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define SLIST_ENTRY(type) \ +struct { \ + struct type *sle_next; /* next element */ \ +} + +/* + * Singly-linked List functions. + */ +#define SLIST_INIT(head) do { \ + (head)->slh_first = NULL; \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ + (elm)->field.sle_next = (slistelm)->field.sle_next; \ + (slistelm)->field.sle_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.sle_next = (head)->slh_first; \ + (head)->slh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE_HEAD(head, field) do { \ + (head)->slh_first = (head)->slh_first->field.sle_next; \ +} while (/*CONSTCOND*/0) + +#define SLIST_REMOVE(head, elm, type, field) do { \ + if ((head)->slh_first == (elm)) { \ + SLIST_REMOVE_HEAD((head), field); \ + } \ + else { \ + struct type *curelm = (head)->slh_first; \ + while(curelm->field.sle_next != (elm)) \ + curelm = curelm->field.sle_next; \ + curelm->field.sle_next = \ + curelm->field.sle_next->field.sle_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SLIST_FOREACH(var, head, field) \ + for((var) = (head)->slh_first; (var); (var) = (var)->field.sle_next) + +/* + * Singly-linked List access methods. + */ +#define SLIST_EMPTY(head) ((head)->slh_first == NULL) +#define SLIST_FIRST(head) ((head)->slh_first) +#define SLIST_NEXT(elm, field) ((elm)->field.sle_next) + + +/* + * Singly-linked Tail queue declarations. + */ +#define STAILQ_HEAD(name, type) \ +struct name { \ + struct type *stqh_first; /* first element */ \ + struct type **stqh_last; /* addr of last next element */ \ +} + +#define STAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).stqh_first } + +#define STAILQ_ENTRY(type) \ +struct { \ + struct type *stqe_next; /* next element */ \ +} + +/* + * Singly-linked Tail queue functions. + */ +#define STAILQ_INIT(head) do { \ + (head)->stqh_first = NULL; \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (head)->stqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.stqe_next = NULL; \ + *(head)->stqh_last = (elm); \ + (head)->stqh_last = &(elm)->field.stqe_next; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\ + (head)->stqh_last = &(elm)->field.stqe_next; \ + (listelm)->field.stqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE_HEAD(head, field) do { \ + if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \ + (head)->stqh_last = &(head)->stqh_first; \ +} while (/*CONSTCOND*/0) + +#define STAILQ_REMOVE(head, elm, type, field) do { \ + if ((head)->stqh_first == (elm)) { \ + STAILQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->stqh_first; \ + while (curelm->field.stqe_next != (elm)) \ + curelm = curelm->field.stqe_next; \ + if ((curelm->field.stqe_next = \ + curelm->field.stqe_next->field.stqe_next) == NULL) \ + (head)->stqh_last = &(curelm)->field.stqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define STAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->stqh_first); \ + (var); \ + (var) = ((var)->field.stqe_next)) + +#define STAILQ_CONCAT(head1, head2) do { \ + if (!STAILQ_EMPTY((head2))) { \ + *(head1)->stqh_last = (head2)->stqh_first; \ + (head1)->stqh_last = (head2)->stqh_last; \ + STAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Singly-linked Tail queue access methods. + */ +#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) +#define STAILQ_FIRST(head) ((head)->stqh_first) +#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) + + +/* + * Simple queue definitions. + */ +#define SIMPLEQ_HEAD(name, type) \ +struct name { \ + struct type *sqh_first; /* first element */ \ + struct type **sqh_last; /* addr of last next element */ \ +} + +#define SIMPLEQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).sqh_first } + +#define SIMPLEQ_ENTRY(type) \ +struct { \ + struct type *sqe_next; /* next element */ \ +} + +/* + * Simple queue functions. + */ +#define SIMPLEQ_INIT(head) do { \ + (head)->sqh_first = NULL; \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (head)->sqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.sqe_next = NULL; \ + *(head)->sqh_last = (elm); \ + (head)->sqh_last = &(elm)->field.sqe_next; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\ + (head)->sqh_last = &(elm)->field.sqe_next; \ + (listelm)->field.sqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE_HEAD(head, field) do { \ + if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \ + (head)->sqh_last = &(head)->sqh_first; \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_REMOVE(head, elm, type, field) do { \ + if ((head)->sqh_first == (elm)) { \ + SIMPLEQ_REMOVE_HEAD((head), field); \ + } else { \ + struct type *curelm = (head)->sqh_first; \ + while (curelm->field.sqe_next != (elm)) \ + curelm = curelm->field.sqe_next; \ + if ((curelm->field.sqe_next = \ + curelm->field.sqe_next->field.sqe_next) == NULL) \ + (head)->sqh_last = &(curelm)->field.sqe_next; \ + } \ +} while (/*CONSTCOND*/0) + +#define SIMPLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->sqh_first); \ + (var); \ + (var) = ((var)->field.sqe_next)) + +/* + * Simple queue access methods. + */ +#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == NULL) +#define SIMPLEQ_FIRST(head) ((head)->sqh_first) +#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next) + + +/* + * Tail queue definitions. + */ +#define _TAILQ_HEAD(name, type, qual) \ +struct name { \ + qual type *tqh_first; /* first element */ \ + qual type *qual *tqh_last; /* addr of last next element */ \ +} +#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,) + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define _TAILQ_ENTRY(type, qual) \ +struct { \ + qual type *tqe_next; /* next element */ \ + qual type *qual *tqe_prev; /* address of previous next element */\ +} +#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ +} while (/*CONSTCOND*/0) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = ((head)->tqh_first); \ + (var); \ + (var) = ((var)->field.tqe_next)) + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last)); \ + (var); \ + (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last))) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (/*CONSTCOND*/0) + +/* + * Tail queue access methods. + */ +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) + + +/* + * Circular queue definitions. + */ +#define CIRCLEQ_HEAD(name, type) \ +struct name { \ + struct type *cqh_first; /* first element */ \ + struct type *cqh_last; /* last element */ \ +} + +#define CIRCLEQ_HEAD_INITIALIZER(head) \ + { (void *)&head, (void *)&head } + +#define CIRCLEQ_ENTRY(type) \ +struct { \ + struct type *cqe_next; /* next element */ \ + struct type *cqe_prev; /* previous element */ \ +} + +/* + * Circular queue functions. + */ +#define CIRCLEQ_INIT(head) do { \ + (head)->cqh_first = (void *)(head); \ + (head)->cqh_last = (void *)(head); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm)->field.cqe_next; \ + (elm)->field.cqe_prev = (listelm); \ + if ((listelm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (listelm)->field.cqe_next->field.cqe_prev = (elm); \ + (listelm)->field.cqe_next = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \ + (elm)->field.cqe_next = (listelm); \ + (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \ + if ((listelm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (listelm)->field.cqe_prev->field.cqe_next = (elm); \ + (listelm)->field.cqe_prev = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \ + (elm)->field.cqe_next = (head)->cqh_first; \ + (elm)->field.cqe_prev = (void *)(head); \ + if ((head)->cqh_last == (void *)(head)) \ + (head)->cqh_last = (elm); \ + else \ + (head)->cqh_first->field.cqe_prev = (elm); \ + (head)->cqh_first = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.cqe_next = (void *)(head); \ + (elm)->field.cqe_prev = (head)->cqh_last; \ + if ((head)->cqh_first == (void *)(head)) \ + (head)->cqh_first = (elm); \ + else \ + (head)->cqh_last->field.cqe_next = (elm); \ + (head)->cqh_last = (elm); \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_REMOVE(head, elm, field) do { \ + if ((elm)->field.cqe_next == (void *)(head)) \ + (head)->cqh_last = (elm)->field.cqe_prev; \ + else \ + (elm)->field.cqe_next->field.cqe_prev = \ + (elm)->field.cqe_prev; \ + if ((elm)->field.cqe_prev == (void *)(head)) \ + (head)->cqh_first = (elm)->field.cqe_next; \ + else \ + (elm)->field.cqe_prev->field.cqe_next = \ + (elm)->field.cqe_next; \ +} while (/*CONSTCOND*/0) + +#define CIRCLEQ_FOREACH(var, head, field) \ + for ((var) = ((head)->cqh_first); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_next)) + +#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \ + for ((var) = ((head)->cqh_last); \ + (var) != (const void *)(head); \ + (var) = ((var)->field.cqe_prev)) + +/* + * Circular queue access methods. + */ +#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head)) +#define CIRCLEQ_FIRST(head) ((head)->cqh_first) +#define CIRCLEQ_LAST(head) ((head)->cqh_last) +#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next) +#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev) + +#define CIRCLEQ_LOOP_NEXT(head, elm, field) \ + (((elm)->field.cqe_next == (void *)(head)) \ + ? ((head)->cqh_first) \ + : (elm->field.cqe_next)) +#define CIRCLEQ_LOOP_PREV(head, elm, field) \ + (((elm)->field.cqe_prev == (void *)(head)) \ + ? ((head)->cqh_last) \ + : (elm->field.cqe_prev)) + +#endif /* sys/queue.h */ diff --git a/openair-cn/UTILS/signals.c b/openair-cn/UTILS/signals.c new file mode 100644 index 0000000000..51890496d2 --- /dev/null +++ b/openair-cn/UTILS/signals.c @@ -0,0 +1,132 @@ +/******************************************************************************* + + Eurecom OpenAirInterface + Copyright(c) 1999 - 2013 Eurecom + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + + The full GNU General Public License is included in this distribution in + the file called "COPYING". + + Contact Information + Openair Admin: openair_admin@eurecom.fr + Openair Tech : openair_tech@eurecom.fr + Forums : http://forums.eurecom.fr/openairinterface + Address : EURECOM, Campus SophiaTech, 450 Route des Chappes + 06410 Biot FRANCE + +*******************************************************************************/ + +#if HAVE_CONFIG_H +# include "config.h" +#endif + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <signal.h> +#include <time.h> +#include <errno.h> + +#include "intertask_interface.h" +#include "assertions.h" +#include "timer.h" +#include "backtrace.h" + +#include "signals.h" + +sigset_t set; + +int signal_init(void) +{ + /* We set the signal mask to avoid threads other than the main thread + * to receive the timer signal. Note that threads created will inherit this + * configuration. + */ + sigemptyset(&set); + + sigaddset (&set, SIGTIMER); + sigaddset (&set, SIGABRT); + sigaddset (&set, SIGSEGV); + sigaddset (&set, SIGINT); + + if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) { + perror ("sigprocmask"); + return -1; + } + + return 0; +} + +extern int timer_handle_signal(siginfo_t *info); + +int signal_handle(void) +{ + int ret; + siginfo_t info; + + sigemptyset(&set); + + sigaddset (&set, SIGTIMER); + sigaddset (&set, SIGABRT); + sigaddset (&set, SIGSEGV); + sigaddset (&set, SIGINT); + + if (sigprocmask(SIG_BLOCK, &set, NULL) < 0) { + perror ("sigprocmask"); + return -1; + } + + /* Block till a signal is received. + * NOTE: The signals defined by set are required to be blocked at the time + * of the call to sigwait() otherwise sigwait() is not successful. + */ + if ((ret = sigwaitinfo(&set, &info)) == -1) { + perror ("sigwait"); + return ret; + } + +// printf("Received signal %d\n", info.si_signo); + + /* Real-time signals are non constant and are therefore not suitable for + * use in switch. + */ + if (info.si_signo == SIGTIMER) { + timer_handle_signal(&info); + } else { + /* Dispatch the signal to sub-handlers */ + switch(info.si_signo) { + case SIGSEGV: /* Fall through */ + case SIGABRT: + printf("Received SIGABORT\n"); + backtrace_handle_signal(&info); + break; + case SIGQUIT: + case SIGINT: + printf("Received SIGINT\n"); + intertask_interface_send_quit_signal(); + printf("All tasks terminated -> exiting '"PACKAGE_NAME"'\n"); + exit(0); + break; + default: + printf("Received unknown signal %d\n", info.si_signo); + break; + } + } + + return 0; +} diff --git a/openair-cn/UTILS/signals.h b/openair-cn/UTILS/signals.h new file mode 100644 index 0000000000..2a56e71841 --- /dev/null +++ b/openair-cn/UTILS/signals.h @@ -0,0 +1,8 @@ +#ifndef SIGNALS_H_ +#define SIGNALS_H_ + +int signal_init(void); + +int signal_handle(void); + +#endif /* SIGNALS_H_ */ diff --git a/openair-cn/UTILS/tree.h b/openair-cn/UTILS/tree.h new file mode 100644 index 0000000000..8e4e35c408 --- /dev/null +++ b/openair-cn/UTILS/tree.h @@ -0,0 +1,678 @@ +/* + * Copyright 2002 Niels Provos <provos@citi.umich.edu> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root))) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-back tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field))) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field))) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field))) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ +void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +struct type *name##_RB_REMOVE(struct name *, struct type *); \ +struct type *name##_RB_INSERT(struct name *, struct type *); \ +struct type *name##_RB_FIND(struct name *, struct type *); \ +struct type *name##_RB_NEXT(struct type *); \ +struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ +void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)))\ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)))\ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field))) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field))); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + { \ + RB_ROOT(head) = elm; \ + } \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/openair-cn/aclocal.m4 b/openair-cn/aclocal.m4 new file mode 100644 index 0000000000..97239a262c --- /dev/null +++ b/openair-cn/aclocal.m4 @@ -0,0 +1,9895 @@ +# generated automatically by aclocal 1.11.3 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.68],, +[m4_warning([this file was generated for autoconf 2.68. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to <bug-libtool@gnu.org>." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$lt_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +_LT_PATH_LD_GNU +AC_SUBST([LD]) + +_LT_TAGDECL([], [LD], [1], [The linker used to build libraries]) +])# LT_PATH_LD + +# Old names: +AU_ALIAS([AM_PROG_LD], [LT_PATH_LD]) +AU_ALIAS([AC_PROG_LD], [LT_PATH_LD]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_LD], []) +dnl AC_DEFUN([AC_PROG_LD], []) + + +# _LT_PATH_LD_GNU +#- -------------- +m4_defun([_LT_PATH_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac]) +with_gnu_ld=$lt_cv_prog_gnu_ld +])# _LT_PATH_LD_GNU + + +# _LT_CMD_RELOAD +# -------------- +# find reload flag for linker +# -- PORTME Some linkers may need a different reload flag. +m4_defun([_LT_CMD_RELOAD], +[AC_CACHE_CHECK([for $LD option to reload object files], + lt_cv_ld_reload_flag, + [lt_cv_ld_reload_flag='-r']) +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac +_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl +_LT_TAGDECL([], [reload_cmds], [2])dnl +])# _LT_CMD_RELOAD + + +# _LT_CHECK_MAGIC_METHOD +# ---------------------- +# how to check for library dependencies +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_MAGIC_METHOD], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +AC_CACHE_CHECK([how to recognize dependent libraries], +lt_cv_deplibs_check_method, +[lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[[4-9]]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[[45]]*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + _LT_TAGVAR(link_all_deplibs, $1)=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + _LT_TAGVAR(link_all_deplibs, $1)=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS + +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) + +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) + +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) + +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) + +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 1 (pkg-config-0.24) +# +# Copyright © 2004 Scott James Remnant <scott@netsplit.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# PKG_PROG_PKG_CONFIG([MIN-VERSION]) +# ---------------------------------- +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])# PKG_PROG_PKG_CONFIG + +# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +# +# Check to see whether a particular set of modules exists. Similar +# to PKG_CHECK_MODULES(), but does not set variables or print errors. +# +# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +# only at the first occurence in configure.ac, so if the first place +# it's called might be skipped (such as if it is within an "if", you +# have to call PKG_CHECK_EXISTS manually +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +# --------------------------------------------- +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])# _PKG_CONFIG + +# _PKG_SHORT_ERRORS_SUPPORTED +# ----------------------------- +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])# _PKG_SHORT_ERRORS_SUPPORTED + + +# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +# [ACTION-IF-NOT-FOUND]) +# +# +# Note that if there is a possibility the first call to +# PKG_CHECK_MODULES might not happen, you should be sure to include an +# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +# +# +# -------------------------------------------------------------- +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $1]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])# PKG_CHECK_MODULES + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.3], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.3])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_COND_IF -*- Autoconf -*- + +# Copyright (C) 2008, 2010 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_COND_IF +# _AM_COND_ELSE +# _AM_COND_ENDIF +# -------------- +# These macros are only used for tracing. +m4_define([_AM_COND_IF]) +m4_define([_AM_COND_ELSE]) +m4_define([_AM_COND_ENDIF]) + + +# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE]) +# --------------------------------------- +# If the shell condition COND is true, execute IF-TRUE, otherwise execute +# IF-FALSE. Allow automake to learn about conditional instantiating macros +# (the AC_CONFIG_FOOS). +AC_DEFUN([AM_COND_IF], +[m4_ifndef([_AM_COND_VALUE_$1], + [m4_fatal([$0: no such condition "$1"])])dnl +_AM_COND_IF([$1])dnl +if test -z "$$1_TRUE"; then : + m4_n([$2])[]dnl +m4_ifval([$3], +[_AM_COND_ELSE([$1])dnl +else + $3 +])dnl +_AM_COND_ENDIF([$1])dnl +fi[]dnl +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, +# 2010, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_PROG_LEX +# ----------- +# Autoconf leaves LEX=: if lex or flex can't be found. Change that to a +# "missing" invocation, for better error output. +AC_DEFUN([AM_PROG_LEX], +[AC_PREREQ(2.50)dnl +AC_REQUIRE([AM_MISSING_HAS_RUN])dnl +AC_REQUIRE([AC_PROG_LEX])dnl +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, +# 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2009, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# AM_SILENT_RULES([DEFAULT]) +# -------------------------- +# Enable less verbose build rules; with the default set to DEFAULT +# (`yes' being less verbose, `no' or empty being verbose). +AC_DEFUN([AM_SILENT_RULES], +[AC_ARG_ENABLE([silent-rules], +[ --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0')]) +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; +esac +dnl +dnl A few `make' implementations (e.g., NonStop OS and NextStep) +dnl do not support nested variable expansions. +dnl See automake bug#9928 and bug#10237. +am_make=${MAKE-make} +AC_CACHE_CHECK([whether $am_make supports nested variables], + [am_cv_make_support_nested_variables], + [if AS_ECHO([['TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi]) +if test $am_cv_make_support_nested_variables = yes; then + dnl Using `$V' instead of `$(V)' breaks IRIX make. + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AC_SUBST([AM_V])dnl +AM_SUBST_NOTMAKE([AM_V])dnl +AC_SUBST([AM_DEFAULT_V])dnl +AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl +AC_SUBST([AM_DEFAULT_VERBOSITY])dnl +AM_BACKSLASH='\' +AC_SUBST([AM_BACKSLASH])dnl +_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl +]) + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/openair-cn/autogen.sh b/openair-cn/autogen.sh new file mode 100755 index 0000000000..dc425bedc0 --- /dev/null +++ b/openair-cn/autogen.sh @@ -0,0 +1,8 @@ +#! /bin/sh + +(cd GTPV2-C/nwgtpv2c-0.11 && libtoolize && autoreconf --install --force) + +aclocal \ +&& autoheader \ +&& automake --add-missing \ +&& autoconf \ No newline at end of file diff --git a/openair-cn/compile b/openair-cn/compile new file mode 100644 index 0000000000..7b4a9a7e1e --- /dev/null +++ b/openair-cn/compile @@ -0,0 +1,342 @@ +#! /bin/sh +# Wrapper for compilers which do not understand '-c -o'. + +scriptversion=2012-03-05.13; # UTC + +# Copyright (C) 1999-2012 Free Software Foundation, Inc. +# Written by Tom Tromey <tromey@cygnus.com>. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# This file is maintained in Automake, please report +# bugs to <bug-automake@gnu.org> or send patches to +# <automake-patches@gnu.org>. + +nl=' +' + +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent tools from complaining about whitespace usage. +IFS=" "" $nl" + +file_conv= + +# func_file_conv build_file lazy +# Convert a $build file to $host form and store it in $file +# Currently only supports Windows hosts. If the determined conversion +# type is listed in (the comma separated) LAZY, no conversion will +# take place. +func_file_conv () +{ + file=$1 + case $file in + / | /[!/]*) # absolute file, and not a UNC file + if test -z "$file_conv"; then + # lazily determine how to convert abs files + case `uname -s` in + MINGW*) + file_conv=mingw + ;; + CYGWIN*) + file_conv=cygwin + ;; + *) + file_conv=wine + ;; + esac + fi + case $file_conv/,$2, in + *,$file_conv,*) + ;; + mingw/*) + file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` + ;; + cygwin/*) + file=`cygpath -m "$file" || echo "$file"` + ;; + wine/*) + file=`winepath -w "$file" || echo "$file"` + ;; + esac + ;; + esac +} + +# func_cl_dashL linkdir +# Make cl look for libraries in LINKDIR +func_cl_dashL () +{ + func_file_conv "$1" + if test -z "$lib_path"; then + lib_path=$file + else + lib_path="$lib_path;$file" + fi + linker_opts="$linker_opts -LIBPATH:$file" +} + +# func_cl_dashl library +# Do a library search-path lookup for cl +func_cl_dashl () +{ + lib=$1 + found=no + save_IFS=$IFS + IFS=';' + for dir in $lib_path $LIB + do + IFS=$save_IFS + if $shared && test -f "$dir/$lib.dll.lib"; then + found=yes + lib=$dir/$lib.dll.lib + break + fi + if test -f "$dir/$lib.lib"; then + found=yes + lib=$dir/$lib.lib + break + fi + done + IFS=$save_IFS + + if test "$found" != yes; then + lib=$lib.lib + fi +} + +# func_cl_wrapper cl arg... +# Adjust compile command to suit cl +func_cl_wrapper () +{ + # Assume a capable shell + lib_path= + shared=: + linker_opts= + for arg + do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + eat=1 + case $2 in + *.o | *.[oO][bB][jJ]) + func_file_conv "$2" + set x "$@" -Fo"$file" + shift + ;; + *) + func_file_conv "$2" + set x "$@" -Fe"$file" + shift + ;; + esac + ;; + -I) + eat=1 + func_file_conv "$2" mingw + set x "$@" -I"$file" + shift + ;; + -I*) + func_file_conv "${1#-I}" mingw + set x "$@" -I"$file" + shift + ;; + -l) + eat=1 + func_cl_dashl "$2" + set x "$@" "$lib" + shift + ;; + -l*) + func_cl_dashl "${1#-l}" + set x "$@" "$lib" + shift + ;; + -L) + eat=1 + func_cl_dashL "$2" + ;; + -L*) + func_cl_dashL "${1#-L}" + ;; + -static) + shared=false + ;; + -Wl,*) + arg=${1#-Wl,} + save_ifs="$IFS"; IFS=',' + for flag in $arg; do + IFS="$save_ifs" + linker_opts="$linker_opts $flag" + done + IFS="$save_ifs" + ;; + -Xlinker) + eat=1 + linker_opts="$linker_opts $2" + ;; + -*) + set x "$@" "$1" + shift + ;; + *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) + func_file_conv "$1" + set x "$@" -Tp"$file" + shift + ;; + *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) + func_file_conv "$1" mingw + set x "$@" "$file" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift + done + if test -n "$linker_opts"; then + linker_opts="-link$linker_opts" + fi + exec "$@" $linker_opts + exit 1 +} + +eat= + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: compile [--help] [--version] PROGRAM [ARGS] + +Wrapper for compilers which do not understand '-c -o'. +Remove '-o dest.o' from ARGS, run PROGRAM with the remaining +arguments, and rename the output as expected. + +If you are trying to build a whole package this is not the +right script to run: please start by reading the file 'INSTALL'. + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "compile $scriptversion" + exit $? + ;; + cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) + func_cl_wrapper "$@" # Doesn't return... + ;; +esac + +ofile= +cfile= + +for arg +do + if test -n "$eat"; then + eat= + else + case $1 in + -o) + # configure might choose to run compile as 'compile cc -o foo foo.c'. + # So we strip '-o arg' only if arg is an object. + eat=1 + case $2 in + *.o | *.obj) + ofile=$2 + ;; + *) + set x "$@" -o "$2" + shift + ;; + esac + ;; + *.c) + cfile=$1 + set x "$@" "$1" + shift + ;; + *) + set x "$@" "$1" + shift + ;; + esac + fi + shift +done + +if test -z "$ofile" || test -z "$cfile"; then + # If no '-o' option was seen then we might have been invoked from a + # pattern rule where we don't need one. That is ok -- this is a + # normal compilation that the losing compiler can handle. If no + # '.c' file was seen then we are probably linking. That is also + # ok. + exec "$@" +fi + +# Name of file we expect compiler to create. +cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` + +# Create the lock directory. +# Note: use '[/\\:.-]' here to ensure that we don't use the same name +# that we are using for the .o file. Also, base the name on the expected +# object file name, since that is what matters with a parallel build. +lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d +while true; do + if mkdir "$lockdir" >/dev/null 2>&1; then + break + fi + sleep 1 +done +# FIXME: race condition here if user kills between mkdir and trap. +trap "rmdir '$lockdir'; exit 1" 1 2 15 + +# Run the compile. +"$@" +ret=$? + +if test -f "$cofile"; then + test "$cofile" = "$ofile" || mv "$cofile" "$ofile" +elif test -f "${cofile}bj"; then + test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" +fi + +rmdir "$lockdir" +exit $ret + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/openair-cn/config.guess b/openair-cn/config.guess new file mode 100644 index 0000000000..d622a44e55 --- /dev/null +++ b/openair-cn/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to <config-patches@gnu.org> and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +and + http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <config-patches@gnu.org> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/openair-cn/config.h.in b/openair-cn/config.h.in new file mode 100644 index 0000000000..f3e3ed2d2c --- /dev/null +++ b/openair-cn/config.h.in @@ -0,0 +1,331 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* asn1c minimum version */ +#undef ASN1_MINIMUM_VERSION + +/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP + systems. This function is required for `alloca.c' support on those systems. + */ +#undef CRAY_STACKSEG_END + +/* Define to 1 if using `alloca.c'. */ +#undef C_ALLOCA + +/* freeDiameter minimum version */ +#undef FREE_DIAMETER_MINIMUM_VERSION + +/* Define to 1 if you have gnutls 2.10 installed */ +#undef GNUTLS_VERSION_210 + +/* Define to 1 if you have gnutls 3.0 installed */ +#undef GNUTLS_VERSION_300 + +/* Define to 1 if you have gnutls 3.1 installed */ +#undef GNUTLS_VERSION_310 + +/* Define to 1 if you have AI_ADDRCONFIG defined in netdb.h */ +#undef HAVE_AI_ADDRCONFIG + +/* Define to 1 if you have `alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). + */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the <arpa/inet.h> header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have clock_gettime in librt */ +#undef HAVE_CLOCK_GETTIME + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the <float.h> header file. */ +#undef HAVE_FLOAT_H + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `getpagesize' function. */ +#undef HAVE_GETPAGESIZE + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `fdcore' library (-lfdcore). */ +#undef HAVE_LIBFDCORE + +/* Define to 1 if you have the `fdproto' library (-lfdproto). */ +#undef HAVE_LIBFDPROTO + +/* Define to 1 if you have the <libintl.h> header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have the `netfilter_queue' library (-lnetfilter_queue). + */ +#undef HAVE_LIBNETFILTER_QUEUE + +/* Define to 1 if you have the `nfnetlink' library (-lnfnetlink). */ +#undef HAVE_LIBNFNETLINK + +/* Define to 1 if you have the `pcap' library (-lpcap). */ +#undef HAVE_LIBPCAP + +/* Define to 1 if you have the `pthread' library (-lpthread). */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the `rt' library (-lrt). */ +#undef HAVE_LIBRT + +/* Define to 1 if you have the `sctp' library (-lsctp). */ +#undef HAVE_LIBSCTP + +/* Define to 1 if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if your system has a GNU libc compatible `malloc' function, and + to 0 otherwise. */ +#undef HAVE_MALLOC + +/* Define to 1 if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memchr' function. */ +#undef HAVE_MEMCHR + +/* Define to 1 if you have the `memmove' function. */ +#undef HAVE_MEMMOVE + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have a working `mmap' system call. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the `munmap' function. */ +#undef HAVE_MUNMAP + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the `ntohll' function. */ +#undef HAVE_NTOHLL + +/* Define to 1 if you have pthread_barrier_wait in libpthread */ +#undef HAVE_PTHREAD_BAR + +/* Define to 1 if the system has the type `ptrdiff_t'. */ +#undef HAVE_PTRDIFF_T + +/* Define to 1 if your system has a GNU libc compatible `realloc' function, + and to 0 otherwise. */ +#undef HAVE_REALLOC + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define to 1 if you have the <signalent.h> header file. */ +#undef HAVE_SIGNALENT_H + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the <stddef.h> header file. */ +#undef HAVE_STDDEF_H + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strndup' function. */ +#undef HAVE_STRNDUP + +/* Define to 1 if you have the `strspn' function. */ +#undef HAVE_STRSPN + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if sctp_connectx function accepts 4 arguments */ +#undef SCTP_CONNECTX_4_ARGS + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* SVN Revision */ +#undef SVN_REVISION + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define for Solaris 2.5.1 so the uint32_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT32_T + +/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT64_T + +/* Define for Solaris 2.5.1 so the uint8_t typedef from <sys/synch.h>, + <pthread.h>, or <semaphore.h> is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#undef _UINT8_T + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to the type of a signed integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef int16_t + +/* Define to the type of a signed integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef int32_t + +/* Define to the type of a signed integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef int64_t + +/* Define to the type of a signed integer type of width exactly 8 bits if such + a type exists and the standard includes do not define it. */ +#undef int8_t + +/* Define to rpl_malloc if the replacement function should be used. */ +#undef malloc + +/* Define to `long int' if <sys/types.h> does not define. */ +#undef off_t + +/* Define to rpl_realloc if the replacement function should be used. */ +#undef realloc + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> does not define. */ +#undef ssize_t + +/* Define to the type of an unsigned integer type of width exactly 16 bits if + such a type exists and the standard includes do not define it. */ +#undef uint16_t + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#undef uint32_t + +/* Define to the type of an unsigned integer type of width exactly 64 bits if + such a type exists and the standard includes do not define it. */ +#undef uint64_t + +/* Define to the type of an unsigned integer type of width exactly 8 bits if + such a type exists and the standard includes do not define it. */ +#undef uint8_t diff --git a/openair-cn/config.sub b/openair-cn/config.sub new file mode 100644 index 0000000000..c894da4550 --- /dev/null +++ b/openair-cn/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <http://www.gnu.org/licenses/>. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <config-patches@gnu.org>. Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <config-patches@gnu.org>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/openair-cn/configure b/openair-cn/configure new file mode 100755 index 0000000000..cba1d35cb8 --- /dev/null +++ b/openair-cn/configure @@ -0,0 +1,22230 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.68 for oaisim_mme 0.3.3851:3935M. +# +# Report bugs to <openair_admin@eurecom.fr>. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software +# Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + # Preserve -v and -x to the replacement shell. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; + esac + exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and +$0: openair_admin@eurecom.fr about your system, including +$0: any error possibly output before this message. Then +$0: install a modern shell, or manually run the script +$0: under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 </dev/null +exec 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='oaisim_mme' +PACKAGE_TARNAME='oaisim_mme' +PACKAGE_VERSION='0.3.3851:3935M' +PACKAGE_STRING='oaisim_mme 0.3.3851:3935M' +PACKAGE_BUGREPORT='openair_admin@eurecom.fr' +PACKAGE_URL='' + +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_header_list= +enable_option_checking=no +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +subdirs +HOSTNAME +HAVE_DOXYGEN_FALSE +HAVE_DOXYGEN_TRUE +HAVE_GCCXML_FALSE +HAVE_GCCXML_TRUE +HAVE_GCCXML +HAVE_CHECK_FALSE +HAVE_CHECK_TRUE +CHECK_LIBS +CHECK_CFLAGS +OPENSSL_LIBS +OPENSSL_CFLAGS +ASN1DIR +UPDATE_RELEASE_10_FALSE +UPDATE_RELEASE_10_TRUE +UPDATE_RELEASE_9_FALSE +UPDATE_RELEASE_9_TRUE +ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE +ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE +ENABLE_USE_NETFILTER_FOR_SGI_FALSE +ENABLE_USE_NETFILTER_FOR_SGI_TRUE +ENABLE_USE_PCAP_FOR_SGI_FALSE +ENABLE_USE_PCAP_FOR_SGI_TRUE +DISABLE_USE_NAS_FALSE +DISABLE_USE_NAS_TRUE +ADD_CFLAGS +ENABLE_USE_HSS_FALSE +ENABLE_USE_HSS_TRUE +STANDALONE_EPC_FALSE +STANDALONE_EPC_TRUE +nettle_LIBS +nettle_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +POW_LIB +ALLOCA +LIBOBJS +YFLAGS +YACC +CXXCPP +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +ASN1C_CHECK +HAVE_PDFLATEX_FALSE +HAVE_PDFLATEX_TRUE +PDFLATEX +DOXYGEN +CONFIGURE_DEPENDS +LEXLIB +LEX_OUTPUT_ROOT +LEX +CPP +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +EGREP +GREP +SED +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +LIBTOOL +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +AM_BACKSLASH +AM_DEFAULT_VERBOSITY +AM_DEFAULT_V +AM_V +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_silent_rules +enable_maintainer_mode +enable_shared +enable_static +with_pic +enable_fast_install +enable_dependency_tracking +with_gnu_ld +with_sysroot +enable_libtool_lock +enable_autoconf +enable_standalone_epc +enable_hss +enable_r8 +enable_r9 +enable_nas +enable_pcap_for_sgi +enable_netfilter_for_sgi +enable_raw_socket_for_sgi +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP +CXX +CXXFLAGS +CCC +CXXCPP +YACC +YFLAGS +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +nettle_CFLAGS +nettle_LIBS +OPENSSL_CFLAGS +OPENSSL_LIBS +CHECK_CFLAGS +CHECK_LIBS' +ac_subdirs_all='GTPV2-C/nwgtpv2c-0.11' + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used" >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures oaisim_mme 0.3.3851:3935M to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/oaisim_mme] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of oaisim_mme 0.3.3851:3935M:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-silent-rules less verbose build output (undo: `make V=1') + --disable-silent-rules verbose build output (undo: `make V=0') + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-libtool-lock avoid locking (might break parallel builds) + --disable-autoconf disable automatic generation of configure script + --enable-standalone-epc Compile MME, SGW and PGW in a single executable + --enable-hss Enable 3GPP S6A support + --enable-r8 Disable 3GPP release 9 and 10 updates + --enable-r9 Disable 3GPP release 10 updates + --disable-nas Disable NAS layer + --enable-pcap-for-sgi Enable PCAP for SGI layer + --enable-netfilter-for-sgi + Enable netfilter for SGI layer + --enable-raw-socket-for-sgi + Enable netfilter for SGI layer + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + YACC The `Yet Another Compiler Compiler' implementation to use. + Defaults to the first program found out of: `bison -y', `byacc', + `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + nettle_CFLAGS + C compiler flags for nettle, overriding pkg-config + nettle_LIBS linker flags for nettle, overriding pkg-config + OPENSSL_CFLAGS + C compiler flags for OPENSSL, overriding pkg-config + OPENSSL_LIBS + linker flags for OPENSSL, overriding pkg-config + CHECK_CFLAGS + C compiler flags for CHECK, overriding pkg-config + CHECK_LIBS linker flags for CHECK, overriding pkg-config + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to <openair_admin@eurecom.fr>. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +oaisim_mme configure 0.3.3851:3935M +generated by GNU Autoconf 2.68 + +Copyright (C) 2010 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case <limits.h> declares $2. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} +( $as_echo "## --------------------------------------- ## +## Report this to openair_admin@eurecom.fr ## +## --------------------------------------- ##" + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type + +# ac_fn_c_find_intX_t LINENO BITS VAR +# ----------------------------------- +# Finds a signed integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_intX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 +$as_echo_n "checking for int$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in int$2_t 'int' 'long int' \ + 'long long int' 'short int' 'signed char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default + enum { N = $2 / 2 - 1 }; +int +main () +{ +static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) + < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + case $ac_type in #( + int$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_intX_t + +# ac_fn_c_find_uintX_t LINENO BITS VAR +# ------------------------------------ +# Finds an unsigned integer type with width BITS, setting cache variable VAR +# accordingly. +ac_fn_c_find_uintX_t () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 +$as_echo_n "checking for uint$2_t... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + # Order is important - never check a type that is potentially smaller + # than half of the expected target width. + for ac_type in uint$2_t 'unsigned int' 'unsigned long int' \ + 'unsigned long long int' 'unsigned short int' 'unsigned char'; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ +static int test_array [1 - 2 * !((($ac_type) -1 >> ($2 / 2 - 1)) >> ($2 / 2 - 1) == 3)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + case $ac_type in #( + uint$2_t) : + eval "$3=yes" ;; #( + *) : + eval "$3=\$ac_type" ;; +esac +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if eval test \"x\$"$3"\" = x"no"; then : + +else + break +fi + done +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_find_uintX_t + +# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES +# --------------------------------------------- +# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR +# accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by oaisim_mme $as_me 0.3.3851:3935M, which was +generated by GNU Autoconf 2.68. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +as_fn_append ac_header_list " stdlib.h" +as_fn_append ac_header_list " unistd.h" +as_fn_append ac_header_list " sys/param.h" +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=1;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='oaisim_mme' + VERSION='0.3.3851:3935M' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + + + +ac_config_headers="$ac_config_headers config.h" + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# Check whether --enable-silent-rules was given. +if test "${enable_silent_rules+set}" = set; then : + enableval=$enable_silent_rules; +fi + +case $enable_silent_rules in +yes) AM_DEFAULT_VERBOSITY=0;; +no) AM_DEFAULT_VERBOSITY=1;; +*) AM_DEFAULT_VERBOSITY=0;; +esac +am_make=${MAKE-make} +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +$as_echo_n "checking whether $am_make supports nested variables... " >&6; } +if ${am_cv_make_support_nested_variables+:} false; then : + $as_echo_n "(cached) " >&6 +else + if $as_echo 'TRUE=$(BAR$(V)) +BAR0=false +BAR1=true +V=1 +am__doit: + @$(TRUE) +.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then + am_cv_make_support_nested_variables=yes +else + am_cv_make_support_nested_variables=no +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +$as_echo "$am_cv_make_support_nested_variables" >&6; } +if test $am_cv_make_support_nested_variables = yes; then + AM_V='$(V)' + AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' +else + AM_V=$AM_DEFAULT_VERBOSITY + AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY +fi +AM_BACKSLASH='\' + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdio.h> +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + link_all_deplibs=no + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd* | netbsdelf*-gnu) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#include <stdio.h> + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LEX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 +$as_echo "$LEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { yyless (input () != 0); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ { ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 +$as_echo_n "checking lex output file root... " >&6; } +if ${ac_cv_prog_lex_root+:} false; then : + $as_echo_n "(cached) " >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 +$as_echo "$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 +$as_echo_n "checking lex library... " >&6; } +if ${ac_cv_lib_lex+:} false; then : + $as_echo_n "(cached) " >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_lex=$ac_lib +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 +$as_echo "$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 +$as_echo_n "checking whether yytext is a pointer... " >&6; } +if ${ac_cv_prog_lex_yytext_pointer+:} false; then : + $as_echo_n "(cached) " >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + #define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_prog_lex_yytext_pointer=yes +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 +$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +if test "$LEX" = :; then + LEX=${am_missing_run}flex +fi + +# Check whether --enable-autoconf was given. +if test "${enable_autoconf+set}" = set; then : + enableval=$enable_autoconf; enable_autoconf=$enableval +else + enable_autoconf=yes + +fi + +# Extract the first word of "autoconf", so it can be a program name with args. +set dummy autoconf; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_AUTOCONF+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $AUTOCONF in + [\\/]* | ?:[\\/]*) + ac_cv_path_AUTOCONF="$AUTOCONF" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_AUTOCONF="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_AUTOCONF" && ac_cv_path_AUTOCONF="@echo autoconf not available" + ;; +esac +fi +AUTOCONF=$ac_cv_path_AUTOCONF +if test -n "$AUTOCONF"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOCONF" >&5 +$as_echo "$AUTOCONF" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# Extract the first word of "autoheader", so it can be a program name with args. +set dummy autoheader; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_AUTOHEADER+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $AUTOHEADER in + [\\/]* | ?:[\\/]*) + ac_cv_path_AUTOHEADER="$AUTOHEADER" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_AUTOHEADER="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_AUTOHEADER" && ac_cv_path_AUTOHEADER="@echo autoheader not available" + ;; +esac +fi +AUTOHEADER=$ac_cv_path_AUTOHEADER +if test -n "$AUTOHEADER"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AUTOHEADER" >&5 +$as_echo "$AUTOHEADER" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +if test -z "$AUTOCONF"; then enable_autoconf=no ; fi +if test -z "$AUTOHEADER"; then enable_autoconf=no ; fi +if test x$enable_autoconf = xyes; then + CONFIGURE_DEPENDS="configure.in aclocal.m4" +fi + + +for ac_prog in doxygen +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DOXYGEN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DOXYGEN"; then + ac_cv_prog_DOXYGEN="$DOXYGEN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_DOXYGEN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DOXYGEN=$ac_cv_prog_DOXYGEN +if test -n "$DOXYGEN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DOXYGEN" >&5 +$as_echo "$DOXYGEN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DOXYGEN" && break +done + +if test -z "$DOXYGEN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Doxygen not found - continuing without Doxygen support" >&5 +$as_echo "$as_me: WARNING: Doxygen not found - continuing without Doxygen support" >&2;} +else + # Check for presence of pdfLaTeX + # Extract the first word of "pdflatex", so it can be a program name with args. +set dummy pdflatex; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_PDFLATEX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$PDFLATEX"; then + ac_cv_prog_PDFLATEX="$PDFLATEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_PDFLATEX="pdflatex" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +PDFLATEX=$ac_cv_prog_PDFLATEX +if test -n "$PDFLATEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PDFLATEX" >&5 +$as_echo "$PDFLATEX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test -z "$PDFLATEX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to create PDF version of the user manual." >&5 +$as_echo "$as_me: WARNING: Unable to create PDF version of the user manual." >&2;} + fi +fi + if test -n "$PDFLATEX"; then + HAVE_PDFLATEX_TRUE= + HAVE_PDFLATEX_FALSE='#' +else + HAVE_PDFLATEX_TRUE='#' + HAVE_PDFLATEX_FALSE= +fi + + +# Extract the first word of "asn1c", so it can be a program name with args. +set dummy asn1c; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ASN1C_CHECK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ASN1C_CHECK"; then + ac_cv_prog_ASN1C_CHECK="$ASN1C_CHECK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ASN1C_CHECK="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_ASN1C_CHECK" && ac_cv_prog_ASN1C_CHECK="as_fn_error $? "Please install asn1c before going further." "$LINENO" 5" +fi +fi +ASN1C_CHECK=$ac_cv_prog_ASN1C_CHECK +if test -n "$ASN1C_CHECK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ASN1C_CHECK" >&5 +$as_echo "$ASN1C_CHECK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + +# Checks for programs. +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if ${ac_cv_cxx_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if ${ac_cv_prog_cxx_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CXX_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + + +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf + + if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if ${ac_cv_prog_CXXCPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +else + _lt_caught_CXX_error=yes +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + +archive_cmds_need_lc_CXX=no +allow_undefined_flag_CXX= +always_export_symbols_CXX=no +archive_expsym_cmds_CXX= +compiler_needs_object_CXX=no +export_dynamic_flag_spec_CXX= +hardcode_direct_CXX=no +hardcode_direct_absolute_CXX=no +hardcode_libdir_flag_spec_CXX= +hardcode_libdir_separator_CXX= +hardcode_minus_L_CXX=no +hardcode_shlibpath_var_CXX=unsupported +hardcode_automatic_CXX=no +inherit_rpath_CXX=no +module_cmds_CXX= +module_expsym_cmds_CXX= +link_all_deplibs_CXX=unknown +old_archive_cmds_CXX=$old_archive_cmds +reload_flag_CXX=$reload_flag +reload_cmds_CXX=$reload_cmds +no_undefined_flag_CXX= +whole_archive_flag_spec_CXX= +enable_shared_with_static_runtimes_CXX=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +objext_CXX=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + + # save warnings/boilerplate of simple test code + ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + + ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + compiler_CXX=$CC + for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin' + else + lt_prog_compiler_no_builtin_flag_CXX= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break + ;; + *) + test "$with_gnu_ld" != yes && break + ;; + esac + fi + done + IFS="$lt_save_ifs" +else + lt_cv_path_LD="$LD" # Let the user override the test with a path. +fi +fi + +LD="$lt_cv_path_LD" +if test -n "$LD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 </dev/null` in +*GNU* | *'with BFD'*) + lt_cv_prog_gnu_ld=yes + ;; +*) + lt_cv_prog_gnu_ld=no + ;; +esac +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec_CXX= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + ld_shlibs_CXX=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds_CXX='' + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + file_list_spec_CXX='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct_CXX=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L_CXX=yes + hardcode_libdir_flag_spec_CXX='-L$libdir' + hardcode_libdir_separator_CXX= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec_CXX='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + always_export_symbols_CXX=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag_CXX='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + + archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag_CXX="-z nodefs" + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath__CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath__CXX"; then + lt_cv_aix_libpath__CXX="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath__CXX +fi + + hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag_CXX=' ${wl}-bernotok' + allow_undefined_flag_CXX=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec_CXX='$convenience' + fi + archive_cmds_need_lc_CXX=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag_CXX=unsupported + # Joseph Beckenbach <jrb3@best.com> says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs_CXX=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + hardcode_libdir_flag_spec_CXX=' ' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=yes + file_list_spec_CXX='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true' + enable_shared_with_static_runtimes_CXX=yes + # Don't use ranlib + old_postinstall_cmds_CXX='chmod 644 $oldlib' + postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec_CXX='-L$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-all-symbols' + allow_undefined_flag_CXX=unsupported + always_export_symbols_CXX=no + enable_shared_with_static_runtimes_CXX=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs_CXX=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + + + archive_cmds_need_lc_CXX=no + hardcode_direct_CXX=no + hardcode_automatic_CXX=yes + hardcode_shlibpath_var_CXX=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec_CXX='' + fi + link_all_deplibs_CXX=yes + allow_undefined_flag_CXX="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + if test "$lt_cv_apple_cc_single_mod" != "yes"; then + archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi + + else + ld_shlibs_CXX=no + fi + + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + ld_shlibs_CXX=no + ;; + + freebsd-elf*) + archive_cmds_need_lc_CXX=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + ld_shlibs_CXX=yes + ;; + + gnu*) + ;; + + haiku*) + archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs_CXX=yes + ;; + + hpux9*) + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + export_dynamic_flag_spec_CXX='${wl}-E' + hardcode_direct_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + export_dynamic_flag_spec_CXX='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + ;; + *) + hardcode_direct_CXX=yes + hardcode_direct_absolute_CXX=yes + hardcode_minus_L_CXX=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + interix[3-9]*) + hardcode_direct_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + link_all_deplibs_CXX=yes + ;; + esac + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + inherit_rpath_CXX=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + archive_cmds_need_lc_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [1-5].* | *pgcpp\ [1-5].*) + prelink_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + old_archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + archive_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec_CXX='${wl}--export-dynamic' + archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + hardcode_libdir_flag_spec_CXX='-R$libdir' + whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object_CXX=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + ld_shlibs_CXX=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + ld_shlibs_CXX=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct_CXX=yes + hardcode_shlibpath_var_CXX=no + hardcode_direct_absolute_CXX=yes + archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + export_dynamic_flag_spec_CXX='${wl}-E' + whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + ld_shlibs_CXX=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir' + hardcode_libdir_separator_CXX=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + cxx*) + case $host in + osf3*) + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + ;; + *) + allow_undefined_flag_CXX=' -expect_unresolved \*' + archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + hardcode_libdir_flag_spec_CXX='-rpath $libdir' + ;; + esac + + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator_CXX=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + archive_cmds_need_lc_CXX=yes + no_undefined_flag_CXX=' -zdefs' + archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + hardcode_libdir_flag_spec_CXX='-R$libdir' + hardcode_shlibpath_var_CXX=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract' + ;; + esac + link_all_deplibs_CXX=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + no_undefined_flag_CXX=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir' + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag_CXX='${wl}-z,text' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag_CXX='${wl}-z,text' + allow_undefined_flag_CXX='${wl}-z,nodefs' + archive_cmds_need_lc_CXX=no + hardcode_shlibpath_var_CXX=no + hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir' + hardcode_libdir_separator_CXX=':' + link_all_deplibs_CXX=yes + export_dynamic_flag_spec_CXX='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~ + '"$old_archive_cmds_CXX" + reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~ + '"$reload_cmds_CXX" + ;; + *) + archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + + *) + # FIXME: insert proper C++ library support + ld_shlibs_CXX=no + ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } + test "$ld_shlibs_CXX" = no && can_build_shared=no + + GCC_CXX="$GXX" + LD_CXX="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + # Dependencies to place before and after the object being linked: +predep_objects_CXX= +postdep_objects_CXX= +predeps_CXX= +postdeps_CXX= +compiler_lib_search_path_CXX= + +cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF + + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$compiler_lib_search_path_CXX"; then + compiler_lib_search_path_CXX="${prev}${p}" + else + compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$postdeps_CXX"; then + postdeps_CXX="${prev}${p}" + else + postdeps_CXX="${postdeps_CXX} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$predep_objects_CXX"; then + predep_objects_CXX="$p" + else + predep_objects_CXX="$predep_objects_CXX $p" + fi + else + if test -z "$postdep_objects_CXX"; then + postdep_objects_CXX="$p" + else + postdep_objects_CXX="$postdep_objects_CXX $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling CXX test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +case $host_os in +interix[3-9]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + predep_objects_CXX= + postdep_objects_CXX= + postdeps_CXX= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + postdeps_CXX='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac + + +case " $postdeps_CXX " in +*" -lc "*) archive_cmds_need_lc_CXX=no ;; +esac + compiler_lib_search_dirs_CXX= +if test -n "${compiler_lib_search_path_CXX}"; then + compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + lt_prog_compiler_wl_CXX= +lt_prog_compiler_pic_CXX= +lt_prog_compiler_static_CXX= + + + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic_CXX='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic_CXX='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + lt_prog_compiler_pic_CXX= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static_CXX= + ;; + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic_CXX=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + *) + lt_prog_compiler_pic_CXX='-fPIC' + ;; + esac + else + case $host_os in + aix[4-9]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static_CXX='-Bstatic' + else + lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic_CXX='-DDLL_EXPORT' + ;; + dgux*) + case $cc_basename in + ec++*) + lt_prog_compiler_pic_CXX='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + lt_prog_compiler_pic_CXX='+Z' + fi + ;; + aCC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic_CXX='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_static_CXX='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + lt_prog_compiler_wl_CXX='--backend -Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fPIC' + lt_prog_compiler_static_CXX='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-fpic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + xlc* | xlC* | bgxl[cC]* | mpixl[cC]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-qpic' + lt_prog_compiler_static_CXX='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + lt_prog_compiler_pic_CXX='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd* | netbsdelf*-gnu) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic_CXX='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + lt_prog_compiler_wl_CXX='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + lt_prog_compiler_pic_CXX='-pic' + ;; + cxx*) + # Digital/Compaq C++ + lt_prog_compiler_wl_CXX='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + lt_prog_compiler_pic_CXX= + lt_prog_compiler_static_CXX='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + lt_prog_compiler_wl_CXX='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + lt_prog_compiler_pic_CXX='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + lt_prog_compiler_pic_CXX='-pic' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + lcc*) + # Lucid + lt_prog_compiler_pic_CXX='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + lt_prog_compiler_wl_CXX='-Wl,' + lt_prog_compiler_pic_CXX='-KPIC' + lt_prog_compiler_static_CXX='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + lt_prog_compiler_pic_CXX='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + lt_prog_compiler_can_build_shared_CXX=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic_CXX= + ;; + *) + lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; } +lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; } +if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works_CXX=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works_CXX=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then + case $lt_prog_compiler_pic_CXX in + "" | " "*) ;; + *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;; + esac +else + lt_prog_compiler_pic_CXX= + lt_prog_compiler_can_build_shared_CXX=no +fi + +fi + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works_CXX=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works_CXX=yes + fi + else + lt_cv_prog_compiler_static_works_CXX=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; } + +if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then + : +else + lt_prog_compiler_static_CXX= +fi + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o_CXX=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o_CXX=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5 +$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + case $host_os in + aix[4-9]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + export_symbols_cmds_CXX="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + ;; + esac + ;; + linux* | k*bsd*-gnu | gnu*) + link_all_deplibs_CXX=no + ;; + *) + export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5 +$as_echo "$ld_shlibs_CXX" >&6; } +test "$ld_shlibs_CXX" = no && can_build_shared=no + +with_gnu_ld_CXX=$with_gnu_ld + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc_CXX" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc_CXX=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds_CXX in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl_CXX + pic_flag=$lt_prog_compiler_pic_CXX + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag_CXX + allow_undefined_flag_CXX= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc_CXX=no + else + lt_cv_archive_cmds_need_lc_CXX=yes + fi + allow_undefined_flag_CXX=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; } + archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib<name>.so + # instead of lib<name>.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsdelf*-gnu) + version_type=linux + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='NetBSD ld.elf_so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action_CXX= +if test -n "$hardcode_libdir_flag_spec_CXX" || + test -n "$runpath_var_CXX" || + test "X$hardcode_automatic_CXX" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct_CXX" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no && + test "$hardcode_minus_L_CXX" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action_CXX=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action_CXX=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action_CXX=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5 +$as_echo "$hardcode_action_CXX" >&6; } + +if test "$hardcode_action_CXX" = relink || + test "$inherit_rpath_CXX" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_YACC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +for ac_header in arpa/inet.h fcntl.h float.h inttypes.h limits.h malloc.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in netinet/in.h stddef.h stdint.h stdlib.h string.h libintl.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in sys/time.h sys/ioctl.h sys/socket.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +# Checks for library functions. + + + + for ac_header in $ac_header_list +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + +for ac_func in getpagesize +do : + ac_fn_c_check_func "$LINENO" "getpagesize" "ac_cv_func_getpagesize" +if test "x$ac_cv_func_getpagesize" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_GETPAGESIZE 1 +_ACEOF + +fi +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working mmap" >&5 +$as_echo_n "checking for working mmap... " >&6; } +if ${ac_cv_func_mmap_fixed_mapped+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_mmap_fixed_mapped=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +/* malloc might have been renamed as rpl_malloc. */ +#undef malloc + +/* Thanks to Mike Haertel and Jim Avera for this test. + Here is a matrix of mmap possibilities: + mmap private not fixed + mmap private fixed at somewhere currently unmapped + mmap private fixed at somewhere already mapped + mmap shared not fixed + mmap shared fixed at somewhere currently unmapped + mmap shared fixed at somewhere already mapped + For private mappings, we should verify that changes cannot be read() + back from the file, nor mmap's back from the file at a different + address. (There have been systems where private was not correctly + implemented like the infamous i386 svr4.0, and systems where the + VM page cache was not coherent with the file system buffer cache + like early versions of FreeBSD and possibly contemporary NetBSD.) + For shared mappings, we should conversely verify that changes get + propagated back to all the places they're supposed to be. + + Grep wants private fixed already mapped. + The main things grep needs to know about mmap are: + * does it exist and is it safe to write into the mmap'd area + * how to use it (BSD variants) */ + +#include <fcntl.h> +#include <sys/mman.h> + +#if !defined STDC_HEADERS && !defined HAVE_STDLIB_H +char *malloc (); +#endif + +/* This mess was copied from the GNU getpagesize.h. */ +#ifndef HAVE_GETPAGESIZE +# ifdef _SC_PAGESIZE +# define getpagesize() sysconf(_SC_PAGESIZE) +# else /* no _SC_PAGESIZE */ +# ifdef HAVE_SYS_PARAM_H +# include <sys/param.h> +# ifdef EXEC_PAGESIZE +# define getpagesize() EXEC_PAGESIZE +# else /* no EXEC_PAGESIZE */ +# ifdef NBPG +# define getpagesize() NBPG * CLSIZE +# ifndef CLSIZE +# define CLSIZE 1 +# endif /* no CLSIZE */ +# else /* no NBPG */ +# ifdef NBPC +# define getpagesize() NBPC +# else /* no NBPC */ +# ifdef PAGESIZE +# define getpagesize() PAGESIZE +# endif /* PAGESIZE */ +# endif /* no NBPC */ +# endif /* no NBPG */ +# endif /* no EXEC_PAGESIZE */ +# else /* no HAVE_SYS_PARAM_H */ +# define getpagesize() 8192 /* punt totally */ +# endif /* no HAVE_SYS_PARAM_H */ +# endif /* no _SC_PAGESIZE */ + +#endif /* no HAVE_GETPAGESIZE */ + +int +main () +{ + char *data, *data2, *data3; + const char *cdata2; + int i, pagesize; + int fd, fd2; + + pagesize = getpagesize (); + + /* First, make a file with some known garbage in it. */ + data = (char *) malloc (pagesize); + if (!data) + return 1; + for (i = 0; i < pagesize; ++i) + *(data + i) = rand (); + umask (0); + fd = creat ("conftest.mmap", 0600); + if (fd < 0) + return 2; + if (write (fd, data, pagesize) != pagesize) + return 3; + close (fd); + + /* Next, check that the tail of a page is zero-filled. File must have + non-zero length, otherwise we risk SIGBUS for entire page. */ + fd2 = open ("conftest.txt", O_RDWR | O_CREAT | O_TRUNC, 0600); + if (fd2 < 0) + return 4; + cdata2 = ""; + if (write (fd2, cdata2, 1) != 1) + return 5; + data2 = (char *) mmap (0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd2, 0L); + if (data2 == MAP_FAILED) + return 6; + for (i = 0; i < pagesize; ++i) + if (*(data2 + i)) + return 7; + close (fd2); + if (munmap (data2, pagesize)) + return 8; + + /* Next, try to mmap the file at a fixed address which already has + something else allocated at it. If we can, also make sure that + we see the same garbage. */ + fd = open ("conftest.mmap", O_RDWR); + if (fd < 0) + return 9; + if (data2 != mmap (data2, pagesize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_FIXED, fd, 0L)) + return 10; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data2 + i)) + return 11; + + /* Finally, make sure that changes to the mapped area do not + percolate back to the file as seen by read(). (This is a bug on + some variants of i386 svr4.0.) */ + for (i = 0; i < pagesize; ++i) + *(data2 + i) = *(data2 + i) + 1; + data3 = (char *) malloc (pagesize); + if (!data3) + return 12; + if (read (fd, data3, pagesize) != pagesize) + return 13; + for (i = 0; i < pagesize; ++i) + if (*(data + i) != *(data3 + i)) + return 14; + close (fd); + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_mmap_fixed_mapped=yes +else + ac_cv_func_mmap_fixed_mapped=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_mmap_fixed_mapped" >&5 +$as_echo "$ac_cv_func_mmap_fixed_mapped" >&6; } +if test $ac_cv_func_mmap_fixed_mapped = yes; then + +$as_echo "#define HAVE_MMAP 1" >>confdefs.h + +fi +rm -f conftest.mmap conftest.txt + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5 +$as_echo_n "checking for GNU libc compatible malloc... " >&6; } +if ${ac_cv_func_malloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_malloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include <stdlib.h> +#else +char *malloc (); +#endif + +int +main () +{ +return ! malloc (0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_malloc_0_nonnull=yes +else + ac_cv_func_malloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_malloc_0_nonnull" >&6; } +if test $ac_cv_func_malloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_MALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_MALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" malloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS malloc.$ac_objext" + ;; +esac + + +$as_echo "#define malloc rpl_malloc" >>confdefs.h + +fi + + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works +# for constant arguments. Useless! +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working alloca.h" >&5 +$as_echo_n "checking for working alloca.h... " >&6; } +if ${ac_cv_working_alloca_h+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <alloca.h> +int +main () +{ +char *p = (char *) alloca (2 * sizeof (int)); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_working_alloca_h=yes +else + ac_cv_working_alloca_h=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_working_alloca_h" >&5 +$as_echo "$ac_cv_working_alloca_h" >&6; } +if test $ac_cv_working_alloca_h = yes; then + +$as_echo "#define HAVE_ALLOCA_H 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alloca" >&5 +$as_echo_n "checking for alloca... " >&6; } +if ${ac_cv_func_alloca_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __GNUC__ +# define alloca __builtin_alloca +#else +# ifdef _MSC_VER +# include <malloc.h> +# define alloca _alloca +# else +# ifdef HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ +void *alloca (size_t); +# endif +# endif +# endif +# endif +#endif + +int +main () +{ +char *p = (char *) alloca (1); + if (p) return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_func_alloca_works=yes +else + ac_cv_func_alloca_works=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_alloca_works" >&5 +$as_echo "$ac_cv_func_alloca_works" >&6; } + +if test $ac_cv_func_alloca_works = yes; then + +$as_echo "#define HAVE_ALLOCA 1" >>confdefs.h + +else + # The SVR3 libPW and SVR4 libucb both contain incompatible functions +# that cause trouble. Some versions do not even contain alloca or +# contain a buggy version. If you still want to use their alloca, +# use ar to extract alloca.o from them instead of compiling alloca.c. + +ALLOCA=\${LIBOBJDIR}alloca.$ac_objext + +$as_echo "#define C_ALLOCA 1" >>confdefs.h + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether \`alloca.c' needs Cray hooks" >&5 +$as_echo_n "checking whether \`alloca.c' needs Cray hooks... " >&6; } +if ${ac_cv_os_cray+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined CRAY && ! defined CRAY2 +webecray +#else +wenotbecray +#endif + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "webecray" >/dev/null 2>&1; then : + ac_cv_os_cray=yes +else + ac_cv_os_cray=no +fi +rm -f conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_os_cray" >&5 +$as_echo "$ac_cv_os_cray" >&6; } +if test $ac_cv_os_cray = yes; then + for ac_func in _getb67 GETB67 getb67; do + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + +cat >>confdefs.h <<_ACEOF +#define CRAY_STACKSEG_END $ac_func +_ACEOF + + break +fi + + done +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking stack direction for C alloca" >&5 +$as_echo_n "checking stack direction for C alloca... " >&6; } +if ${ac_cv_c_stack_direction+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_c_stack_direction=0 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +find_stack_direction () +{ + static char *addr = 0; + auto char dummy; + if (addr == 0) + { + addr = &dummy; + return find_stack_direction (); + } + else + return (&dummy > addr) ? 1 : -1; +} + +int +main () +{ + return find_stack_direction () < 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_stack_direction=1 +else + ac_cv_c_stack_direction=-1 +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_stack_direction" >&5 +$as_echo "$ac_cv_c_stack_direction" >&6; } +cat >>confdefs.h <<_ACEOF +#define STACK_DIRECTION $ac_cv_c_stack_direction +_ACEOF + + +fi + +for ac_header in stdlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" +if test "x$ac_cv_header_stdlib_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_STDLIB_H 1 +_ACEOF + +fi + +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible realloc" >&5 +$as_echo_n "checking for GNU libc compatible realloc... " >&6; } +if ${ac_cv_func_realloc_0_nonnull+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_realloc_0_nonnull=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#if defined STDC_HEADERS || defined HAVE_STDLIB_H +# include <stdlib.h> +#else +char *realloc (); +#endif + +int +main () +{ +return ! realloc (0, 0); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_realloc_0_nonnull=yes +else + ac_cv_func_realloc_0_nonnull=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_realloc_0_nonnull" >&5 +$as_echo "$ac_cv_func_realloc_0_nonnull" >&6; } +if test $ac_cv_func_realloc_0_nonnull = yes; then : + +$as_echo "#define HAVE_REALLOC 1" >>confdefs.h + +else + $as_echo "#define HAVE_REALLOC 0" >>confdefs.h + + case " $LIBOBJS " in + *" realloc.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS realloc.$ac_objext" + ;; +esac + + +$as_echo "#define realloc rpl_realloc" >>confdefs.h + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for working strtod" >&5 +$as_echo_n "checking for working strtod... " >&6; } +if ${ac_cv_func_strtod+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + ac_cv_func_strtod=no +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +$ac_includes_default +#ifndef strtod +double strtod (); +#endif +int +main() +{ + { + /* Some versions of Linux strtod mis-parse strings with leading '+'. */ + char *string = " +69"; + char *term; + double value; + value = strtod (string, &term); + if (value != 69 || term != (string + 4)) + return 1; + } + + { + /* Under Solaris 2.4, strtod returns the wrong value for the + terminating character under some conditions. */ + char *string = "NaN"; + char *term; + strtod (string, &term); + if (term != string && *(term - 1) == 0) + return 1; + } + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_func_strtod=yes +else + ac_cv_func_strtod=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strtod" >&5 +$as_echo "$ac_cv_func_strtod" >&6; } +if test $ac_cv_func_strtod = no; then + case " $LIBOBJS " in + *" strtod.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS strtod.$ac_objext" + ;; +esac + +ac_fn_c_check_func "$LINENO" "pow" "ac_cv_func_pow" +if test "x$ac_cv_func_pow" = xyes; then : + +fi + +if test $ac_cv_func_pow = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pow in -lm" >&5 +$as_echo_n "checking for pow in -lm... " >&6; } +if ${ac_cv_lib_m_pow+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lm $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pow (); +int +main () +{ +return pow (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_m_pow=yes +else + ac_cv_lib_m_pow=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_pow" >&5 +$as_echo "$ac_cv_lib_m_pow" >&6; } +if test "x$ac_cv_lib_m_pow" = xyes; then : + POW_LIB=-lm +else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cannot find library containing definition of pow" >&5 +$as_echo "$as_me: WARNING: cannot find library containing definition of pow" >&2;} +fi + +fi + +fi + +for ac_func in ftruncate inet_ntoa memchr memmove memset munmap select socket +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in strdup strerror strspn strchr +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in gethostname gethostbyname +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +# Checks for typedefs, structures, and compiler characteristics. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + +ac_fn_c_find_intX_t "$LINENO" "8" "ac_cv_c_int8_t" +case $ac_cv_c_int8_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int8_t $ac_cv_c_int8_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "16" "ac_cv_c_int16_t" +case $ac_cv_c_int16_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int16_t $ac_cv_c_int16_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "32" "ac_cv_c_int32_t" +case $ac_cv_c_int32_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int32_t $ac_cv_c_int32_t +_ACEOF +;; +esac + +ac_fn_c_find_intX_t "$LINENO" "64" "ac_cv_c_int64_t" +case $ac_cv_c_int64_t in #( + no|yes) ;; #( + *) + +cat >>confdefs.h <<_ACEOF +#define int64_t $ac_cv_c_int64_t +_ACEOF +;; +esac + +ac_fn_c_check_type "$LINENO" "off_t" "ac_cv_type_off_t" "$ac_includes_default" +if test "x$ac_cv_type_off_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define off_t long int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" "$ac_includes_default" +if test "x$ac_cv_type_ssize_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define ssize_t int +_ACEOF + +fi + +ac_fn_c_find_uintX_t "$LINENO" "8" "ac_cv_c_uint8_t" +case $ac_cv_c_uint8_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT8_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint8_t $ac_cv_c_uint8_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "16" "ac_cv_c_uint16_t" +case $ac_cv_c_uint16_t in #( + no|yes) ;; #( + *) + + +cat >>confdefs.h <<_ACEOF +#define uint16_t $ac_cv_c_uint16_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "32" "ac_cv_c_uint32_t" +case $ac_cv_c_uint32_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT32_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint32_t $ac_cv_c_uint32_t +_ACEOF +;; + esac + +ac_fn_c_find_uintX_t "$LINENO" "64" "ac_cv_c_uint64_t" +case $ac_cv_c_uint64_t in #( + no|yes) ;; #( + *) + +$as_echo "#define _UINT64_T 1" >>confdefs.h + + +cat >>confdefs.h <<_ACEOF +#define uint64_t $ac_cv_c_uint64_t +_ACEOF +;; + esac + + +ac_fn_c_check_type "$LINENO" "ptrdiff_t" "ac_cv_type_ptrdiff_t" "$ac_includes_default" +if test "x$ac_cv_type_ptrdiff_t" = xyes; then : + +cat >>confdefs.h <<_ACEOF +#define HAVE_PTRDIFF_T 1 +_ACEOF + + +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sctp_sendmsg in -lsctp" >&5 +$as_echo_n "checking for sctp_sendmsg in -lsctp... " >&6; } +if ${ac_cv_lib_sctp_sctp_sendmsg+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsctp $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char sctp_sendmsg (); +int +main () +{ +return sctp_sendmsg (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_sctp_sctp_sendmsg=yes +else + ac_cv_lib_sctp_sctp_sendmsg=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sctp_sctp_sendmsg" >&5 +$as_echo "$ac_cv_lib_sctp_sctp_sendmsg" >&6; } +if test "x$ac_cv_lib_sctp_sctp_sendmsg" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSCTP 1 +_ACEOF + + LIBS="-lsctp $LIBS" + +else + as_fn_error $? "libsctp-dev needed!" "$LINENO" 5 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_mutex_init in -lpthread" >&5 +$as_echo_n "checking for pthread_mutex_init in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_mutex_init+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_mutex_init (); +int +main () +{ +return pthread_mutex_init (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_mutex_init=yes +else + ac_cv_lib_pthread_pthread_mutex_init=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_mutex_init" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_mutex_init" >&6; } +if test "x$ac_cv_lib_pthread_pthread_mutex_init" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +else + as_fn_error $? "pthread library needed!" "$LINENO" 5 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for timer_create in -lrt" >&5 +$as_echo_n "checking for timer_create in -lrt... " >&6; } +if ${ac_cv_lib_rt_timer_create+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char timer_create (); +int +main () +{ +return timer_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_timer_create=yes +else + ac_cv_lib_rt_timer_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_timer_create" >&5 +$as_echo "$ac_cv_lib_rt_timer_create" >&6; } +if test "x$ac_cv_lib_rt_timer_create" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRT 1 +_ACEOF + + LIBS="-lrt $LIBS" + +else + as_fn_error $? "rt library needed!" "$LINENO" 5 +fi + + + + + + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +$as_echo "$ac_pt_PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + PKG_CONFIG="" + fi +fi + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nettle" >&5 +$as_echo_n "checking for nettle... " >&6; } + +if test -n "$nettle_CFLAGS"; then + pkg_cv_nettle_CFLAGS="$nettle_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nettle >= 2.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "nettle >= 2.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_nettle_CFLAGS=`$PKG_CONFIG --cflags "nettle >= 2.5" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$nettle_LIBS"; then + pkg_cv_nettle_LIBS="$nettle_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"nettle >= 2.5\""; } >&5 + ($PKG_CONFIG --exists --print-errors "nettle >= 2.5") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_nettle_LIBS=`$PKG_CONFIG --libs "nettle >= 2.5" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + nettle_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "nettle >= 2.5" 2>&1` + else + nettle_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "nettle >= 2.5" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$nettle_PKG_ERRORS" >&5 + + as_fn_error $? "\"Please install nettle >= 2.5\"" "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "\"Please install nettle >= 2.5\"" "$LINENO" 5 +else + nettle_CFLAGS=$pkg_cv_nettle_CFLAGS + nettle_LIBS=$pkg_cv_nettle_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_NETTLE=true +fi +CFLAGS="$CFLAGS $nettle_CFLAGS" +LIBS="$LIBS $nettle_LIBS" + +# Check whether --enable-standalone-epc was given. +if test "${enable_standalone_epc+set}" = set; then : + enableval=$enable_standalone_epc; +else + STANDALONE_EPC="yes" +fi + + if test "x$enable_standalone_epc" = "xyes"; then + STANDALONE_EPC_TRUE= + STANDALONE_EPC_FALSE='#' +else + STANDALONE_EPC_TRUE='#' + STANDALONE_EPC_FALSE= +fi + +if test "x$enable_standalone_epc" = "xyes"; then + CFLAGS="$CFLAGS -DENABLE_STANDALONE_EPC" +else + CFLAGS="$CFLAGS -DDISABLE_STANDALONE_EPC" +fi + +# Check whether --enable-hss was given. +if test "${enable_hss+set}" = set; then : + enableval=$enable_hss; CFLAGS="$CFLAGS -DENABLE_USE_HSS" +else + CFLAGS="$CFLAGS -DDISABLE_USE_HSS" +fi + + +if test "x$enable_hss" == "xyes"; then : + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fd_core_initialize in -lfdcore" >&5 +$as_echo_n "checking for fd_core_initialize in -lfdcore... " >&6; } +if ${ac_cv_lib_fdcore_fd_core_initialize+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lfdcore $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char fd_core_initialize (); +int +main () +{ +return fd_core_initialize (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_fdcore_fd_core_initialize=yes +else + ac_cv_lib_fdcore_fd_core_initialize=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fdcore_fd_core_initialize" >&5 +$as_echo "$ac_cv_lib_fdcore_fd_core_initialize" >&6; } +if test "x$ac_cv_lib_fdcore_fd_core_initialize" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBFDCORE 1 +_ACEOF + + LIBS="-lfdcore $LIBS" + +else + as_fn_error $? "Free diameter lib not installed" "$LINENO" 5 +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fd_msg_search_avp in -lfdproto" >&5 +$as_echo_n "checking for fd_msg_search_avp in -lfdproto... " >&6; } +if ${ac_cv_lib_fdproto_fd_msg_search_avp+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lfdproto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char fd_msg_search_avp (); +int +main () +{ +return fd_msg_search_avp (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_fdproto_fd_msg_search_avp=yes +else + ac_cv_lib_fdproto_fd_msg_search_avp=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_fdproto_fd_msg_search_avp" >&5 +$as_echo "$ac_cv_lib_fdproto_fd_msg_search_avp" >&6; } +if test "x$ac_cv_lib_fdproto_fd_msg_search_avp" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBFDPROTO 1 +_ACEOF + + LIBS="-lfdproto $LIBS" + +else + as_fn_error $? "Free diameter lib not installed" "$LINENO" 5 +fi + + + for ac_header in signalent.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "signalent.h" "ac_cv_header_signalent_h" "$ac_includes_default" +if test "x$ac_cv_header_signalent_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SIGNALENT_H 1 +_ACEOF + +fi + +done + + for ac_func in ntohll strndup +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +$as_echo "#define HAVE_AI_ADDRCONFIG /**/" >>confdefs.h + + +$as_echo "#define HAVE_CLOCK_GETTIME /**/" >>confdefs.h + + +$as_echo "#define HAVE_PTHREAD_BAR /**/" >>confdefs.h + + +$as_echo "#define SCTP_CONNECTX_4_ARGS /**/" >>confdefs.h + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 +$as_echo_n "checking for clock_gettime in -lrt... " >&6; } +if ${ac_cv_lib_rt_clock_gettime+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrt $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char clock_gettime (); +int +main () +{ +return clock_gettime (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_rt_clock_gettime=yes +else + ac_cv_lib_rt_clock_gettime=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 +$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } +if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : + $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_barrier_wait in -lpthread" >&5 +$as_echo_n "checking for pthread_barrier_wait in -lpthread... " >&6; } +if ${ac_cv_lib_pthread_pthread_barrier_wait+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_barrier_wait (); +int +main () +{ +return pthread_barrier_wait (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_barrier_wait=yes +else + ac_cv_lib_pthread_pthread_barrier_wait=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_barrier_wait" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_barrier_wait" >&6; } +if test "x$ac_cv_lib_pthread_pthread_barrier_wait" = xyes; then : + $as_echo "#define HAVE_PTHREAD_BAR 1" >>confdefs.h + +fi + + ac_fn_c_check_decl "$LINENO" "AI_ADDRCONFIG" "ac_cv_have_decl_AI_ADDRCONFIG" "#include <netdb.h> +" +if test "x$ac_cv_have_decl_AI_ADDRCONFIG" = xyes; then : + $as_echo "#define HAVE_AI_ADDRCONFIG 1" >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if sctp_connectx accepts 4 arguments" >&5 +$as_echo_n "checking if sctp_connectx accepts 4 arguments... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + int main() { return sctp_connectx(0, NULL, 0, NULL); } + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + $as_echo "#define SCTP_CONNECTX_4_ARGS 1" >>confdefs.h + +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_hash in -lgnutls" >&5 +$as_echo_n "checking for gnutls_hash in -lgnutls... " >&6; } +if ${ac_cv_lib_gnutls_gnutls_hash+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gnutls_hash (); +int +main () +{ +return gnutls_hash (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_gnutls_gnutls_hash=yes +else + ac_cv_lib_gnutls_gnutls_hash=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_hash" >&5 +$as_echo "$ac_cv_lib_gnutls_gnutls_hash" >&6; } +if test "x$ac_cv_lib_gnutls_gnutls_hash" = xyes; then : + +$as_echo "#define GNUTLS_VERSION_210 1" >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_x509_trust_list_verify_crt in -lgnutls" >&5 +$as_echo_n "checking for gnutls_x509_trust_list_verify_crt in -lgnutls... " >&6; } +if ${ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gnutls_x509_trust_list_verify_crt (); +int +main () +{ +return gnutls_x509_trust_list_verify_crt (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt=yes +else + ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt" >&5 +$as_echo "$ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt" >&6; } +if test "x$ac_cv_lib_gnutls_gnutls_x509_trust_list_verify_crt" = xyes; then : + +$as_echo "#define GNUTLS_VERSION_300 1" >>confdefs.h + +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_handshake_set_timeout in -lgnutls" >&5 +$as_echo_n "checking for gnutls_handshake_set_timeout in -lgnutls... " >&6; } +if ${ac_cv_lib_gnutls_gnutls_handshake_set_timeout+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lgnutls $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gnutls_handshake_set_timeout (); +int +main () +{ +return gnutls_handshake_set_timeout (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_gnutls_gnutls_handshake_set_timeout=yes +else + ac_cv_lib_gnutls_gnutls_handshake_set_timeout=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_handshake_set_timeout" >&5 +$as_echo "$ac_cv_lib_gnutls_gnutls_handshake_set_timeout" >&6; } +if test "x$ac_cv_lib_gnutls_gnutls_handshake_set_timeout" = xyes; then : + +$as_echo "#define GNUTLS_VERSION_310 1" >>confdefs.h + +fi + + +fi + +$as_echo "#define FREE_DIAMETER_MINIMUM_VERSION \"1.1.5\"" >>confdefs.h + + + if test x$enable_hss == xyes; then + ENABLE_USE_HSS_TRUE= + ENABLE_USE_HSS_FALSE='#' +else + ENABLE_USE_HSS_TRUE='#' + ENABLE_USE_HSS_FALSE= +fi + + + +# Check whether --enable-r8 was given. +if test "${enable_r8+set}" = set; then : + enableval=$enable_r8; +fi + + +# Check whether --enable-r9 was given. +if test "${enable_r9+set}" = set; then : + enableval=$enable_r9; +fi + + +# Check whether --enable-nas was given. +if test "${enable_nas+set}" = set; then : + enableval=$enable_nas; CFLAGS="$CFLAGS -DDISABLE_USE_NAS" +fi + + if test x$enable_nas == xno; then + DISABLE_USE_NAS_TRUE= + DISABLE_USE_NAS_FALSE='#' +else + DISABLE_USE_NAS_TRUE='#' + DISABLE_USE_NAS_FALSE= +fi + + +# Check whether --enable-pcap_for_sgi was given. +if test "${enable_pcap_for_sgi+set}" = set; then : + enableval=$enable_pcap_for_sgi; case "${enableval}" in + yes) pcap_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_PCAP_FOR_SGI" ;; + no ) pcap_for_sgi=false;; + *) as_fn_error $? "bad value ${enableval} for --enable-pcap-for-sgi" "$LINENO" 5 ;; + esac +else + pcap_for_sgi=false +fi + + +# Check whether --enable-netfilter_for_sgi was given. +if test "${enable_netfilter_for_sgi+set}" = set; then : + enableval=$enable_netfilter_for_sgi; case "${enableval}" in + yes) netfilter_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_NETFILTER_FOR_SGI" ;; + no ) netfilter_for_sgi=false;; + *) as_fn_error $? "bad value ${enableval} for --enable-netfilter-for-sgi" "$LINENO" 5 ;; + esac +else + netfilter_for_sgi=false +fi + + +# Check whether --enable-raw_socket_for_sgi was given. +if test "${enable_raw_socket_for_sgi+set}" = set; then : + enableval=$enable_raw_socket_for_sgi; case "${enableval}" in + yes) raw_socket_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_RAW_SOCKET_FOR_SGI" ;; + no ) raw_socket_for_sgi=false;; + *) as_fn_error $? "bad value ${enableval} for --enable-raw-socket-for-sgi" "$LINENO" 5 ;; + esac +else + if test x$pcap_for_sgi != xtrue && test x$netfilter_for_sgi != xtrue; then + raw_socket_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_RAW_SOCKET_FOR_SGI" + else + raw_socket_for_sgi=false + fi +fi + + + if test x$pcap_for_sgi == xtrue; then + ENABLE_USE_PCAP_FOR_SGI_TRUE= + ENABLE_USE_PCAP_FOR_SGI_FALSE='#' +else + ENABLE_USE_PCAP_FOR_SGI_TRUE='#' + ENABLE_USE_PCAP_FOR_SGI_FALSE= +fi + + if test x$netfilter_for_sgi == xtrue; then + ENABLE_USE_NETFILTER_FOR_SGI_TRUE= + ENABLE_USE_NETFILTER_FOR_SGI_FALSE='#' +else + ENABLE_USE_NETFILTER_FOR_SGI_TRUE='#' + ENABLE_USE_NETFILTER_FOR_SGI_FALSE= +fi + + if test x$raw_socket_for_sgi == xtrue; then + ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE= + ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE='#' +else + ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE='#' + ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE= +fi + + if test x$pcap_for_sgi != xtrue && test x$netfilter_for_sgi != xtrue ; then + ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE= + ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE='#' +else + ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE='#' + ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE= +fi + + +if test "x$enable_pcap_for_sgi" == "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pcap_compile in -lpcap" >&5 +$as_echo_n "checking for pcap_compile in -lpcap... " >&6; } +if ${ac_cv_lib_pcap_pcap_compile+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpcap $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pcap_compile (); +int +main () +{ +return pcap_compile (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pcap_pcap_compile=yes +else + ac_cv_lib_pcap_pcap_compile=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_compile" >&5 +$as_echo "$ac_cv_lib_pcap_pcap_compile" >&6; } +if test "x$ac_cv_lib_pcap_pcap_compile" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPCAP 1 +_ACEOF + + LIBS="-lpcap $LIBS" + +else + + as_fn_error $? "PCAP library needed." "$LINENO" 5 + +fi + + +fi + +if test "x$enable_netfilter_for_sgi" == "xyes"; then : + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfnl_fd in -lnfnetlink" >&5 +$as_echo_n "checking for nfnl_fd in -lnfnetlink... " >&6; } +if ${ac_cv_lib_nfnetlink_nfnl_fd+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnfnetlink $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nfnl_fd (); +int +main () +{ +return nfnl_fd (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_nfnetlink_nfnl_fd=yes +else + ac_cv_lib_nfnetlink_nfnl_fd=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nfnetlink_nfnl_fd" >&5 +$as_echo "$ac_cv_lib_nfnetlink_nfnl_fd" >&6; } +if test "x$ac_cv_lib_nfnetlink_nfnl_fd" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNFNETLINK 1 +_ACEOF + + LIBS="-lnfnetlink $LIBS" + +else + as_fn_error $? "libnfnetlink needed!" "$LINENO" 5 +fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for nfq_open in -lnetfilter_queue" >&5 +$as_echo_n "checking for nfq_open in -lnetfilter_queue... " >&6; } +if ${ac_cv_lib_netfilter_queue_nfq_open+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnetfilter_queue $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char nfq_open (); +int +main () +{ +return nfq_open (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_netfilter_queue_nfq_open=yes +else + ac_cv_lib_netfilter_queue_nfq_open=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netfilter_queue_nfq_open" >&5 +$as_echo "$ac_cv_lib_netfilter_queue_nfq_open" >&6; } +if test "x$ac_cv_lib_netfilter_queue_nfq_open" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNETFILTER_QUEUE 1 +_ACEOF + + LIBS="-lnetfilter_queue $LIBS" + +else + as_fn_error $? "libnetfilter_queue needed!" "$LINENO" 5 +fi + + +fi + + +if test x$enable_r8 == xyes; then + ASN1DIR=R8.10 +else + if test x$enable_r9 == xyes; then + ASN1DIR=R9.8 + CFLAGS="$CFLAGS -DUPDATE_RELEASE_9" + else + ASN1DIR=R10.5 + CFLAGS="$CFLAGS -DUPDATE_RELEASE_9 -DUPDATE_RELEASE_10" + fi +fi + +$as_echo "#define ASN1_MINIMUM_VERSION 924" >>confdefs.h + + if test x$enable_r8 != xyes; then + UPDATE_RELEASE_9_TRUE= + UPDATE_RELEASE_9_FALSE='#' +else + UPDATE_RELEASE_9_TRUE='#' + UPDATE_RELEASE_9_FALSE= +fi + + if test x$enable_r8 != xyes && test x$enable_r9 != xyes; then + UPDATE_RELEASE_10_TRUE= + UPDATE_RELEASE_10_FALSE='#' +else + UPDATE_RELEASE_10_TRUE='#' + UPDATE_RELEASE_10_FALSE= +fi + + + + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5 +$as_echo_n "checking for OPENSSL... " >&6; } + +if test -n "$OPENSSL_CFLAGS"; then + pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl >= 1.0.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "openssl >= 1.0.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OPENSSL_CFLAGS=`$PKG_CONFIG --cflags "openssl >= 1.0.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$OPENSSL_LIBS"; then + pkg_cv_OPENSSL_LIBS="$OPENSSL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"openssl >= 1.0.1\""; } >&5 + ($PKG_CONFIG --exists --print-errors "openssl >= 1.0.1") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_OPENSSL_LIBS=`$PKG_CONFIG --libs "openssl >= 1.0.1" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + OPENSSL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "openssl >= 1.0.1" 2>&1` + else + OPENSSL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "openssl >= 1.0.1" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$OPENSSL_PKG_ERRORS" >&5 + + as_fn_error $? "\"Please install libcrypto >= 1.0.1\"" "$LINENO" 5 +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + as_fn_error $? "\"Please install libcrypto >= 1.0.1\"" "$LINENO" 5 +else + OPENSSL_CFLAGS=$pkg_cv_OPENSSL_CFLAGS + OPENSSL_LIBS=$pkg_cv_OPENSSL_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_OPENSSL=true +fi +CFLAGS="$CFLAGS $OPENSSL_CFLAGS" +LIBS="$LIBS $OPENSSL_LIBS" + + +pkg_failed=no +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CHECK" >&5 +$as_echo_n "checking for CHECK... " >&6; } + +if test -n "$CHECK_CFLAGS"; then + pkg_cv_CHECK_CFLAGS="$CHECK_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.4\""; } >&5 + ($PKG_CONFIG --exists --print-errors "check >= 0.9.4") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CHECK_CFLAGS=`$PKG_CONFIG --cflags "check >= 0.9.4" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$CHECK_LIBS"; then + pkg_cv_CHECK_LIBS="$CHECK_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.4\""; } >&5 + ($PKG_CONFIG --exists --print-errors "check >= 0.9.4") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_CHECK_LIBS=`$PKG_CONFIG --libs "check >= 0.9.4" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + CHECK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "check >= 0.9.4" 2>&1` + else + CHECK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "check >= 0.9.4" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$CHECK_PKG_ERRORS" >&5 + + HAVE_CHECK=false +elif test $pkg_failed = untried; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + HAVE_CHECK=false +else + CHECK_CFLAGS=$pkg_cv_CHECK_CFLAGS + CHECK_LIBS=$pkg_cv_CHECK_LIBS + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + HAVE_CHECK=true +fi + if test x$HAVE_CHECK = xtrue; then + HAVE_CHECK_TRUE= + HAVE_CHECK_FALSE='#' +else + HAVE_CHECK_TRUE='#' + HAVE_CHECK_FALSE= +fi + + +# Extract the first word of "gccxml", so it can be a program name with args. +set dummy gccxml; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_HAVE_GCCXML+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$HAVE_GCCXML"; then + ac_cv_prog_HAVE_GCCXML="$HAVE_GCCXML" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_HAVE_GCCXML="yes" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_HAVE_GCCXML" && ac_cv_prog_HAVE_GCCXML="no" +fi +fi +HAVE_GCCXML=$ac_cv_prog_HAVE_GCCXML +if test -n "$HAVE_GCCXML"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $HAVE_GCCXML" >&5 +$as_echo "$HAVE_GCCXML" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test x$HAVE_GCCXML = xyes; then + HAVE_GCCXML_TRUE= + HAVE_GCCXML_FALSE='#' +else + HAVE_GCCXML_TRUE='#' + HAVE_GCCXML_FALSE= +fi + + +CFLAGS="$CFLAGS -Wall" +CFLAGS="$CFLAGS -Wcast-align" +CFLAGS="$CFLAGS -Wchar-subscripts" +CFLAGS="$CFLAGS -Wmissing-prototypes" +CFLAGS="$CFLAGS -Wmissing-declarations" +CFLAGS="$CFLAGS -Werror=shadow" +CFLAGS="$CFLAGS -Werror=implicit-function-declaration" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if ${ac_cv_c_bigendian+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <sys/types.h> + #include <sys/param.h> + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if <limits.h> defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <limits.h> + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error $? "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + +if test "x$ac_cv_c_bigendian" = "xyes"; then + CFLAGS="$CFLAGS -DBYTE_ORDER=BIG_ENDIAN" +else + CFLAGS="$CFLAGS -DBYTE_ORDER=LITTLE_ENDIAN" +fi + + + if test -n "$DOXYGEN"; then + HAVE_DOXYGEN_TRUE= + HAVE_DOXYGEN_FALSE='#' +else + HAVE_DOXYGEN_TRUE='#' + HAVE_DOXYGEN_FALSE= +fi + +if test -z "$HAVE_DOXYGEN_TRUE"; then : + ac_config_files="$ac_config_files DOCS/DOXYGEN/Doxyfile" + +fi + +HOSTNAME=$(uname -n) +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host name" >&5 +$as_echo_n "checking host name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $HOSTNAME" >&5 +$as_echo "$HOSTNAME" >&6; } + + +ac_config_files="$ac_config_files GTPV1-U/Makefile GTPV2-C/Makefile INTERTASK_INTERFACE/Makefile SGI/Makefile NAS/Makefile S11/Makefile S1AP/MESSAGES/ASN1/Makefile S1AP/MESSAGES/Makefile S1AP/Makefile S6A/Makefile SCTP/Makefile SECU/Makefile SGW-LITE/Makefile UTILS/CONF/s6a.conf UTILS/TIMER/Makefile UTILS/HASHTABLE/Makefile UTILS/Makefile UDP/Makefile MME_APP/Makefile OAISIM_MME/Makefile OAI_EPC/Makefile DOCS/DOXYGEN/Makefile DOCS/Makefile TEST/Makefile Makefile" + + + + +subdirs="$subdirs GTPV2-C/nwgtpv2c-0.11" + + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PDFLATEX_TRUE}" && test -z "${HAVE_PDFLATEX_FALSE}"; then + as_fn_error $? "conditional \"HAVE_PDFLATEX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${STANDALONE_EPC_TRUE}" && test -z "${STANDALONE_EPC_FALSE}"; then + as_fn_error $? "conditional \"STANDALONE_EPC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_USE_HSS_TRUE}" && test -z "${ENABLE_USE_HSS_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_USE_HSS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DISABLE_USE_NAS_TRUE}" && test -z "${DISABLE_USE_NAS_FALSE}"; then + as_fn_error $? "conditional \"DISABLE_USE_NAS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_USE_PCAP_FOR_SGI_TRUE}" && test -z "${ENABLE_USE_PCAP_FOR_SGI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_USE_PCAP_FOR_SGI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_USE_NETFILTER_FOR_SGI_TRUE}" && test -z "${ENABLE_USE_NETFILTER_FOR_SGI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_USE_NETFILTER_FOR_SGI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE}" && test -z "${ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_USE_RAW_SOCKET_FOR_SGI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${ENABLE_USE_RAW_SOCKET_FOR_SGI_TRUE}" && test -z "${ENABLE_USE_RAW_SOCKET_FOR_SGI_FALSE}"; then + as_fn_error $? "conditional \"ENABLE_USE_RAW_SOCKET_FOR_SGI\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${UPDATE_RELEASE_9_TRUE}" && test -z "${UPDATE_RELEASE_9_FALSE}"; then + as_fn_error $? "conditional \"UPDATE_RELEASE_9\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${UPDATE_RELEASE_10_TRUE}" && test -z "${UPDATE_RELEASE_10_FALSE}"; then + as_fn_error $? "conditional \"UPDATE_RELEASE_10\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_CHECK_TRUE}" && test -z "${HAVE_CHECK_FALSE}"; then + as_fn_error $? "conditional \"HAVE_CHECK\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_GCCXML_TRUE}" && test -z "${HAVE_GCCXML_FALSE}"; then + as_fn_error $? "conditional \"HAVE_GCCXML\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +if test -z "${HAVE_DOXYGEN_TRUE}" && test -z "${HAVE_DOXYGEN_FALSE}"; then + as_fn_error $? "conditional \"HAVE_DOXYGEN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by oaisim_mme $as_me 0.3.3851:3935M, which was +generated by GNU Autoconf 2.68. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to <openair_admin@eurecom.fr>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +oaisim_mme config.status 0.3.3851:3935M +configured by $0, generated by GNU Autoconf 2.68, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2010 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`' +predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`' +postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`' +predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`' +postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`' +LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`' +reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`' +reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`' +GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`' +with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`' +inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`' +link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`' +always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`' +exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`' +prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`' +file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`' +hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`' +predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`' +postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`' +predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`' +postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`' +compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib \ +compiler_lib_search_dirs \ +predep_objects \ +postdep_objects \ +predeps \ +postdeps \ +compiler_lib_search_path \ +LD_CXX \ +reload_flag_CXX \ +compiler_CXX \ +lt_prog_compiler_no_builtin_flag_CXX \ +lt_prog_compiler_pic_CXX \ +lt_prog_compiler_wl_CXX \ +lt_prog_compiler_static_CXX \ +lt_cv_prog_compiler_c_o_CXX \ +export_dynamic_flag_spec_CXX \ +whole_archive_flag_spec_CXX \ +compiler_needs_object_CXX \ +with_gnu_ld_CXX \ +allow_undefined_flag_CXX \ +no_undefined_flag_CXX \ +hardcode_libdir_flag_spec_CXX \ +hardcode_libdir_separator_CXX \ +exclude_expsyms_CXX \ +include_expsyms_CXX \ +file_list_spec_CXX \ +compiler_lib_search_dirs_CXX \ +predep_objects_CXX \ +postdep_objects_CXX \ +predeps_CXX \ +postdeps_CXX \ +compiler_lib_search_path_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec \ +reload_cmds_CXX \ +old_archive_cmds_CXX \ +old_archive_from_new_cmds_CXX \ +old_archive_from_expsyms_cmds_CXX \ +archive_cmds_CXX \ +archive_expsym_cmds_CXX \ +module_cmds_CXX \ +module_expsym_cmds_CXX \ +export_symbols_cmds_CXX \ +prelink_cmds_CXX \ +postlink_cmds_CXX; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "DOCS/DOXYGEN/Doxyfile") CONFIG_FILES="$CONFIG_FILES DOCS/DOXYGEN/Doxyfile" ;; + "GTPV1-U/Makefile") CONFIG_FILES="$CONFIG_FILES GTPV1-U/Makefile" ;; + "GTPV2-C/Makefile") CONFIG_FILES="$CONFIG_FILES GTPV2-C/Makefile" ;; + "INTERTASK_INTERFACE/Makefile") CONFIG_FILES="$CONFIG_FILES INTERTASK_INTERFACE/Makefile" ;; + "SGI/Makefile") CONFIG_FILES="$CONFIG_FILES SGI/Makefile" ;; + "NAS/Makefile") CONFIG_FILES="$CONFIG_FILES NAS/Makefile" ;; + "S11/Makefile") CONFIG_FILES="$CONFIG_FILES S11/Makefile" ;; + "S1AP/MESSAGES/ASN1/Makefile") CONFIG_FILES="$CONFIG_FILES S1AP/MESSAGES/ASN1/Makefile" ;; + "S1AP/MESSAGES/Makefile") CONFIG_FILES="$CONFIG_FILES S1AP/MESSAGES/Makefile" ;; + "S1AP/Makefile") CONFIG_FILES="$CONFIG_FILES S1AP/Makefile" ;; + "S6A/Makefile") CONFIG_FILES="$CONFIG_FILES S6A/Makefile" ;; + "SCTP/Makefile") CONFIG_FILES="$CONFIG_FILES SCTP/Makefile" ;; + "SECU/Makefile") CONFIG_FILES="$CONFIG_FILES SECU/Makefile" ;; + "SGW-LITE/Makefile") CONFIG_FILES="$CONFIG_FILES SGW-LITE/Makefile" ;; + "UTILS/CONF/s6a.conf") CONFIG_FILES="$CONFIG_FILES UTILS/CONF/s6a.conf" ;; + "UTILS/TIMER/Makefile") CONFIG_FILES="$CONFIG_FILES UTILS/TIMER/Makefile" ;; + "UTILS/HASHTABLE/Makefile") CONFIG_FILES="$CONFIG_FILES UTILS/HASHTABLE/Makefile" ;; + "UTILS/Makefile") CONFIG_FILES="$CONFIG_FILES UTILS/Makefile" ;; + "UDP/Makefile") CONFIG_FILES="$CONFIG_FILES UDP/Makefile" ;; + "MME_APP/Makefile") CONFIG_FILES="$CONFIG_FILES MME_APP/Makefile" ;; + "OAISIM_MME/Makefile") CONFIG_FILES="$CONFIG_FILES OAISIM_MME/Makefile" ;; + "OAI_EPC/Makefile") CONFIG_FILES="$CONFIG_FILES OAI_EPC/Makefile" ;; + "DOCS/DOXYGEN/Makefile") CONFIG_FILES="$CONFIG_FILES DOCS/DOXYGEN/Makefile" ;; + "DOCS/Makefile") CONFIG_FILES="$CONFIG_FILES DOCS/Makefile" ;; + "TEST/Makefile") CONFIG_FILES="$CONFIG_FILES TEST/Makefile" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' <conf$$subs.awk | sed ' +/^[^""]/{ + N + s/\n// +} +' >>$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' <confdefs.h | sed ' +s/'"$ac_delim"'/"\\\ +"/g' >>$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="CXX " + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects +postdep_objects=$lt_postdep_objects +predeps=$lt_predeps +postdeps=$lt_postdeps + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + + cat <<_LT_EOF >> "$ofile" + +# ### BEGIN LIBTOOL TAG CONFIG: CXX + +# The linker used to build libraries. +LD=$lt_LD_CXX + +# How to create reloadable object files. +reload_flag=$lt_reload_flag_CXX +reload_cmds=$lt_reload_cmds_CXX + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds_CXX + +# A language specific compiler. +CC=$lt_compiler_CXX + +# Is the compiler the GNU compiler? +with_gcc=$GCC_CXX + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic_CXX + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl_CXX + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static_CXX + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc_CXX + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object_CXX + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds_CXX +archive_expsym_cmds=$lt_archive_expsym_cmds_CXX + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds_CXX +module_expsym_cmds=$lt_module_expsym_cmds_CXX + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld_CXX + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag_CXX + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag_CXX + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct_CXX + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute_CXX + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L_CXX + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic_CXX + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath_CXX + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs_CXX + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols_CXX + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds_CXX + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms_CXX + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms_CXX + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds_CXX + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds_CXX + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec_CXX + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action_CXX + +# The directories searched by this compiler when creating a shared library. +compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX + +# Dependencies to place before and after the objects being linked to +# create a shared library. +predep_objects=$lt_predep_objects_CXX +postdep_objects=$lt_postdep_objects_CXX +predeps=$lt_predeps_CXX +postdeps=$lt_postdeps_CXX + +# The library search path used internally by the compiler when linking +# a shared library. +compiler_lib_search_path=$lt_compiler_lib_search_path_CXX + +# ### END LIBTOOL TAG CONFIG: CXX +_LT_EOF + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi + +# +# CONFIG_SUBDIRS section. +# +if test "$no_recursion" != yes; then + + # Remove --cache-file, --srcdir, and --disable-option-checking arguments + # so they do not pile up. + ac_sub_configure_args= + ac_prev= + eval "set x $ac_configure_args" + shift + for ac_arg + do + if test -n "$ac_prev"; then + ac_prev= + continue + fi + case $ac_arg in + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* \ + | --c=*) + ;; + --config-cache | -C) + ;; + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + ;; + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + ;; + --disable-option-checking) + ;; + *) + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_sub_configure_args " '$ac_arg'" ;; + esac + done + + # Always prepend --prefix to ensure using the same prefix + # in subdir configurations. + ac_arg="--prefix=$prefix" + case $ac_arg in + *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args" + + # Pass --silent + if test "$silent" = yes; then + ac_sub_configure_args="--silent $ac_sub_configure_args" + fi + + # Always prepend --disable-option-checking to silence warnings, since + # different subdirs can have different --enable and --with options. + ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args" + + ac_popdir=`pwd` + for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue + + # Do not complain, so a configure script can configure whichever + # parts of a large source tree are present. + test -d "$srcdir/$ac_dir" || continue + + ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)" + $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5 + $as_echo "$ac_msg" >&6 + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + cd "$ac_dir" + + # Check for guested configure; otherwise get Cygnus style configure. + if test -f "$ac_srcdir/configure.gnu"; then + ac_sub_configure=$ac_srcdir/configure.gnu + elif test -f "$ac_srcdir/configure"; then + ac_sub_configure=$ac_srcdir/configure + elif test -f "$ac_srcdir/configure.in"; then + # This should be Cygnus configure. + ac_sub_configure=$ac_aux_dir/configure + else + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5 +$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;} + ac_sub_configure= + fi + + # The recursion is here. + if test -n "$ac_sub_configure"; then + # Make the cache file name correct relative to the subdirectory. + case $cache_file in + [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;; + *) # Relative name. + ac_sub_cache_file=$ac_top_build_prefix$cache_file ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5 +$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;} + # The eval makes quoting arguments work. + eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \ + --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" || + as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5 + fi + + cd "$ac_popdir" + done +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo " +($PACKAGE_NAME) version $PACKAGE_VERSION +Prefix.........: $prefix +C Compiler.....: $CC $CFLAGS +Linker.........: $LD $LDFLAGS $LIBS +Doxygen........: ${DOXYGEN:-no} +Tests..........: ${HAVE_CHECK} +GCCXML.........: ${HAVE_GCCXML} +HSS............: ${enable_hss:-no} +Standalone ....: ${enable_standalone_epc:-no}" + +if test x$enable_r8 == xyes; then + echo "Release........: 8.10" +else + if test x$enable_r9 == xyes; then + echo "Release........: 9.8" + else + echo "Release........: 10.5" + fi +fi + +if test x$pcap_for_sgi == xtrue; then + echo "SGI pcap.......: yes" +fi + +if test x$netfilter_for_sgi == xtrue; then + echo "SGI netfilter..: yes" +fi + +if test x$raw_socket_for_sgi == xtrue; then + echo "SGI raw socket.: yes" +fi diff --git a/openair-cn/configure.ac b/openair-cn/configure.ac new file mode 100644 index 0000000000..278c2c8d2a --- /dev/null +++ b/openair-cn/configure.ac @@ -0,0 +1,374 @@ +AC_PREREQ([2.68]) + +define([svnversion], esyscmd([sh -c "svnversion ..|tr -d '\n'"])) + +AC_DEFINE(SVN_REVISION, "svnversion", [SVN Revision]) + +AC_INIT([oai_epc], [0.3.svnversion], [openair_admin@eurecom.fr]) +AC_CANONICAL_BUILD +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE([1.11 silent-rules]) + +AC_CONFIG_MACRO_DIR([m4]) + +AC_CONFIG_HEADERS([config.h]) + +AM_MAINTAINER_MODE + +AM_SILENT_RULES([yes]) + +AM_PROG_LIBTOOL +AM_PROG_LEX + +dnl *** Autoconf support *** +AC_ARG_ENABLE(autoconf, + [ --disable-autoconf disable automatic generation of configure script ], + enable_autoconf=$enableval, enable_autoconf=yes +) +AC_PATH_PROG(AUTOCONF, autoconf, @echo autoconf not available) +AC_PATH_PROG(AUTOHEADER, autoheader, @echo autoheader not available) +if test -z "$AUTOCONF"; then enable_autoconf=no ; fi +if test -z "$AUTOHEADER"; then enable_autoconf=no ; fi +if test x$enable_autoconf = xyes; then + CONFIGURE_DEPENDS="configure.in aclocal.m4" +fi +AC_SUBST(CONFIGURE_DEPENDS) + +AC_CHECK_PROGS([DOXYGEN], [doxygen]) +if test -z "$DOXYGEN"; then + AC_MSG_WARN([Doxygen not found - continuing without Doxygen support]) +else + # Check for presence of pdfLaTeX + AC_CHECK_PROG(PDFLATEX, pdflatex, pdflatex) + if test -z "$PDFLATEX"; then + AC_MSG_WARN([Unable to create PDF version of the user manual.]) + fi +fi +AM_CONDITIONAL([HAVE_PDFLATEX], test -n "$PDFLATEX") + +dnl ***asn1c support*** +AC_CHECK_PROG(ASN1C_CHECK, asn1c, yes, [AC_MSG_ERROR(Please install asn1c before going further.)]) + +# Checks for programs. +AC_PROG_CXX +AC_PROG_AWK +AC_PROG_CC +AC_PROG_CPP +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_MKDIR_P +AC_PROG_YACC +AC_PROG_RANLIB + +AC_CHECK_HEADERS([arpa/inet.h fcntl.h float.h inttypes.h limits.h malloc.h]) +AC_CHECK_HEADERS([netinet/in.h stddef.h stdint.h stdlib.h string.h libintl.h]) +AC_CHECK_HEADERS([sys/time.h sys/ioctl.h sys/socket.h unistd.h]) +AC_CHECK_HEADERS([netdb.h termios.h]) + +# Checks for library functions. +AC_FUNC_MMAP +AC_FUNC_MALLOC +AC_FUNC_ALLOCA +AC_FUNC_REALLOC +AC_FUNC_STRTOD +AC_CHECK_FUNCS([ftruncate inet_ntoa memchr memmove memset munmap select socket]) +AC_CHECK_FUNCS([strdup strerror strspn strchr strstr]) +AC_CHECK_FUNCS([gethostname gethostbyname]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_INLINE +AC_TYPE_INT8_T +AC_TYPE_INT16_T +AC_TYPE_INT32_T +AC_TYPE_INT64_T +AC_TYPE_OFF_T +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T +AC_TYPE_UINT8_T +AC_TYPE_UINT16_T +AC_TYPE_UINT32_T +AC_TYPE_UINT64_T + +AC_CHECK_TYPES([ptrdiff_t]) + +dnl *** libsctp-dev support *** +AC_CHECK_LIB([sctp], [sctp_sendmsg], [], + [AC_MSG_ERROR([libsctp-dev needed!])]) + +dnl *** pthread support *** +AC_CHECK_LIB([pthread], [pthread_mutex_init], [], + [AC_MSG_ERROR(pthread library needed!)]) + +dnl *** real time support *** +AC_CHECK_LIB([rt], [timer_create], [], + [AC_MSG_ERROR(rt library needed!)]) + +dnl *** Cryptographic lib nettle support *** +PKG_CHECK_MODULES(nettle, [nettle >= 2.5], + [HAVE_NETTLE=true], + [AC_MSG_ERROR("Please install nettle >= 2.5")]) +CFLAGS="$CFLAGS $nettle_CFLAGS" +LIBS="$LIBS $nettle_LIBS" + +AC_ARG_ENABLE([standalone-epc], + AS_HELP_STRING([--enable-standalone-epc], + [Compile MME, SGW and PGW in a single executable]), + [], + [STANDALONE_EPC="yes"]) +AM_CONDITIONAL([STANDALONE_EPC], [test "x$enable_standalone_epc" = "xyes"]) +if test "x$enable_standalone_epc" = "xyes"; then + CFLAGS="$CFLAGS -DENABLE_STANDALONE_EPC" +else + CFLAGS="$CFLAGS -DDISABLE_STANDALONE_EPC" +fi + +dnl *** Add freediameter dependencies *** +AC_CHECK_LIB([fdcore], [fd_core_initialize], [], + [AC_MSG_ERROR(Free diameter lib not installed)]) +AC_CHECK_LIB([fdproto], [fd_msg_search_avp], [], + [AC_MSG_ERROR(Free diameter lib not installed)]) + +dnl *** Freediameter requirements *** +AC_CHECK_HEADERS([signalent.h]) +AC_CHECK_FUNCS([ntohll strndup]) +AC_DEFINE([HAVE_AI_ADDRCONFIG], [], + [Define to 1 if you have AI_ADDRCONFIG defined in netdb.h]) +AC_DEFINE([HAVE_CLOCK_GETTIME], [], + [Define to 1 if you have clock_gettime in librt]) +AC_DEFINE([HAVE_PTHREAD_BAR], [], + [Define to 1 if you have pthread_barrier_wait in libpthread]) +AC_DEFINE([SCTP_CONNECTX_4_ARGS], [], + [Define to 1 if sctp_connectx function accepts 4 arguments]) +AC_CHECK_LIB([rt], [clock_gettime], [AC_DEFINE(HAVE_CLOCK_GETTIME, 1)], []) +AC_CHECK_LIB([pthread], [pthread_barrier_wait], + [AC_DEFINE(HAVE_PTHREAD_BAR, 1)], []) +AC_CHECK_DECL([AI_ADDRCONFIG], + [AC_DEFINE(HAVE_AI_ADDRCONFIG, 1)], + [], [[#include <netdb.h>]]) +AC_MSG_CHECKING(if sctp_connectx accepts 4 arguments) +AC_LINK_IFELSE([ + AC_LANG_SOURCE( + [[int main() { return sctp_connectx(0, NULL, 0, NULL); }]]) +], [AC_DEFINE(SCTP_CONNECTX_4_ARGS, 1)]) +AC_CHECK_LIB([gnutls], + [gnutls_hash], + [AC_DEFINE(GNUTLS_VERSION_210, 1, + [Define to 1 if you have gnutls 2.10 installed])], + []) +AC_CHECK_LIB([gnutls], + [gnutls_x509_trust_list_verify_crt], + [AC_DEFINE(GNUTLS_VERSION_300, 1, + [Define to 1 if you have gnutls 3.0 installed])], + []) +AC_CHECK_LIB([gnutls], + [gnutls_handshake_set_timeout], + [AC_DEFINE(GNUTLS_VERSION_310, 1, + [Define to 1 if you have gnutls 3.1 installed])], + []) + +AC_DEFINE(FREE_DIAMETER_MINIMUM_VERSION, "1.1.5", [freeDiameter minimum version]) + +AC_SUBST(ADD_CFLAGS) + +dnl *** Enable r8 update *** +AC_ARG_ENABLE([r8], + AS_HELP_STRING([--enable-r8], [Disable 3GPP release 9 and 10 updates]), + [], + []) + +dnl *** Enable r9 update *** +AC_ARG_ENABLE([r9], + AS_HELP_STRING([--enable-r9], [Disable 3GPP release 10 updates]), + [], + []) + +dnl *** Disable NAS layer *** +AC_ARG_ENABLE([nas], + AS_HELP_STRING([--disable-nas], [Disable NAS layer]), + [CFLAGS="$CFLAGS -DDISABLE_USE_NAS"], + []) +AM_CONDITIONAL([DISABLE_USE_NAS], [test x$enable_nas == xno]) + +dnl *** Enable PCAP for SGI *** +AC_ARG_ENABLE([pcap_for_sgi], + AS_HELP_STRING([--enable-pcap-for-sgi], [Enable PCAP for SGI layer]), + [case "${enableval}" in + yes) pcap_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_PCAP_FOR_SGI" ;; + no ) pcap_for_sgi=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-pcap-for-sgi) ;; + esac], + [pcap_for_sgi=false]) + +dnl *** Enable NETFILTER for SGI *** +AC_ARG_ENABLE([netfilter_for_sgi], + AS_HELP_STRING([--enable-netfilter-for-sgi], [Enable netfilter for SGI layer]), + [case "${enableval}" in + yes) netfilter_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_NETFILTER_FOR_SGI" ;; + no ) netfilter_for_sgi=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-netfilter-for-sgi) ;; + esac], + [netfilter_for_sgi=false]) + +dnl *** Enable RAW socket for SGI *** +AC_ARG_ENABLE([raw_socket_for_sgi], + AS_HELP_STRING([--enable-raw-socket-for-sgi], [Enable netfilter for SGI layer]), + [case "${enableval}" in + yes) raw_socket_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_RAW_SOCKET_FOR_SGI" ;; + no ) raw_socket_for_sgi=false;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-raw-socket-for-sgi) ;; + esac], + [if test x$pcap_for_sgi != xtrue && test x$netfilter_for_sgi != xtrue; then + raw_socket_for_sgi=true; CFLAGS="$CFLAGS -DENABLE_USE_RAW_SOCKET_FOR_SGI" + else + raw_socket_for_sgi=false + fi]) + +AM_CONDITIONAL([ENABLE_USE_PCAP_FOR_SGI], [test x$pcap_for_sgi == xtrue]) +AM_CONDITIONAL([ENABLE_USE_NETFILTER_FOR_SGI], [test x$netfilter_for_sgi == xtrue]) +AM_CONDITIONAL([ENABLE_USE_RAW_SOCKET_FOR_SGI], [test x$raw_socket_for_sgi == xtrue]) +AM_CONDITIONAL([ENABLE_USE_RAW_SOCKET_FOR_SGI], [ test x$pcap_for_sgi != xtrue && test x$netfilter_for_sgi != xtrue ]) + +AS_IF([test "x$enable_pcap_for_sgi" == "xyes"], [ + dnl *** libpcap support *** + AC_CHECK_LIB([pcap], [pcap_compile], [], [ + AC_MSG_ERROR([PCAP library needed.]) + ]) +]) + +AS_IF([test "x$enable_netfilter_for_sgi" == "xyes"], [ + dnl *** libnfnetlink support *** + AC_CHECK_LIB([nfnetlink], [nfnl_fd], [], + [AC_MSG_ERROR([libnfnetlink needed!])]) + + dnl *** libnetfilter_queue support *** + AC_CHECK_LIB([netfilter_queue], [nfq_open], [], + [AC_MSG_ERROR([libnetfilter_queue needed!])]) +]) + + +if test x$enable_r8 == xyes; then + ASN1DIR=R8.10 +else + if test x$enable_r9 == xyes; then + ASN1DIR=R9.8 + CFLAGS="$CFLAGS -DUPDATE_RELEASE_9" + else + ASN1DIR=R10.5 + CFLAGS="$CFLAGS -DUPDATE_RELEASE_9 -DUPDATE_RELEASE_10" + fi +fi +AC_DEFINE(ASN1_MINIMUM_VERSION, 924, [asn1c minimum version]) +AM_CONDITIONAL([UPDATE_RELEASE_9], [test x$enable_r8 != xyes]) +AM_CONDITIONAL([UPDATE_RELEASE_10], [test x$enable_r8 != xyes && test x$enable_r9 != xyes]) + +AC_SUBST(ASN1DIR) + +PKG_CHECK_MODULES(OPENSSL, + [openssl >= 1.0.1], + [HAVE_OPENSSL=true], + [AC_MSG_ERROR("Please install libcrypto >= 1.0.1")]) +CFLAGS="$CFLAGS $OPENSSL_CFLAGS" +LIBS="$LIBS $OPENSSL_LIBS" + +PKG_CHECK_MODULES(CHECK, [check >= 0.9.4], [HAVE_CHECK=true], [HAVE_CHECK=false]) +AM_CONDITIONAL(HAVE_CHECK, test x$HAVE_CHECK = xtrue) + +AC_CHECK_PROG(HAVE_GCCXML,gccxml,yes,no) +AM_CONDITIONAL(HAVE_GCCXML, test x$HAVE_GCCXML = xyes) + +dnl Add these flags +CFLAGS="$CFLAGS -Wall" +CFLAGS="$CFLAGS -Wcast-align" +CFLAGS="$CFLAGS -Wchar-subscripts" +CFLAGS="$CFLAGS -Wmissing-prototypes" +CFLAGS="$CFLAGS -Wmissing-declarations" +CFLAGS="$CFLAGS -Werror=shadow" +CFLAGS="$CFLAGS -Werror=implicit-function-declaration" + +dnl *** Check for endianness of platform *** +AC_C_BIGENDIAN +if test "x$ac_cv_c_bigendian" = "xyes"; then + CFLAGS="$CFLAGS -DBYTE_ORDER=BIG_ENDIAN" +else + CFLAGS="$CFLAGS -DBYTE_ORDER=LITTLE_ENDIAN" +fi + +dnl AC_SUBST([AM_CFLAGS]) + +dnl Doxygen section +AM_CONDITIONAL([HAVE_DOXYGEN], [test -n "$DOXYGEN"]) +AM_COND_IF([HAVE_DOXYGEN], [AC_CONFIG_FILES([DOCS/DOXYGEN/Doxyfile])]) + +dnl *** Retrieving hostname for substition in freediameter configuration file *** +HOSTNAME=$(uname -n) +AC_MSG_CHECKING([host name]) +AC_MSG_RESULT([$HOSTNAME]) +AC_SUBST([HOSTNAME]) + +AC_CONFIG_FILES( \ + GTPV1-U/Makefile \ + GTPV2-C/Makefile \ + INTERTASK_INTERFACE/Makefile \ + SGI/Makefile \ + NAS/Makefile \ + S11/Makefile \ + S1AP/MESSAGES/ASN1/Makefile \ + S1AP/MESSAGES/Makefile \ + S1AP/Makefile \ + S6A/Makefile \ + SCTP/Makefile \ + SECU/Makefile \ + SGW-LITE/Makefile \ + UTILS/CONF/s6a.conf \ + UTILS/HASHTABLE/Makefile \ + UTILS/Makefile \ + UDP/Makefile \ + MME_APP/Makefile \ + OAISIM_MME/Makefile \ + OAI_EPC/Makefile \ + OAI_SGW/Makefile \ + DOCS/DOXYGEN/Makefile \ + DOCS/Makefile \ + TEST/Makefile \ + Makefile \ +) + +dnl Call for configure script in gtpv2c subdir +AC_CONFIG_SUBDIRS([GTPV2-C/nwgtpv2c-0.11]) + +dnl configure makefiles +AC_OUTPUT + +echo " +($PACKAGE_NAME) version $PACKAGE_VERSION +Prefix.........: $prefix +C Compiler.....: $CC $CFLAGS +Linker.........: $LD $LDFLAGS $LIBS +Doxygen........: ${DOXYGEN:-no} +Tests..........: ${HAVE_CHECK} +GCCXML.........: ${HAVE_GCCXML} +Standalone ....: ${enable_standalone_epc:-no}" + +if test x$enable_r8 == xyes; then + echo "Release........: 8.10" +else + if test x$enable_r9 == xyes; then + echo "Release........: 9.8" + else + echo "Release........: 10.5" + fi +fi + +if test x$pcap_for_sgi == xtrue; then + echo "SGI pcap.......: yes" +fi + +if test x$netfilter_for_sgi == xtrue; then + echo "SGI netfilter..: yes" +fi + +if test x$raw_socket_for_sgi == xtrue; then + echo "SGI raw socket.: yes" +fi \ No newline at end of file diff --git a/openair-cn/cppcheck.sh b/openair-cn/cppcheck.sh new file mode 100644 index 0000000000..ac79da8f2c --- /dev/null +++ b/openair-cn/cppcheck.sh @@ -0,0 +1,2 @@ +#!/bin/sh +cppcheck . --enable=all --xml --verbose --xml-version=2 -j4 2> err.xml diff --git a/openair-cn/depcomp b/openair-cn/depcomp new file mode 100644 index 0000000000..debb6ffa3e --- /dev/null +++ b/openair-cn/depcomp @@ -0,0 +1,707 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2012-03-27.16; # UTC + +# Copyright (C) 1999-2012 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to <bug-automake@gnu.org>. +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' "$nl" < "$tmpdepfile" | +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependent.h'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. + # However on + # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\': + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + # tcc 0.9.26 (FIXME still under development at the moment of writing) + # will emit a similar output, but also prepend the continuation lines + # with horizontal tabulation characters. + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form 'foo.o: dependent.h', + # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ + < "$tmpdepfile" > "$depfile" + sed ' + s/[ '"$tab"'][ '"$tab"']*/ /g + s/^ *// + s/ *\\*$// + s/^[^:]*: *// + /^$/d + /:$/d + s/$/ :/ + ' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test "$stat" = 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' "$nl" < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/openair-cn/install-sh b/openair-cn/install-sh new file mode 100644 index 0000000000..377bb8687f --- /dev/null +++ b/openair-cn/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-11-20.07; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# 'make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for 'test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call 'install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for 'test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/openair-cn/ltmain.sh b/openair-cn/ltmain.sh new file mode 100644 index 0000000000..c2852d8561 --- /dev/null +++ b/openair-cn/ltmain.sh @@ -0,0 +1,9661 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1ubuntu1 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to <bug-libtool@gnu.org>. +# GNU libtool home page: <http://www.gnu.org/software/libtool/>. +# General help using GNU software: <http://www.gnu.org/gethelp/>. + +PROGRAM=libtool +PACKAGE=libtool +VERSION="2.4.2 Debian-2.4.2-1ubuntu1" +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T <<EOF +# $write_libobj - a libtool object file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# Name of the PIC object. +pic_object=$write_lobj + +# Name of the non-PIC object +non_pic_object=$write_oldobj + +EOF + $MV "${write_libobj}T" "${write_libobj}" + } +} + + +################################################## +# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS # +################################################## + +# func_convert_core_file_wine_to_w32 ARG +# Helper function used by file name conversion functions when $build is *nix, +# and $host is mingw, cygwin, or some other w32 environment. Relies on a +# correctly configured wine environment available, with the winepath program +# in $build's $PATH. +# +# ARG is the $build file name to be converted to w32 format. +# Result is available in $func_convert_core_file_wine_to_w32_result, and will +# be empty on error (or when ARG is empty) +func_convert_core_file_wine_to_w32 () +{ + $opt_debug + func_convert_core_file_wine_to_w32_result="$1" + if test -n "$1"; then + # Unfortunately, winepath does not exit with a non-zero error code, so we + # are forced to check the contents of stdout. On the other hand, if the + # command is not found, the shell will set an exit code of 127 and print + # *an error message* to stdout. So we must check for both error code of + # zero AND non-empty stdout, which explains the odd construction: + func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen <import library>. + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 </dev/null >/dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat <<EOF + +/* $cwrappersource - temporary wrapper executable for $objdir/$outputname + Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION + + The $output program cannot be directly executed until all the libtool + libraries that it depends on are installed. + + This wrapper executable should never be moved out of the build directory. + If it is, it will not operate correctly. +*/ +EOF + cat <<"EOF" +#ifdef _MSC_VER +# define _CRT_SECURE_NO_DEPRECATE 1 +#endif +#include <stdio.h> +#include <stdlib.h> +#ifdef _MSC_VER +# include <direct.h> +# include <process.h> +# include <io.h> +#else +# include <unistd.h> +# include <stdint.h> +# ifdef __CYGWIN__ +# include <io.h> +# endif +#endif +#include <malloc.h> +#include <stdarg.h> +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <<EOF +volatile const char * MAGIC_EXE = "$magic_exe"; +const char * LIB_PATH_VARNAME = "$shlibpath_var"; +EOF + + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + func_to_host_path "$temp_rpath" + cat <<EOF +const char * LIB_PATH_VALUE = "$func_to_host_path_result"; +EOF + else + cat <<"EOF" +const char * LIB_PATH_VALUE = ""; +EOF + fi + + if test -n "$dllsearchpath"; then + func_to_host_path "$dllsearchpath:" + cat <<EOF +const char * EXE_PATH_VARNAME = "PATH"; +const char * EXE_PATH_VALUE = "$func_to_host_path_result"; +EOF + else + cat <<"EOF" +const char * EXE_PATH_VARNAME = ""; +const char * EXE_PATH_VALUE = ""; +EOF + fi + + if test "$fast_install" = yes; then + cat <<EOF +const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */ +EOF + else + cat <<EOF +const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */ +EOF + fi + + + cat <<"EOF" + +#define LTWRAPPER_OPTION_PREFIX "--lt-" + +static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX; +static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script"; +static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug"; + +int +main (int argc, char *argv[]) +{ + char **newargz; + int newargc; + char *tmp_pathspec; + char *actual_cwrapper_path; + char *actual_cwrapper_name; + char *target_name; + char *lt_argv_zero; + intptr_t rval = 127; + + int i; + + program_name = (char *) xstrdup (base_name (argv[0])); + newargz = XMALLOC (char *, argc + 1); + + /* very simple arg parsing; don't want to rely on getopt + * also, copy all non cwrapper options to newargz, except + * argz[0], which is handled differently + */ + newargc=0; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], dumpscript_opt) == 0) + { +EOF + case "$host" in + *mingw* | *cygwin* ) + # make stdout use "unix" line endings + echo " setmode(1,_O_BINARY);" + ;; + esac + + cat <<"EOF" + lt_dump_script (stdout); + return 0; + } + if (strcmp (argv[i], debug_opt) == 0) + { + lt_debug = 1; + continue; + } + if (strcmp (argv[i], ltwrapper_option_prefix) == 0) + { + /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX + namespace, but it is not one of the ones we know about and + have already dealt with, above (inluding dump-script), then + report an error. Otherwise, targets might begin to believe + they are allowed to use options in the LTWRAPPER_OPTION_PREFIX + namespace. The first time any user complains about this, we'll + need to make LTWRAPPER_OPTION_PREFIX a configure-time option + or a configure.ac-settable value. + */ + lt_fatal (__FILE__, __LINE__, + "unrecognized %s option: '%s'", + ltwrapper_option_prefix, argv[i]); + } + /* otherwise ... */ + newargz[++newargc] = xstrdup (argv[i]); + } + newargz[++newargc] = NULL; + +EOF + cat <<EOF + /* The GNU banner must be the first non-error debug message */ + lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n"); +EOF + cat <<"EOF" + lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]); + lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name); + + tmp_pathspec = find_executable (argv[0]); + if (tmp_pathspec == NULL) + lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]); + lt_debugprintf (__FILE__, __LINE__, + "(main) found exe (before symlink chase) at: %s\n", + tmp_pathspec); + + actual_cwrapper_path = chase_symlinks (tmp_pathspec); + lt_debugprintf (__FILE__, __LINE__, + "(main) found exe (after symlink chase) at: %s\n", + actual_cwrapper_path); + XFREE (tmp_pathspec); + + actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path)); + strendzap (actual_cwrapper_path, actual_cwrapper_name); + + /* wrapper name transforms */ + strendzap (actual_cwrapper_name, ".exe"); + tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1); + XFREE (actual_cwrapper_name); + actual_cwrapper_name = tmp_pathspec; + tmp_pathspec = 0; + + /* target_name transforms -- use actual target program name; might have lt- prefix */ + target_name = xstrdup (base_name (TARGET_PROGRAM_NAME)); + strendzap (target_name, ".exe"); + tmp_pathspec = lt_extend_str (target_name, ".exe", 1); + XFREE (target_name); + target_name = tmp_pathspec; + tmp_pathspec = 0; + + lt_debugprintf (__FILE__, __LINE__, + "(main) libtool target name: %s\n", + target_name); +EOF + + cat <<EOF + newargz[0] = + XMALLOC (char, (strlen (actual_cwrapper_path) + + strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1)); + strcpy (newargz[0], actual_cwrapper_path); + strcat (newargz[0], "$objdir"); + strcat (newargz[0], "/"); +EOF + + cat <<"EOF" + /* stop here, and copy so we don't have to do this twice */ + tmp_pathspec = xstrdup (newargz[0]); + + /* do NOT want the lt- prefix here, so use actual_cwrapper_name */ + strcat (newargz[0], actual_cwrapper_name); + + /* DO want the lt- prefix here if it exists, so use target_name */ + lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1); + XFREE (tmp_pathspec); + tmp_pathspec = NULL; +EOF + + case $host_os in + mingw*) + cat <<"EOF" + { + char* p; + while ((p = strchr (newargz[0], '\\')) != NULL) + { + *p = '/'; + } + while ((p = strchr (lt_argv_zero, '\\')) != NULL) + { + *p = '/'; + } + } +EOF + ;; + esac + + cat <<"EOF" + XFREE (target_name); + XFREE (actual_cwrapper_path); + XFREE (actual_cwrapper_name); + + lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */ + lt_setenv ("DUALCASE", "1"); /* for MSK sh */ + /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must + be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath) + because on Windows, both *_VARNAMEs are PATH but uninstalled + libraries must come first. */ + lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE); + lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE); + + lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n", + nonnull (lt_argv_zero)); + for (i = 0; i < newargc; i++) + { + lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n", + i, nonnull (newargz[i])); + } + +EOF + + case $host_os in + mingw*) + cat <<"EOF" + /* execv doesn't actually work on mingw as expected on unix */ + newargz = prepare_spawn (newargz); + rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); + if (rval == -1) + { + /* failed to start process */ + lt_debugprintf (__FILE__, __LINE__, + "(main) failed to launch target \"%s\": %s\n", + lt_argv_zero, nonnull (strerror (errno))); + return 127; + } + return rval; +EOF + ;; + *) + cat <<"EOF" + execv (lt_argv_zero, newargz); + return rval; /* =127, but avoids unused variable warning */ +EOF + ;; + esac + + cat <<"EOF" +} + +void * +xmalloc (size_t num) +{ + void *p = (void *) malloc (num); + if (!p) + lt_fatal (__FILE__, __LINE__, "memory exhausted"); + + return p; +} + +char * +xstrdup (const char *string) +{ + return string ? strcpy ((char *) xmalloc (strlen (string) + 1), + string) : NULL; +} + +const char * +base_name (const char *name) +{ + const char *base; + +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + /* Skip over the disk name in MSDOS pathnames. */ + if (isalpha ((unsigned char) name[0]) && name[1] == ':') + name += 2; +#endif + + for (base = name; *name; name++) + if (IS_DIR_SEPARATOR (*name)) + base = name + 1; + return base; +} + +int +check_executable (const char *path) +{ + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if ((stat (path, &st) >= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) + libs="$deplibs %DEPLIBS%" + test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs" + ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + *) + func_fatal_configuration "$modename: unknown library version type \`$version_type'" + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c <<EOF + int main() { return 0; } +EOF + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then + ldd_output=`ldd conftest` + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + func_append newdeplibs " $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + func_append newdeplibs " $i" + else + droppeddeps=yes + echo + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which I believe you do not have" + echo "*** because a test_compile did reveal that the linker did not use it for" + echo "*** its dynamic dependency list that programs get resolved with at runtime." + fi + fi + ;; + *) + func_append newdeplibs " $i" + ;; + esac + done + else + # Error occurred in the first compile. Let's try to salvage + # the situation: Compile a separate program for each library. + for i in $deplibs; do + case $i in + -l*) + func_stripname -l '' "$i" + name=$func_stripname_result + $opt_dry_run || $RM conftest + if $LTCC $LTCFLAGS -o conftest conftest.c $i; then + ldd_output=`ldd conftest` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $i "*) + func_append newdeplibs " $i" + i="" + ;; + esac + fi + if test -n "$i" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + deplib_matches=`eval "\\$ECHO \"$library_names_spec\""` + set dummy $deplib_matches; shift + deplib_match=$1 + if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then + func_append newdeplibs " $i" + else + droppeddeps=yes + echo + $ECHO "*** Warning: dynamic linker does not accept needed library $i." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because a test_compile did reveal that the linker did not use this one" + echo "*** as a dynamic dependency that programs can get resolved with at runtime." + fi + fi + else + droppeddeps=yes + echo + $ECHO "*** Warning! Library $i is needed by this library but I was not able to" + echo "*** make it link in! You will probably need to install it or some" + echo "*** library that it depends on before this library will be fully" + echo "*** functional. Installing it before continuing would be even better." + fi + ;; + *) + func_append newdeplibs " $i" + ;; + esac + done + fi + ;; + file_magic*) + set dummy $deplibs_check_method; shift + file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + if test -n "$file_magic_glob"; then + libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob` + else + libnameglob=$libname + fi + test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + if test "$want_nocaseglob" = yes; then + shopt -s nocaseglob + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/openair-cn/missing b/openair-cn/missing new file mode 100644 index 0000000000..86a8fc31e3 --- /dev/null +++ b/openair-cn/missing @@ -0,0 +1,331 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2012-01-06.13; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to <bug-automake@gnu.org>." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/openair-cn/valgrind.sh b/openair-cn/valgrind.sh new file mode 100644 index 0000000000..e353645435 --- /dev/null +++ b/openair-cn/valgrind.sh @@ -0,0 +1,2 @@ +#!/bin/sh +valgrind --tool=memcheck --leak-check=full --show-reachable=yes --num-callers=20 --track-origins=yes --track-fds=yes ./objs/OAISIM_MME/oaisim_mme 2>leakage \ No newline at end of file -- 2.26.2