File: ClntMsgConfirm.cpp

package info (click to toggle)
dibbler 1.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 13,352 kB
  • sloc: cpp: 60,323; ansic: 12,235; sh: 11,951; yacc: 3,418; lex: 969; makefile: 940; perl: 319; xml: 116; python: 74
file content (193 lines) | stat: -rw-r--r-- 5,793 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*
 * Dibbler - a portable DHCPv6
 *
 * authors: Tomasz Mrugalski <thomson@klub.com.pl>
 *          Marek Senderski <msend@o2.pl>
 * changes: Michal Kowalczuk <michal@kowalczuk.eu>
 *
 * released under GNU GPL v2 only licence
 *
 */

#include "SmartPtr.h"
#include "ClntMsgConfirm.h"
#include "OptDUID.h"
#include "ClntOptStatusCode.h"
#include "ClntOptIA_NA.h"
#include "DHCPConst.h"
#include "Logger.h"

//  iaLst - contain all IA's to  be checked (they have to be in the same link)
TClntMsgConfirm::TClntMsgConfirm(unsigned int iface,
                                 List(TAddrIA) iaLst)
    :TClntMsg(iface, SPtr<TIPv6Addr>(), CONFIRM_MSG) {

    IRT = CNF_TIMEOUT;
    MRT = CNF_MAX_RT;
    MRC = 0;
    MRD = CNF_MAX_RD;

    //The client sets the "msg-type" field to CONFIRM.  The client
    //generates a transaction ID and inserts this value in the
    //"transaction-id" field.

    //The client MUST include a Client Identifier option to identify itself
    //to the server.
    Options.push_back(new TOptDUID(OPTION_CLIENTID, ClntCfgMgr().getDUID(), this ) );
    //The client includes IA options for all of the IAs
    //assigned to the interface for which the Confirm message is being
    //sent.  The IA options include all of the addresses the client
    //currently has associated with those IAs.  The client SHOULD set the
    //T1 and T2 fields in any IA_NA options, and the preferred-lifetime and
    //valid-lifetime fields in the IA Address options to 0, as the server
    //will ignore these fields.
    SPtr<TAddrIA> ia;
    iaLst.first();
    while(ia=iaLst.get())
        Options.push_back(new TClntOptIA_NA(ia,true,this));

    appendRequestedOptions();
    appendElapsedOption();
    appendAuthenticationOption();

    IsDone = false;
    send();
}

void TClntMsgConfirm::answer(SPtr<TClntMsg> reply)
{
    SPtr <TClntOptStatusCode> status;
    status = (Ptr*) reply->getOption(OPTION_STATUS_CODE);
    if (!status) {
        Log(Warning) << "Received malformed REPLY for CONFIRM: no status option." << LogEnd;
        addrsRejected();
	return;
    }
    switch (status->getCode() ) {
    case STATUSCODE_SUCCESS:
        addrsAccepted();
        IsDone = true;
        break;
    case STATUSCODE_NOTONLINK:
        addrsRejected();
        IsDone = true;
        break;
    case STATUSCODE_UNSPECFAIL:
    case STATUSCODE_NOADDRSAVAIL:
    case STATUSCODE_NOBINDING:
    case STATUSCODE_USEMULTICAST:
    default:
        Log(Warning) << "REPLY for CONFIRM received with invalid ("
                     << status->getCode() << ") status code." << LogEnd;
        break;
    }
    return;

}

void TClntMsgConfirm::addrsAccepted() {
    SPtr<TAddrIA> ptrIA;
    SPtr<TOpt> ptrOpt;
    this->firstOption();
    SPtr<TAddrAddr> ptrAddrAddr;
    while ( ptrOpt = this->getOption() ) {
        if (ptrOpt->getOptType()!=OPTION_IA_NA)
            continue;

        SPtr<TClntOptIA_NA> ptrOptIA = (Ptr*) ptrOpt;
        ptrIA = ClntAddrMgr().getIA( ptrOptIA->getIAID() );
        if (!ptrIA)
            continue;

        // Uncomment this line if you don't want RENEW to be sent after
        // CONFIRM exchange is complete
        ptrIA->setState(STATE_CONFIGURED);

	// Once confirmed, this triggers the
        ptrIA->setTimestamp( (uint32_t)time(NULL) - ptrIA->getT1() );
	
	SPtr<TIfaceIface> ptrIface = ClntIfaceMgr().getIfaceByID(ptrIA->getIfindex());
	if (!ptrIface)
	  continue;
	
	ptrIA->firstAddr();
	while (ptrAddrAddr = ptrIA->getAddr()) {
            ptrIface->addAddr(ptrAddrAddr->get(),ptrAddrAddr->getPref(),
			      ptrAddrAddr->getValid(), ptrIface->getPrefixLength());
	}
    }
}

void TClntMsgConfirm::addrsRejected() {
    SPtr<TAddrIA> ptrIA;
    SPtr<TOpt> ptrOpt;
    this->firstOption();
    while ( ptrOpt = this->getOption() ) {
        if (ptrOpt->getOptType()!=OPTION_IA_NA)
            continue;

        SPtr<TClntOptIA_NA> ptrOptIA = (Ptr*) ptrOpt;
        ptrIA = ClntAddrMgr().getIA(ptrOptIA->getIAID());
        if (!ptrIA)
            continue;

        // release all addrs
        SPtr<TIfaceIface> ptrIface;
        ptrIface = ClntIfaceMgr().getIfaceByID(ptrIA->getIfindex());
        if (!ptrIface) {
            Log(Crit) << "We have addresses assigned to non-existing interface."
                "Help! Somebody stole an interface!" << LogEnd;
            ptrIA->setState(STATE_NOTCONFIGURED);
            return;
        }
        SPtr<TAddrAddr> ptrAddr;
        ptrIA->firstAddr();
        while (ptrAddr = ptrIA->getAddr() ) {
            // remove addr from ...
            ptrIface->delAddr( ptrAddr->get(), ptrIface->getPrefixLength() );
            // ... and from DB
            ptrIA->delAddr( ptrAddr->get() );
        }

        //not only the address should be rejected, but also the original IA should be deleted and using a new IA to process SOLICIT
        SPtr<TClntCfgIA> ptrCfgIA = ClntCfgMgr().getIA(ptrOptIA->getIAID());
        ptrCfgIA->reset();
        ptrIA->reset();
    }
    ClntAddrMgr().firstIA();
}

void TClntMsgConfirm::doDuties()
{
    //The first Confirm message from the client on the interface MUST be
    //delayed by a random amount of time between 0 and CNF_MAX_DELAY.
    /// @todo: MRD counters are a mess.
    if (!MRD) {
        // MRD reached. Nobody said that out addrs are faulty, so we suppose
        // they are ok. Use them
        Log(Info) << "MRD reached and there is no valid response for CONFIRM. "
		  << "Assuming addresses are valid." << LogEnd;
        addrsAccepted();
        IsDone = true;
        return;
    }

    send();
}

unsigned long TClntMsgConfirm::getTimeout()
{
        return 0;
}

bool TClntMsgConfirm::check()
{
        return 0;
}

std::string TClntMsgConfirm::getName() const {
    return "CONFIRM";
}

TClntMsgConfirm::~TClntMsgConfirm() {
}