| /** | |
| * GGSN.java | |
| * | |
| * Core logic of GGSN | |
| **/ | |
| class PDPcontext { | |
| public int nsapi; | |
| public String imsi; | |
| //public int uplinkDataTeid; | |
| //public int downlinkDataTeid; | |
| } | |
| class GGSN extends StateMachine | |
| { | |
| private Charging charging; | |
| private CLI cli; | |
| private NodeConfiguration nodeConfiguration; | |
| private int uplinkData; | |
| private int downlinkData; | |
| private PDPcontext pdpContext; | |
| public GGSN(Charging charging, CLI cli, NodeConfiguration nodeConfiguration) | |
| { | |
| this.charging = charging; | |
| this.cli = cli; | |
| this.nodeConfiguration = nodeConfiguration; | |
| uplinkData = 0; | |
| downlinkData = 0; | |
| // NB: In our simplified view (for now) we only handle a single context, | |
| // but the model can be easily enhanced to handle multiple contexts. | |
| pdpContext = new PDPcontext(); | |
| } | |
| private void createPDPcontext(CreatePDPcontext request) | |
| { | |
| // Control incoming data values - Qtronic specific to | |
| // control test data generated for test suite. | |
| /** | |
| * Snippet of how it may look with a more or less | |
| * one-to-one mapping between model and GTPC data: | |
| require request.imsi_digits != null; | |
| require request.imsi_digits.length == IMSI_OCTETS; | |
| for (int i = 0; i < request.imsi_digits.length; i++) | |
| require request.imsi_digits[i] == imsi1[i]; | |
| require request.teidDataI != null; | |
| require request.teidDataI.length == TEID_OCTETS; | |
| for (int i = 0; i < request.teidDataI.length; i++) | |
| require request.teidDataI[i] == teid1[i]; | |
| **/ | |
| // Our simplified view on data | |
| require request.imsi == "240001111231411"; | |
| //require request.downlinkDataTeid == 1; | |
| require request.nsapi == 5; | |
| require request.apn == "apn1.com"; | |
| // Handle request - in our simplified view we handle | |
| // only one single PDP context. The state machine is | |
| // laid out so that a createPDPcontext will always be | |
| // done before any update, delete, or sending of payload. | |
| pdpContext.imsi = request.imsi; | |
| pdpContext.nsapi = request.nsapi; | |
| //pdpContext.downlinkDataTeid = request.downlinkDataTeid; | |
| //pdpContext.uplinkDataTeid = 3; | |
| } | |
| private void sendRadiusAuthRequest() | |
| { | |
| RadiusAccessRequest request; | |
| GiRadiusOut.send(request); | |
| requirement "Radius/Authentication/Send Access Request"; | |
| } | |
| private void confirmCreatePDPcontext() | |
| { | |
| // Send response back | |
| CreatePDPresponse response; | |
| response.causevalue = REQUEST_ACCEPTED; | |
| //response.uplinkDataTeid = pdpContext.uplinkDataTeid; | |
| GnOut.send(response); | |
| requirement "PDP context/Confirm successful creation"; | |
| } | |
| private void updatePDPcontext(UpdatePDPcontext request) | |
| { | |
| // TODO: what to do with update?? | |
| // Currently it seems TTCN libraries take care of both update | |
| // details and receiving the correct response, as well as doing | |
| // the pass/fail verdict. | |
| // We can have an "empty" update request in the model to just | |
| // trigger a call to the existing library update function, or | |
| // we can add more detail to the model and NOT use the existing | |
| // library update function. | |
| // 100114: we can handle the response to the update on the | |
| // model level for understanding, but regard it as a NOP on | |
| // the QtronicHarness level. | |
| require request.nsapi == pdpContext.nsapi; | |
| //require request.downlinkDataTeid == pdpContext.downlinkDataTeid; | |
| // Send response | |
| UpdatePDPresponse response; | |
| response.causevalue = REQUEST_ACCEPTED; | |
| GnOut.send(response); | |
| requirement "PDP context/Confirm successful update"; | |
| } | |
| private void deletePDPcontext(DeletePDPcontext request) | |
| { | |
| // Take care of request parameters | |
| require request.nsapi == pdpContext.nsapi; | |
| // Send response back | |
| DeletePDPresponse response; | |
| response.causevalue = REQUEST_ACCEPTED; | |
| GnOut.send(response); | |
| requirement "PDP context/Confirm successful deletion"; | |
| } | |
| // forwardGPDUtoGi() - when a GPDU is recieved on the Gn interface | |
| // the payload should be forwarded to the Gi interface | |
| private void forwardGPDUtoGi(GPDU pdu) | |
| { | |
| //require pdu.header.teid == pdpContext.uplinkDataTeid; | |
| // TODO: how much detail on model level? | |
| uplinkData++; | |
| charging.payload(pdu); | |
| // Forward payload | |
| UDPpdu udpPdu; | |
| udpPdu.data = pdu.data; | |
| GiOut.send(udpPdu); | |
| } | |
| // forwardUdpPduToGn() - when a UDP pdu is recieved on the Gi interface | |
| // it should be forwarded/tunneled to the Gn interface | |
| private void forwardUdpPduToGn(UDPpdu udpPdu) | |
| { | |
| // Forward/tunnel payload | |
| GPDU pdu; | |
| //pdu.header.teid = pdpContext.downlinkDataTeid; | |
| pdu.data = udpPdu.data; | |
| GnOut.send(pdu); | |
| // TODO: how much detail on model level? | |
| downlinkData++; | |
| charging.payload(pdu); | |
| } | |
| } | |
| void main() | |
| { | |
| NodeConfiguration nodeConfiguration = new NodeConfiguration(); | |
| Charging charging = new Charging(); | |
| CLI cli = new CLI(nodeConfiguration); | |
| GGSN ggsn = new GGSN(charging, cli, nodeConfiguration); | |
| ggsn.start("GGSN"); | |
| } |