1 /* 2 * Copyright 2003-2004, Waldemar Kornewald <Waldemar.Kornewald@web.de> 3 * Distributed under the terms of the MIT License. 4 */ 5 6 /*! \class KPPPLCP 7 \brief The LCP protocol. 8 9 Every PPP interface \e must have an LCP protocol. It is used for establishing 10 and terminating connections. \n 11 When establishing a connecition the LCP protocol determines connection-specific 12 settings like the packet MRU. These settings are handled by the KPPPOptionHandler 13 class. Additional LCP codes like the PPP Multilink-Protocol uses them should 14 be implemented through the KPPPLCPExtension class. \n 15 */ 16 17 #include <KPPPInterface.h> 18 #include <KPPPDevice.h> 19 #include <KPPPLCPExtension.h> 20 #include <KPPPOptionHandler.h> 21 22 #include <LockerHelper.h> 23 24 #include <netinet/in.h> 25 #include <core_funcs.h> 26 #include <sys/socket.h> 27 28 29 //! Creates a new LCP protocol for the given interface. 30 KPPPLCP::KPPPLCP(KPPPInterface& interface) 31 : KPPPProtocol("LCP", PPP_ESTABLISHMENT_PHASE, PPP_LCP_PROTOCOL, 32 PPP_PROTOCOL_LEVEL, AF_UNSPEC, 0, interface, NULL, PPP_ALWAYS_ALLOWED), 33 fStateMachine(interface.StateMachine()), 34 fTarget(NULL) 35 { 36 SetUpRequested(false); 37 // the state machine does everything for us 38 } 39 40 41 //! Deletes all added option handlers and LCP extensions. 42 KPPPLCP::~KPPPLCP() 43 { 44 while(CountOptionHandlers()) 45 delete OptionHandlerAt(0); 46 while(CountLCPExtensions()) 47 delete LCPExtensionAt(0); 48 } 49 50 51 /*! \brief Adds a new option handler. 52 53 NOTE: You can only add option handlers in \c PPP_DOWN_PHASE. \n 54 There may only be one handler per option type! 55 */ 56 bool 57 KPPPLCP::AddOptionHandler(KPPPOptionHandler *optionHandler) 58 { 59 if(!optionHandler || &optionHandler->Interface() != &Interface()) 60 return false; 61 62 LockerHelper locker(StateMachine().fLock); 63 64 if(Interface().Phase() != PPP_DOWN_PHASE 65 || OptionHandlerFor(optionHandler->Type())) 66 return false; 67 // a running connection may not change and there may only be 68 // one handler per option type 69 70 return fOptionHandlers.AddItem(optionHandler); 71 } 72 73 74 /*! \brief Removes an option handler, but does not delete it. 75 76 NOTE: You can only remove option handlers in \c PPP_DOWN_PHASE. 77 */ 78 bool 79 KPPPLCP::RemoveOptionHandler(KPPPOptionHandler *optionHandler) 80 { 81 LockerHelper locker(StateMachine().fLock); 82 83 if(Interface().Phase() != PPP_DOWN_PHASE) 84 return false; 85 // a running connection may not change 86 87 return fOptionHandlers.RemoveItem(optionHandler); 88 } 89 90 91 //! Returns the option handler at the given \a index. 92 KPPPOptionHandler* 93 KPPPLCP::OptionHandlerAt(int32 index) const 94 { 95 KPPPOptionHandler *optionHandler = fOptionHandlers.ItemAt(index); 96 97 if(optionHandler == fOptionHandlers.GetDefaultItem()) 98 return NULL; 99 100 return optionHandler; 101 } 102 103 104 //! Returns the option handler that can handle options of a given \a type. 105 KPPPOptionHandler* 106 KPPPLCP::OptionHandlerFor(uint8 type, int32 *start = NULL) const 107 { 108 // The iteration style in this method is strange C/C++. 109 // Explanation: I use this style because it makes extending all XXXFor 110 // methods simpler as that they look very similar, now. 111 112 int32 index = start ? *start : 0; 113 114 if(index < 0) 115 return NULL; 116 117 KPPPOptionHandler *current = OptionHandlerAt(index); 118 119 for(; current; current = OptionHandlerAt(++index)) { 120 if(current->Type() == type) { 121 if(start) 122 *start = index; 123 return current; 124 } 125 } 126 127 return NULL; 128 } 129 130 131 /*! \brief Adds a new LCP extension. 132 133 NOTE: You can only add LCP extensions in \c PPP_DOWN_PHASE. 134 */ 135 bool 136 KPPPLCP::AddLCPExtension(KPPPLCPExtension *lcpExtension) 137 { 138 if(!lcpExtension || &lcpExtension->Interface() != &Interface()) 139 return false; 140 141 LockerHelper locker(StateMachine().fLock); 142 143 if(Interface().Phase() != PPP_DOWN_PHASE) 144 return false; 145 // a running connection may not change 146 147 return fLCPExtensions.AddItem(lcpExtension); 148 } 149 150 151 /*! \brief Removes an LCP extension, but does not delete it. 152 153 NOTE: You can only remove LCP extensions in \c PPP_DOWN_PHASE. 154 */ 155 bool 156 KPPPLCP::RemoveLCPExtension(KPPPLCPExtension *lcpExtension) 157 { 158 LockerHelper locker(StateMachine().fLock); 159 160 if(Interface().Phase() != PPP_DOWN_PHASE) 161 return false; 162 // a running connection may not change 163 164 return fLCPExtensions.RemoveItem(lcpExtension); 165 } 166 167 168 //! Returns the LCP extension at the given \a index. 169 KPPPLCPExtension* 170 KPPPLCP::LCPExtensionAt(int32 index) const 171 { 172 KPPPLCPExtension *lcpExtension = fLCPExtensions.ItemAt(index); 173 174 if(lcpExtension == fLCPExtensions.GetDefaultItem()) 175 return NULL; 176 177 return lcpExtension; 178 } 179 180 181 //! Returns the LCP extension that can handle LCP packets of a given \a code. 182 KPPPLCPExtension* 183 KPPPLCP::LCPExtensionFor(uint8 code, int32 *start = NULL) const 184 { 185 // The iteration style in this method is strange C/C++. 186 // Explanation: I use this style because it makes extending all XXXFor 187 // methods simpler as that they look very similar, now. 188 189 int32 index = start ? *start : 0; 190 191 if(index < 0) 192 return NULL; 193 194 KPPPLCPExtension *current = LCPExtensionAt(index); 195 196 for(; current; current = LCPExtensionAt(++index)) { 197 if(current->Code() == code) { 198 if(start) 199 *start = index; 200 return current; 201 } 202 } 203 204 return NULL; 205 } 206 207 208 //! Returns the interface, target, and device overhead. 209 uint32 210 KPPPLCP::AdditionalOverhead() const 211 { 212 uint32 overhead = Interface().Overhead(); 213 214 if(Target()) 215 overhead += Target()->Overhead(); 216 217 if(Interface().Device()) 218 overhead += Interface().Device()->Overhead(); 219 220 return overhead; 221 } 222 223 224 //! Calls \c ProfileChanged() for each option handler and LCP extension. 225 void 226 KPPPLCP::ProfileChanged() 227 { 228 KPPPLCPExtension *extension; 229 KPPPOptionHandler *handler; 230 231 for(int32 index = 0; index < CountLCPExtensions(); index++) { 232 extension = LCPExtensionAt(index); 233 if(extension) 234 extension->ProfileChanged(); 235 } 236 237 for(int32 index = 0; index < CountOptionHandlers(); index++) { 238 handler = OptionHandlerAt(index); 239 if(handler) 240 handler->ProfileChanged(); 241 } 242 } 243 244 245 //! Always returns \c true. 246 bool 247 KPPPLCP::Up() 248 { 249 return true; 250 } 251 252 253 //! Always returns \c true. 254 bool 255 KPPPLCP::Down() 256 { 257 return true; 258 } 259 260 261 //! Sends a packet to the target (if there is one) or to the interface. 262 status_t 263 KPPPLCP::Send(struct mbuf *packet, uint16 protocolNumber = PPP_LCP_PROTOCOL) 264 { 265 if(Target()) 266 return Target()->Send(packet, PPP_LCP_PROTOCOL); 267 else 268 return Interface().Send(packet, PPP_LCP_PROTOCOL); 269 } 270 271 272 //! Decodes the LCP packet and passes it to the KPPPStateMachine or an LCP extension. 273 status_t 274 KPPPLCP::Receive(struct mbuf *packet, uint16 protocolNumber) 275 { 276 if(!packet) 277 return B_ERROR; 278 279 if(protocolNumber != PPP_LCP_PROTOCOL) { 280 ERROR("KPPPLCP::Receive(): wrong protocol number!\n"); 281 return PPP_UNHANDLED; 282 } 283 284 ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*); 285 286 // remove padding 287 int32 length = packet->m_len; 288 if(packet->m_flags & M_PKTHDR) 289 length = packet->m_pkthdr.len; 290 length -= ntohs(data->length); 291 if(length) 292 m_adj(packet, -length); 293 294 struct mbuf *copy = m_gethdr(MT_DATA); 295 if(copy) { 296 copy->m_data += AdditionalOverhead(); 297 copy->m_pkthdr.len = copy->m_len = packet->m_len; 298 memcpy(copy->m_data, packet->m_data, copy->m_len); 299 } 300 301 if(ntohs(data->length) < 4) 302 return B_ERROR; 303 304 bool handled = true; 305 306 switch(data->code) { 307 case PPP_CONFIGURE_REQUEST: 308 StateMachine().RCREvent(packet); 309 break; 310 311 case PPP_CONFIGURE_ACK: 312 StateMachine().RCAEvent(packet); 313 break; 314 315 case PPP_CONFIGURE_NAK: 316 case PPP_CONFIGURE_REJECT: 317 StateMachine().RCNEvent(packet); 318 break; 319 320 case PPP_TERMINATE_REQUEST: 321 StateMachine().RTREvent(packet); 322 break; 323 324 case PPP_TERMINATE_ACK: 325 StateMachine().RTAEvent(packet); 326 break; 327 328 case PPP_CODE_REJECT: 329 StateMachine().RXJEvent(packet); 330 break; 331 332 case PPP_PROTOCOL_REJECT: 333 StateMachine().RXJEvent(packet); 334 break; 335 336 case PPP_ECHO_REQUEST: 337 case PPP_ECHO_REPLY: 338 case PPP_DISCARD_REQUEST: 339 StateMachine().RXREvent(packet); 340 break; 341 342 default: 343 m_freem(packet); 344 handled = false; 345 } 346 347 packet = copy; 348 349 if(!packet) 350 return handled ? B_OK : B_ERROR; 351 352 status_t result = B_OK; 353 354 // Try to find LCP extensions that can handle this code. 355 // We must duplicate the packet in order to ask all handlers. 356 int32 index = 0; 357 KPPPLCPExtension *lcpExtension = LCPExtensionFor(data->code, &index); 358 for(; lcpExtension; lcpExtension = LCPExtensionFor(data->code, &(++index))) { 359 if(!lcpExtension->IsEnabled()) 360 continue; 361 362 result = lcpExtension->Receive(packet, data->code); 363 364 // check return value and return it on error 365 if(result == B_OK) 366 handled = true; 367 else if(result != PPP_UNHANDLED) { 368 m_freem(packet); 369 return result; 370 } 371 } 372 373 if(!handled) { 374 StateMachine().RUCEvent(packet, PPP_LCP_PROTOCOL, PPP_CODE_REJECT); 375 return PPP_REJECTED; 376 } 377 378 m_freem(packet); 379 380 return result; 381 } 382 383 384 //! Calls \c Pulse() for each LCP extension. 385 void 386 KPPPLCP::Pulse() 387 { 388 StateMachine().TimerEvent(); 389 390 for(int32 index = 0; index < CountLCPExtensions(); index++) 391 LCPExtensionAt(index)->Pulse(); 392 } 393