Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members

pana_client.cxx

00001 /* BEGIN_COPYRIGHT                                                        */
00002 /*                                                                        */
00003 /* Open Diameter: Open-source software for the Diameter and               */
00004 /*                Diameter related protocols                              */
00005 /*                                                                        */
00006 /* Copyright (C) 2002-2004 Open Diameter Project                          */
00007 /*                                                                        */
00008 /* This library is free software; you can redistribute it and/or modify   */
00009 /* it under the terms of the GNU Lesser General Public License as         */
00010 /* published by the Free Software Foundation; either version 2.1 of the   */
00011 /* License, or (at your option) any later version.                        */
00012 /*                                                                        */
00013 /* This library is distributed in the hope that it will be useful,        */
00014 /* but WITHOUT ANY WARRANTY; without even the implied warranty of         */
00015 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      */
00016 /* Lesser General Public License for more details.                        */
00017 /*                                                                        */
00018 /* You should have received a copy of the GNU Lesser General Public       */
00019 /* License along with this library; if not, write to the Free Software    */
00020 /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307    */
00021 /* USA.                                                                   */
00022 /*                                                                        */
00023 /* In addition, when you copy and redistribute some or the entire part of */
00024 /* the source code of this software with or without modification, you     */
00025 /* MUST include this copyright notice in each copy.                       */
00026 /*                                                                        */
00027 /* If you make any changes that are appeared to be useful, please send    */
00028 /* sources that include the changed part to                               */
00029 /* diameter-developers@lists.sourceforge.net so that we can reflect your  */
00030 /* changes to one unified version of this software.                       */
00031 /*                                                                        */
00032 /* END_COPYRIGHT                                                          */
00033 
00034 #include "pana_client.h"
00035 #include "pana_device_id.h"
00036 #include "pana_serial_num.h"
00037 #include "pana_config_manager.h"
00038 
00039 void PANA_Client::SendDiscover()
00040 {
00041    /* Draft 3 notes:
00042       
00043       When a PaC attaches to a network, and knows that it has to discover
00044       PAA for PANA, it SHOULD send a PANA-PAA-Discover message to a well-
00045       known link local multicast address (TBD) and UDP port (TBD).  PANA
00046       PAA discovery assumes that PaC and PAA are one hop away from each
00047       other. If PaC knows the IP address of the PAA (some
00048       pre-configuration), it MAY unicast the PANA discovery message to that
00049       address. PAA SHOULD answer to the PANA-PAA-Discover message with a
00050       PANA-Start-Request message.
00051 
00052 
00053       PaC      PAA         Message 
00054       ------------------------------------------------------ 
00055       ----->            PANA-PAA-Discover(0,0) 
00056       <-----            PANA-Start-Request(x,0)[Cookie] 
00057       ----->            PANA-Start-Answer(x,y)[ Cookie] 
00058                         (continued to authentication phase) 
00059 
00060      9.3.2 PANA-PAA-Discover (PDI)
00061 
00062         The PANA-PAA-Discover (PDI) message is used to discover the address
00063         of PAA(s). Both sequence numbers in this message are set to zero (0).
00064         If the EP detects a new PaC and sends the PANA-PAA-Discover to the
00065         PAA, it MUST include the Device-Id of the PaC.
00066 
00067               PANA-PAA-Discover ::= < PANA-Header: 1 >
00068                         0*1 < Device-Id >
00069                         0*1 < Session-Id >
00070                          *  [ AVP ]
00071     */
00072 
00073    AAAAvpContainerManager cm;
00074    AAAAvpContainerEntryManager em;
00075    PANA_Message *msg;
00076 
00077    ACE_NEW_NORETURN(msg, PANA_Message);
00078    if (msg == NULL) {
00079       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00080                             "Failed to allocate msg message"));
00081    }
00082 
00083    // Populate header
00084    PANA_MsgHeader::Flags flg = { 0, 0, 0, 0 }; 
00085    msg->flags(flg);
00086    msg->type(PANA_MTYPE_DISCOVER);
00087    msg->tseq(0);
00088    msg->rseq(0);
00089 
00090    // Populate AVP's
00091    AAAAvpContainerEntry *e;
00092    AAAAvpContainer *c_deviceId = cm.acquire("Device-Id");
00093 
00094    // Add the AVP's to containers
00095    e = em.acquire(AAA_AVPDataType(AAA_AVP_DEVICEID_TYPE));
00096    PANA_TVData_t &deviceId = e->dataRef(Type2Type<PANA_TVData_t>());
00097    c_deviceId->add(e);
00098 
00099    // Add containers to list
00100    msg->avpList().add(c_deviceId);
00101 
00102    // check for pre-established session-id for re-auth
00103    if (m_SessionId.size() > 0) {
00104       AAAAvpContainer *c_sessionId = cm.acquire("Session-Id");
00105 
00106       // Add the AVP's to containers
00107       e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
00108       diameter_utf8string_t &sid = e->dataRef(Type2Type<diameter_utf8string_t>());
00109       c_sessionId->add(e);
00110 
00111       msg->avpList().add(c_sessionId);
00112       sid.assign(m_SessionId.data(), m_SessionId.size());
00113 
00114       // inherit sequence nums
00115       msg->tseq(++ m_LastTransmittedTsec);
00116       msg->rseq(m_LastReceivedTsec);
00117       
00118       // Notify EAP
00119       ReAuthenticate(PANA_REAUTH_EAP);
00120    }
00121 
00122    // resolve source address
00123    PANA_DeviceIdContainer srcDevices;
00124    m_TxChannel.GetLocalAddress(srcDevices);
00125 
00126    // Fill MAC address 
00127    PANA_DeviceId *id = srcDevices.search(PANA_DeviceId::LL_ADDRESS);
00128    if (id == NULL) {
00129       id = srcDevices.search(PANA_DeviceId::IPV4_ADDRESS);
00130    }
00131 
00132    if (id) {
00133       deviceId.type = id->type();
00134       deviceId.value.assign(id->id().data(), id->id().size());
00135    }
00136    else {
00137       throw (PANA_Exception(PANA_Exception::FAILED, 
00138                            "No device ID available"));
00139    }
00140 
00141    DestinationAddressFormatting(*msg);
00142    m_TxChannel.Send(*this, *msg);
00143 
00144    PANA_RtQueueNullData data;
00145    if (m_RtQueue.Schedule(data)) {
00146        m_Timer.Schedule(PANA_TID_DISC_RETRY, data.Timeout());       
00147    }
00148 
00149    ACE_DEBUG((LM_INFO, "(%P|%t) SEND: Discover, tseq=%d, rseq=%d\n",
00150               msg->tseq(), msg->rseq()));
00151 }
00152 
00153 void PANA_Client::RetryDiscover()
00154 {
00155    m_Timer.Cancel(PANA_TID_DISC_RETRY);
00156    
00157    PANA_RtQueueData *data = NULL;
00158    if (m_RtQueue.ReSchedule(data)) {
00159        SendDiscover();
00160        m_Timer.Schedule(PANA_TID_DISC_RETRY, data->Timeout());       
00161    }
00162    else {
00163        m_Timer.Schedule(PANA_TID_DISCONNECT, 0);
00164    }
00165 }
00166 
00167 void PANA_Client::ReceiveStartRequest()
00168 { 
00169    PANA_Message &msg = *(m_RxMessageQueue.front());
00170    m_RxMessageQueue.pop_front();
00171 
00172    ACE_DEBUG((LM_INFO, "(%P|%t) RECV: Start Req, S-flag %d, tseq=%d, rseq=%d\n",
00173                        msg.flags().separate, msg.tseq(), msg.rseq()));
00174 
00175    // cancel discovery retry
00176    m_Timer.Cancel(PANA_TID_DISC_RETRY);
00177    m_RtQueue.ClearFront();
00178    
00179    // extract NAP info if any
00180    AAAAvpContainer* c_napInfo = msg.avpList().search("NAP-Information");
00181    if (c_napInfo) {       
00182       diameter_grouped_t &nap = (*c_napInfo)[0]->dataRef
00183           (Type2Type<diameter_grouped_t>());
00184       PANA_ProviderInfoTool infoTool;
00185       infoTool.Extract(nap, m_PreferedNAP);
00186 
00187       ACE_DEBUG((LM_INFO, "(%P|%t) NAP information received: [%d] %s\n",
00188                  m_PreferedNAP.id_, m_PreferedNAP.name_.data()));      
00189    }
00190 
00191    // extract ISP info if any
00192    AAAAvpContainer* c_ispInfo = msg.avpList().search("ISP-Information");
00193    if (c_ispInfo) {
00194       m_IspSelected = IspSelection(c_ispInfo);
00195    }
00196 
00197    // initialize parts of session attributes
00198    m_InitialPaaTsec        = msg.tseq();
00199    m_InitialPacTsec        = PANA_SerialNumber::generateIsn(msg.tseq());
00200    m_LastTransmittedTsec   = m_InitialPacTsec;
00201    m_LastReceivedTsec      = msg.tseq();
00202    m_LastReceivedRsec      = msg.rseq();
00203    m_PeerPort              = msg.srcPort();
00204    m_PeerDeviceId.clone(msg.srcDevices());
00205    m_ReqDeviceId           = PANA_DeviceId::IPV4_ADDRESS;
00206 
00207    /*
00208       If the S-flag of the received PANA-Start-Request message is not set,
00209       PaC MUST NOT set the S-flag in the PANA-Start-Answer message sent
00210       back to the PAA.  In this case, PaC can indicate its choice of ISP by
00211       including its ISP-Information AVP in the PANA-Start-Answer message.
00212       AAA routing will be based on the ISP choice if an ISP-Information AVP
00213       is specified in the PANA-Start-Answer message, otherwise it will be
00214       based on EAP identifier.
00215       
00216       If the S-flag of the received PANA-Start-Request message is set, PaC
00217       can indicate its desire to perform separate EAP authentication for
00218       NAP and ISP by setting the S-flag in the PANA-Start-Answer message.
00219       In this case, PaC can also indicate its choice of ISP by including
00220       its ISP-Information AVP in the PANA-Start-Answer message.  AAA
00221       routing for NAP authentication will be based on the NAP.  AAA routing
00222       for ISP authentication will be based on the ISP choice if an
00223       ISP-Information AVP is specified in the PANA-Start-Answer message,
00224       otherwise it will be based on EAP identifier.  If the S-flag of the
00225       received PANA-Start-Request message is set and the S-flag of the
00226       corresponding PANA-Start-Answer message is not set, only one EAP
00227       authentication occurs without distinction between NAP and ISP
00228       authentications.  In this case, PaC can still indicate its choice of
00229       ISP by including its ISP-Information AVP in the PANA-Start-Answer
00230       message.
00231    */
00232    bool localSFlag = PANA_CONFIG_CLIENT().s_flag_ ? true : false;
00233    m_SeparateAuth = (msg.flags().separate) ? localSFlag : false;
00234    
00235    /*
00236       Start EAP processing
00237     */
00238    static_cast<PANA_ClientEventInterface&>(m_Event).EapStart();
00239 
00240    /*
00241       When a Cookie-AVP is carried in a PANA-Start-Request message, the
00242       initial EAP Request MUST NOT be carried in the PANA-Start-Request
00243       message in order for the PAA to be stateless.
00244    */
00245 
00246    // extract cookie and eap payload if any
00247    AAAAvpContainer *c_cookie = msg.avpList().search("Cookie");
00248    AAAAvpContainer* c_eapPayload = msg.avpList().search("EAP-Payload");
00249    if (c_cookie) {
00250        m_Cookie = (*c_cookie)[0]->dataRef
00251            (Type2Type<diameter_octetstring_t>());
00252        if (c_eapPayload) {
00253            throw (PANA_Exception(PANA_Exception::FAILED, 
00254                                  "Both cookie and EAP AVP present in PSR"));
00255        }
00256        SendStartAnswer(NULL);
00257    }
00258    else if (c_eapPayload) {
00259        diameter_octetstring_t &eapPayload = (*c_eapPayload)[0]->
00260            dataRef(Type2Type<diameter_octetstring_t>());
00261 
00262        m_InStatefulDiscovery = true;
00263        
00264        AAAMessageBlock *block = AAAMessageBlock::Acquire
00265            ((char*)eapPayload.data(), eapPayload.size());              
00266        static_cast<PANA_ClientEventInterface&>(m_Event).EapRequest
00267            (block, PANA_PINFO_NONE);
00268        block->Release();
00269    }
00270    else {
00271        SendStartAnswer(NULL);
00272    }
00273 }
00274 
00275 void PANA_Client::SendStartAnswer(AAAMessageBlock *response)
00276 {
00277    /*
00278       When a PaC receives the PANA-Start-Request message in response to the
00279       PANA-PAA-Discover message, it responds with a PANA-Start-Answer
00280       message if it wishes to enter the authentication phase.  The
00281       PANA-Start-Answer message contains the initial sequence numbers in
00282       the tseq and rseq fields of the PANA header, a copy of the received
00283       Cookie (if any) as the PANA payload.
00284 
00285       If the S-flag of the received PANA-Start-Request message is not set,
00286       PaC MUST NOT set the S-flag in the PANA-Start-Answer message sent
00287       back to the PAA.  In this case, PaC can indicate its choice of ISP by
00288       including its ISP-Information AVP in the PANA-Start-Answer message.
00289       AAA routing will be based on the ISP choice if an ISP-Information AVP
00290       is specified in the PANA-Start-Answer message, otherwise it will be
00291       based on EAP identifier.
00292 
00293      9.3.4 PANA-Start-Answer (PSA)
00294 
00295        PANA-Start-Answer (PSA) is sent by the PaC to the PAA in response to
00296        a PANA-Start-Request message.  The PANA_start message transmission
00297        sequence number field is copied to the received sequence number
00298        field.  The transmission sequence number is set to initial random
00299        value.
00300 
00301              PANA-Start-Answer ::= < PANA-Header: 2 [SEP] >
00302                             [ Cookie ]
00303                             [ EAP-Payload ]
00304                             [ ISP-Information ]
00305                          *  [ AVP ]
00306     */
00307 
00308    AAAAvpContainerManager cm;
00309    AAAAvpContainerEntryManager em;
00310    PANA_Message *msg;
00311 
00312    ACE_NEW_NORETURN(msg, PANA_Message);
00313    if (msg == NULL) {
00314       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00315                            "Failed to allocate start answer message"));
00316    }
00317 
00318    // Populate header
00319    PANA_MsgHeader::Flags flg = { 0, 0, 0, 0 }; // answer
00320    msg->flags(flg);
00321    msg->type(PANA_MTYPE_START);
00322    msg->tseq(m_InitialPacTsec);
00323    msg->rseq(m_LastReceivedTsec);
00324    msg->flags().separate = m_SeparateAuth;
00325 
00326    // Populate AVP's
00327    AAAAvpContainerEntry *e;
00328    if (response == NULL) {
00329       // Setup cookie avp 
00330       AAAAvpContainer *c_cookie = cm.acquire("Cookie");
00331       e = em.acquire(AAA_AVPDataType(AAA_AVP_STRING_TYPE));
00332       diameter_octetstring_t &dest_cookie = e->dataRef(Type2Type<diameter_octetstring_t>());
00333       c_cookie->add(e);
00334 
00335       // Add containers to list
00336       msg->avpList().add(c_cookie);
00337 
00338       // Populate cookie
00339       dest_cookie.assign(m_Cookie.data(), m_Cookie.size());
00340    }
00341    else {
00342       // Setup eap payload
00343       AAAAvpContainer *c_eapPayload = cm.acquire("EAP-Payload");
00344       e = em.acquire(AAA_AVP_STRING_TYPE);
00345       diameter_octetstring_t &eapPayload = e->dataRef(Type2Type<diameter_octetstring_t>());
00346       c_eapPayload->add(e);
00347 
00348       // Add containers to listen
00349       msg->avpList().add(c_eapPayload);
00350 
00351       // Populate eap payload
00352       eapPayload.assign(response->base(), response->size());
00353 
00354       // done with stateful discovery
00355       m_InStatefulDiscovery = false;
00356    }
00357 
00358    // Populate ISP-Information if ANY
00359    if (m_IspSelected) {
00360        
00361        ACE_DEBUG((LM_INFO, "(%P|%t) Selected ISP: [id=%d] %s\n",
00362                   m_PreferedISP.id_, m_PreferedISP.name_.data()));
00363        
00364        AAAAvpContainer *c_ispInfo = cm.acquire("ISP-Information");        
00365        e = em.acquire(AAA_AVP_GROUPED_TYPE);
00366        diameter_grouped_t &ispInfo = e->dataRef(Type2Type<diameter_grouped_t>());
00367        c_ispInfo->add(e);
00368 
00369        // Add containers to list and populate
00370        msg->avpList().add(c_ispInfo);
00371        PANA_ProviderInfoTool infoTool;
00372        infoTool.Add(ispInfo, m_PreferedISP);
00373    }
00374 
00375    // send session-id avp if session resumption
00376    if (PANA_CONFIG_GENERAL().mobility_) {
00377 
00378       AAAAvpContainerEntry *e;
00379       AAAAvpContainer *c_sessionId = cm.acquire("Session-Id");
00380 
00381       // Add the AVP's to containers
00382       e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
00383       diameter_utf8string_t &sid = e->dataRef(Type2Type<diameter_utf8string_t>());
00384       c_sessionId->add(e);
00385 
00386       msg->avpList().add(c_sessionId);
00387       sid.assign(m_SessionId.data(), m_SessionId.size());
00388   }
00389 
00390   DestinationAddressFormatting(*msg);
00391   m_TxChannel.Send(*this, *msg);
00392 
00393   ACE_DEBUG((LM_INFO, "(%P|%t) SEND: Start-Answer, tseq=%d, rseq=%d\n",
00394              msg->tseq(), msg->rseq()));
00395 
00396   PANA_RtQueueMsgBlockData data(response);
00397   if (m_RtQueue.Schedule(data)) {
00398       m_Timer.Schedule(PANA_TID_PSA_RETRY, data.Timeout());       
00399   }
00400 }
00401 
00402 void PANA_Client::RetryStartAnswer()
00403 {
00404    m_Timer.Cancel(PANA_TID_PSA_RETRY);
00405    
00406    PANA_RtQueueData *data = NULL;
00407    if (m_RtQueue.ReSchedule(data)) {
00408        SendStartAnswer(static_cast<PANA_RtQueueMsgBlockData*>(data)->MsgBlock());
00409        m_Timer.Schedule(PANA_TID_PSA_RETRY, data->Timeout());       
00410    }
00411    else {
00412        m_Timer.Schedule(PANA_TID_DISCONNECT, 0);
00413    }
00414 }
00415 
00416 void PANA_Client::ReceiveEapRequest()
00417 {
00418    PANA_Message &msg = *(m_RxMessageQueue.front());
00419    m_RxMessageQueue.pop_front();
00420 
00421    ACE_DEBUG((LM_INFO, "(%P|%t) RECV: EAP-Request, S-flag %d, tseq=%d, rseq=%d\n",
00422               msg.flags().separate, msg.tseq(), msg.rseq()));
00423 
00424    // cancel discovery retry if any
00425    m_Timer.Cancel(PANA_TID_DISC_RETRY);
00426    m_RtQueue.ClearFront();
00427    
00428    // cancel start answer retry if any
00429    m_Timer.Cancel(PANA_TID_PSA_RETRY);
00430    m_RtQueue.ClearFront();
00431 
00432    if (m_SessionId.size() == 0) {
00433       // save session id
00434       AAAAvpContainer *c_sessionId = msg.avpList().search("Session-Id");
00435       diameter_utf8string_t &id = (*c_sessionId)[0]->dataRef(Type2Type<diameter_utf8string_t>());
00436       m_SessionId.assign(id.data(), id.size());
00437    }
00438 
00439    // extract EAP payload
00440    AAAAvpContainer* c_eapPayload = msg.avpList().search("EAP-Payload");
00441    diameter_octetstring_t &eapPayload = (*c_eapPayload)[0]->dataRef(Type2Type<diameter_octetstring_t>());
00442 
00443    // invoke application handler
00444    AAAMessageBlock *block = AAAMessageBlock::Acquire((char*)eapPayload.data(), 
00445                                                      eapPayload.size());              
00446 
00447    AAAAvpContainer *c_pInfo;
00448    diameter_grouped_t *pList = NULL;
00449    PANA_PINFO type = PANA_PINFO_NONE;
00450 
00451    // NAP/ISP processing
00452    if ((c_pInfo = msg.avpList().search("NAP-Information"))) {
00453        pList = (*c_pInfo)[0]->dataPtr(Type2Type<diameter_grouped_t>());
00454        type = PANA_PINFO_NAP;
00455    }
00456    else if ((c_pInfo = msg.avpList().search("ISP-Information"))) {
00457        pList = (*c_pInfo)[0]->dataPtr(Type2Type<diameter_grouped_t>());
00458        type = PANA_PINFO_ISP;
00459    }
00460 
00461    // invoke the EAP handler
00462    if (pList) {
00463        PANA_CfgProviderInfo pInfo;
00464        PANA_ProviderInfoTool infoTool;
00465        infoTool.Extract(*pList, pInfo);
00466        static_cast<PANA_ClientEventInterface&>(m_Event).EapRequest(block, type, &pInfo);
00467    }
00468    else {
00469        static_cast<PANA_ClientEventInterface&>(m_Event).EapRequest(block, type);
00470    }
00471    block->Release();
00472    delete &msg;
00473 }
00474 
00475 void PANA_Client::ReceiveEapReAuthRequest()
00476 {
00477    PANA_Message &msg = *(m_RxMessageQueue.front());
00478    m_RxMessageQueue.pop_front();
00479 
00480    ACE_DEBUG((LM_INFO, "(%P|%t) RECV: EAP-ReAuth-Request, S-flag %d, tseq=%d, rseq=%d\n",
00481               msg.flags().separate, msg.tseq(), msg.rseq()));
00482 
00483    // notify EAP
00484    ReAuthenticate(PANA_REAUTH_EAP);
00485    
00486    // extract EAP payload
00487    AAAAvpContainer* c_eapPayload = msg.avpList().search("EAP-Payload");
00488    diameter_octetstring_t &eapPayload = (*c_eapPayload)[0]->dataRef(Type2Type<diameter_octetstring_t>());
00489 
00490    // invoke application handler
00491    AAAMessageBlock *block = AAAMessageBlock::Acquire((char*)eapPayload.data(), 
00492                                                      eapPayload.size());              
00493 
00494    static_cast<PANA_ClientEventInterface&>(m_Event).EapRequest(block, PANA_PINFO_NONE);
00495    block->Release();
00496    delete &msg;
00497 }
00498 
00499 void PANA_Client::SendEapResponse(AAAMessageBlock *response)
00500 {
00501    /*
00502        PaC      PAA  Message(tseq,rseq)[AVPs] 
00503        ------------------------------------------------- 
00504                      (continued from discovery and initial handshake phase) 
00505           <-----     PANA-Auth-Request(x+1,y)[EAP{Request}] 
00506           ----->     PANA-Auth-Answer(y+1,x+1)[EAP{Response}] 
00507             . 
00508             . 
00509           <-----     PANA-Auth-Request (x+2,y+1)[EAP{Request}] 
00510           ----->     PANA-Auth-Answer (y+2,x+2)[EAP{Response}] 
00511           <-----     PANA-Bind-Request(x+3,y+2)                // F-flag 
00512        set 
00513                        [EAP{Success}, Device-Id, Protection-Cap., MAC]  
00514           ----->     PANA-Bind-Answer(y+3,x+3) 
00515                        [Device-Id, Protection-Cap., MAC]  // F-flag set 
00516 
00517       9.3.6 PANA-Auth-Answer (PAN)
00518 
00519          PANA-Auth-Answer (PAN) is sent by the PaC to the PAA in response to a
00520          PANA-Auth-Request message.
00521 
00522               PANA-Auth-Answer ::= < PANA-Header: 3 >
00523                             < Session-Id >
00524                             < EAP-Payload >
00525                          *  [ AVP ]
00526                         0*1 < MAC >
00527     */
00528    AAAAvpContainerManager cm;
00529    AAAAvpContainerEntryManager em;
00530    PANA_Message *msg;
00531 
00532    ACE_NEW_NORETURN(msg, PANA_Message);
00533    if (msg == NULL) {
00534       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00535                            "Failed to allocate msg message"));
00536    }
00537 
00538    // Populate header
00539    PANA_MsgHeader::Flags flg = { 0, 0, 0, 0 }; // TBD: answer
00540    msg->flags(flg);
00541    msg->type(PANA_MTYPE_AUTH);
00542    msg->tseq(++ m_LastTransmittedTsec);
00543    msg->rseq(m_LastReceivedTsec);
00544 
00545    // Populate AVP's
00546    AAAAvpContainerEntry *e;
00547    AAAAvpContainer *c_sessionId = cm.acquire("Session-Id");
00548    AAAAvpContainer *c_eapPayload = cm.acquire("EAP-Payload");
00549 
00550    // Add the AVP's to containers
00551    e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
00552    diameter_utf8string_t &sessionId = e->dataRef(Type2Type<diameter_utf8string_t>());
00553    c_sessionId->add(e);
00554 
00555    e = em.acquire(AAA_AVP_STRING_TYPE);
00556    diameter_octetstring_t &eapPayload = e->dataRef(Type2Type<diameter_octetstring_t>());
00557    c_eapPayload->add(e);
00558 
00559    // Add containers to listen
00560    msg->avpList().add(c_sessionId);
00561    msg->avpList().add(c_eapPayload);
00562 
00563    /*
00564      The EAP-Payload AVP (AVP Code 402) is of type OctetString and 
00565      is used to encapsulate the actual EAP packet [RFC2284] that is 
00566      being exchanged between the EAP client and the home Diameter 
00567      server.
00568     */
00569 
00570    sessionId.assign(m_SessionId.data(), m_SessionId.size());
00571    eapPayload.assign(response->base(), response->size());
00572 
00573    DestinationAddressFormatting(*msg, response);
00574    m_TxChannel.Send(*this, *msg);
00575 
00576    ACE_DEBUG((LM_INFO, "(%P|%t) SEND: EAP-Response, tseq=%d, rseq=%d\n",
00577               msg->tseq(), msg->rseq()));
00578 }
00579 
00580 void PANA_Client::ReceiveBindRequest()
00581 {
00582    PANA_Message &msg = *(m_RxMessageQueue.front());
00583    m_RxMessageQueue.pop_front();
00584 
00585    // cancel discovery retry if any
00586    m_Timer.Cancel(PANA_TID_DISC_RETRY);
00587    m_RtQueue.ClearFront();
00588    
00589    // cancel start answer retry if any
00590    m_Timer.Cancel(PANA_TID_PSA_RETRY);
00591    m_RtQueue.ClearFront();
00592 
00593    if (BindResult() == PANA_BIND_SUCCESS_FINAL) {      
00594       AAAAvpContainer* c_sessionLifetime = msg.avpList().search
00595           ("Session-Lifetime");
00596       if (c_sessionLifetime) {
00597          diameter_unsigned32_t &sessLifetime = (*c_sessionLifetime)
00598                  [0]->dataRef(Type2Type<diameter_unsigned32_t>());
00599          m_SessionLifetime = sessLifetime;
00600          m_Timer.Schedule(PANA_TID_SESSION, sessLifetime);
00601       }
00602    }
00603                
00604    // extract EAP payload
00605    AAAAvpContainer* c_eapPayload = msg.avpList().search("EAP-Payload");
00606    if (c_eapPayload == NULL) {
00607       throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00608                            "PANA client received bind msg with no EAP payload"));
00609    }
00610    diameter_octetstring_t &eapPayload = (*c_eapPayload)[0]->dataRef(
00611        Type2Type<diameter_octetstring_t>());
00612 
00613    AAAMessageBlock *block = AAAMessageBlock::Acquire((char*)eapPayload.data(), 
00614                                                      eapPayload.size());
00615 
00616    AAAAvpContainer* c_rcode = msg.avpList().search("Result-Code");
00617    if (c_rcode == NULL) {
00618       throw (PANA_Exception(PANA_Exception::INVALID_MESSAGE, 
00619                            "PANA client received bind msg with no result code"));
00620    }
00621    diameter_unsigned32_t &rcode = (*c_rcode)[0]->dataRef(Type2Type<diameter_unsigned32_t>());
00622 
00623    diameter_unsigned32_t pcap = PANA_PCAP_UNKNOWN;
00624    AAAAvpContainer* c_pcap = msg.avpList().search("Protection-Capability");
00625    if (c_pcap) {
00626        pcap = (*c_pcap)[0]->dataRef(Type2Type<diameter_unsigned32_t>());
00627    }
00628 
00629    AAAAvpContainer* c_keyId = msg.avpList().search("Key-Id");
00630    if (c_keyId) {
00631        diameter_integer32_t &id = (*c_keyId)[0]->dataRef
00632            (Type2Type<diameter_integer32_t>());
00633        if (m_SA.KeyId() != id) {
00634            m_SA.KeyId(id);
00635            m_RegenerateKey = true;
00636        }
00637    }
00638 
00639    PANA_DeviceIdContainer epId;
00640    AAAAvpContainer* c_epId = msg.avpList().search("EP-Device-Id");
00641    if (c_epId) {
00642        for (unsigned int i=0; i<c_epId->size(); i++) {           
00643            PANA_TVData_t &deviceId = (*c_epId)[i]->dataRef(Type2Type<PANA_TVData_t>());
00644            PANA_DeviceId newId(PANA_DeviceId::TYPE(deviceId.type));
00645            std::string &value = const_cast<std::string&>(newId.id());
00646            value.assign(deviceId.value.data(), deviceId.value.size());
00647            epId.clone(newId);
00648        }
00649    }
00650    
00651    AAAAvpContainer* c_deviceId = msg.avpList().search("Device-Id");
00652    if (c_deviceId) {
00653        PANA_TVData_t &deviceId = (*c_deviceId)[0]->dataRef(Type2Type<PANA_TVData_t>());
00654        m_ReqDeviceId = PANA_DeviceId::TYPE(deviceId.type);
00655    }
00656 
00657    ACE_DEBUG((LM_INFO, "(%P|%t) RECV: Bind-Request, tseq=%d, rseq=%d\n",
00658               msg.tseq(), msg.rseq()));
00659 
00660    static_cast<PANA_ClientEventInterface&>(m_Event).EapRequest
00661        (block, rcode, pcap, epId);
00662    block->Release();
00663 
00664    if (BindResult() == PANA_BIND_FAILED) {
00665        // For INITIAL, INTERIM and FINAL, API must
00666        // be called to send a bind answer
00667        SendBindAnswer();
00668        PANA_Session::Disconnect(PANA_TC_ADMINISTRATIVE);
00669    }
00670    delete &msg;
00671 }
00672 
00673 void PANA_Client::SendBindAnswer()
00674 {
00675    /*
00676        PaC      PAA  Message(tseq,rseq)[AVPs] 
00677        ------------------------------------------------- 
00678                      (continued from discovery and initial handshake phase) 
00679           <-----     PANA-Auth-Request(x+1,y)[EAP{Request}] 
00680           ----->     PANA-Auth-Answer(y+1,x+1)[EAP{Response}] 
00681             . 
00682             . 
00683           <-----     PANA-Auth-Request (x+2,y+1)[EAP{Request}] 
00684           ----->     PANA-Auth-Answer (y+2,x+2)[EAP{Response}] 
00685           <-----     PANA-Bind-Request(x+3,y+2) // F-flag set 
00686                        [EAP{Success}, Device-Id, Protection-Cap., MAC]  
00687           ----->     PANA-Bind-Answer(y+3,x+3) 
00688                        [Device-Id, Protection-Cap., MAC]  // F-flag set 
00689 
00690        9.3.8 PANA-Bind-Answer (PBA)
00691 
00692         PANA-Bind-Answer (PBA) is sent by the PaC to the PAA in response to a
00693         PANA-Result-Request message.
00694 
00695               PANA-Bind-Answer ::= < PANA-Header: 4 >
00696                             < Session-Id >
00697                             < Device-Id >
00698                             [ Key-Id ]
00699                          *  [ AVP ]
00700                         0*1 < MAC >
00701    */
00702 
00703    AAAAvpContainerManager cm;
00704    AAAAvpContainerEntryManager em;
00705    PANA_Message *msg;
00706 
00707    ACE_NEW_NORETURN(msg, PANA_Message);
00708    if (msg == NULL) {
00709       throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00710                            "Failed to allocate msg message"));
00711    }
00712 
00713    // Populate header
00714    PANA_MsgHeader::Flags flg = { 0, 0, 0, 0 }; // answer
00715    msg->flags(flg);
00716    msg->type(PANA_MTYPE_BIND);
00717    msg->tseq(++ m_LastTransmittedTsec);
00718    msg->rseq(m_LastReceivedTsec);
00719 
00720    // Populate AVP's
00721    AAAAvpContainerEntry *e;
00722    AAAAvpContainer *c_sessionId = cm.acquire("Session-Id");
00723    AAAAvpContainer *c_deviceId = cm.acquire("Device-Id");
00724 
00725    // Add the AVP's to containers
00726    e = em.acquire(AAA_AVP_UTF8_STRING_TYPE);
00727    diameter_utf8string_t &sessionId = e->dataRef(Type2Type<diameter_utf8string_t>());
00728    c_sessionId->add(e);
00729 
00730    e = em.acquire(AAA_AVPDataType(AAA_AVP_DEVICEID_TYPE));
00731    PANA_TVData_t &deviceId = e->dataRef(Type2Type<PANA_TVData_t>());
00732    c_deviceId->add(e);
00733 
00734    // Add containers to list
00735    msg->avpList().add(c_sessionId);
00736    msg->avpList().add(c_deviceId);
00737 
00738    // Fill session id
00739    sessionId.assign(m_SessionId.data(), m_SessionId.size());
00740 
00741    // resolve source address
00742    PANA_DeviceIdContainer srcDevices;
00743    m_TxChannel.GetLocalAddress(srcDevices);
00744 
00745    // Fill device id
00746    PANA_DeviceId *id = srcDevices.search(m_ReqDeviceId);
00747    if (id == NULL) {
00748       throw (PANA_Exception(PANA_Exception::FAILED, 
00749             "No IPV4/MAC address given in the peer device list"));
00750    }
00751    deviceId.type = id->type();
00752    deviceId.value.assign(id->id().data(), id->id().size());
00753 
00754    // Fill in key id
00755    if (m_SA.MSK().length() > 0) {
00756        
00757        AAAAvpContainer *c_keyId = cm.acquire("Key-Id");
00758        
00759        e = em.acquire(AAA_AVP_INTEGER32_TYPE);
00760        diameter_integer32_t &keyId = e->dataRef(Type2Type<diameter_integer32_t>());
00761        c_keyId->add(e);
00762        
00763        msg->avpList().add(c_keyId);
00764        keyId = m_SA.KeyId();
00765        
00766        ACE_DEBUG((LM_INFO, "(%P|%t) key id=%d\n", id));
00767    }
00768    
00769    DestinationAddressFormatting(*msg);
00770    m_TxChannel.Send(*this, *msg);
00771 
00772    ACE_DEBUG((LM_INFO, "(%P|%t) SEND: Bind-Answer, tseq=%d, rseq=%d\n",
00773               msg->tseq(), msg->rseq()));
00774 }
00775 
00776 void PANA_Client::DestinationAddressFormatting(PANA_Message &msg,
00777                                                AAAMessageBlock *eapPayload)
00778 {
00779    // Save the payload
00780    if (eapPayload) {
00781       if (m_LastPayload) {
00782          m_LastPayload->Release();
00783       }
00784       m_LastPayload = AAAMessageBlock::Acquire(eapPayload);
00785    }
00786 
00787    PANA_CfgClient &c = PANA_CONFIG_CLIENT();
00788 
00789    // compute output address
00790    PANA_DeviceId *ipId, *hwId;
00791 
00792    // Proper destination IP address hierarchy is as follows:
00793    //   a. locally stored peer device id if present
00794    //   b. configured ip address if present
00795    //   c. configured mcast address if present
00796    //   d. undeliverable if not found
00797    ipId = m_PeerDeviceId.search(PANA_DeviceId::IPV4_ADDRESS);
00798    if (ipId) {
00799       msg.srcDevices().clone(*ipId);
00800       msg.srcPort(m_PeerPort);
00801    }
00802    else {
00803       // have to compute peer IP address
00804       std::string *destIp;
00805 
00806       if (c.paa_ip_address_.size() > 0) {
00807          destIp = &c.paa_ip_address_;
00808          msg.srcPort(PANA_CONFIG_CLIENT().paa_port_number_);
00809       }
00810       else if (c.paa_mcast_address_.size() > 0) {
00811          destIp = &c.paa_mcast_address_;
00812          msg.srcPort(PANA_CONFIG_CLIENT().paa_mcast_port_number_);
00813       }
00814       else {
00815          throw (PANA_Exception(PANA_Exception::FAILED, 
00816                               "Unable to configure a destination address"));
00817       }
00818 
00819       char buf[64];
00820       ACE_OS::sprintf(buf, "%s:%d", destIp->data(), c.paa_port_number_);
00821       ACE_INET_Addr paaAddr(buf);
00822 
00823       ACE_NEW_NORETURN(ipId, PANA_DeviceId(PANA_DeviceId::IPV4_ADDRESS));
00824 
00825       if (ipId == NULL) {
00826          throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00827                               "Failed to allocate IP device id"));
00828       }
00829 
00830       ACE_UINT32 ipAddr = paaAddr.get_ip_address();
00831       const_cast<std::string&>(ipId->id()).assign((char*)&ipAddr, sizeof(ACE_UINT32));
00832 
00833       msg.srcDevices().push_back(ipId);
00834    }
00835 
00836    // Proper destination L2 address hierarchy is as follows:
00837    //   a. locally stored peer device id if present
00838    hwId = m_PeerDeviceId.search(PANA_DeviceId::LL_ADDRESS);
00839    if (hwId) {
00840       msg.srcDevices().clone(*hwId);
00841    }
00842 }
00843 
00844 bool PANA_Client::IspSelection(AAAAvpContainer* c_ispInfo)
00845 {
00846    ACE_DEBUG((LM_INFO, "(%P|%t) ISP information received [count=%d]\n", c_ispInfo->size()));
00847 
00848    PANA_CfgProviderList ispList;
00849    PANA_CfgProviderList::iterator n;
00850    PANA_CfgProviderInfo *ispInfo, *ispChoice = NULL;
00851    
00852    try {
00853        // ask user to choose isp
00854        for (unsigned int i = 0; i < c_ispInfo->size(); i ++) {
00855 
00856           ACE_NEW_NORETURN(ispInfo, PANA_CfgProviderInfo);
00857           if (ispInfo) {
00858               PANA_ProviderInfoTool infoTool;
00859               diameter_grouped_t &isp = (*c_ispInfo)[i]->dataRef(Type2Type<diameter_grouped_t>());
00860               infoTool.Extract(isp, *ispInfo);
00861               ispList.push_back(ispInfo);
00862           }
00863           else {
00864              throw (PANA_Exception(PANA_Exception::NO_MEMORY, 
00865                                   "Failed to allocate ISP structure"));
00866           }
00867        }
00868 
00869        static_cast<PANA_ClientEventInterface&>(m_Event).ChooseISP(ispList, ispChoice);
00870        if (ispChoice) {
00871            throw(true);
00872        }
00873    
00874        // select from configuration
00875        if (PANA_CONFIG_CLIENT().isp_info_.name_.length() > 0) {
00876            for (n = ispList.begin(); n != ispList.end(); n++) {
00877                ispChoice = *n;
00878                if (PANA_CONFIG_CLIENT().isp_info_.name_ == ispChoice->name_) {
00879                    throw (true);
00880                }
00881            }
00882        }
00883        throw (false);
00884    }
00885    catch (const PANA_Exception &c) {
00886        ACE_UNUSED_ARG(c);
00887    }
00888    catch (bool rc) {
00889        if (rc) {
00890            m_PreferedISP.name_ = ispChoice->name_;
00891            m_PreferedISP.id_   = ispChoice->id_;
00892            
00893            ACE_DEBUG((LM_INFO, "(%P|%t) ISP information choosen: id=%d %s\n",
00894                  m_PreferedISP.id_, m_PreferedISP.name_.data()));      
00895        }
00896        n = ispList.begin();
00897        while (! ispList.empty()) {
00898            ispChoice = ispList.front();
00899            ispList.pop_front();
00900            delete ispChoice;
00901        }
00902        return (rc);
00903    }
00904    
00905    return (false);
00906 }

Generated on Fri Jun 25 19:18:29 2004 for PANA by doxygen 1.3.5