1 /* 2 * Copyright 2003-2005, Waldemar Kornewald <wkornew@gmx.net> 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) 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) 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 //! Always returns \c true. 225 bool 226 KPPPLCP::Up() 227 { 228 return true; 229 } 230 231 232 //! Always returns \c true. 233 bool 234 KPPPLCP::Down() 235 { 236 return true; 237 } 238 239 240 //! Sends a packet to the target (if there is one) or to the interface. 241 status_t 242 KPPPLCP::Send(struct mbuf *packet, uint16 protocolNumber) 243 { 244 if(Target()) 245 return Target()->Send(packet, PPP_LCP_PROTOCOL); 246 else 247 return Interface().Send(packet, PPP_LCP_PROTOCOL); 248 } 249 250 251 //! Decodes the LCP packet and passes it to the KPPPStateMachine or an LCP extension. 252 status_t 253 KPPPLCP::Receive(struct mbuf *packet, uint16 protocolNumber) 254 { 255 if(!packet) 256 return B_ERROR; 257 258 if(protocolNumber != PPP_LCP_PROTOCOL) { 259 ERROR("KPPPLCP::Receive(): wrong protocol number!\n"); 260 return PPP_UNHANDLED; 261 } 262 263 ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*); 264 265 // remove padding 266 int32 length = packet->m_len; 267 if(packet->m_flags & M_PKTHDR) 268 length = packet->m_pkthdr.len; 269 length -= ntohs(data->length); 270 if(length) 271 m_adj(packet, -length); 272 273 struct mbuf *copy = m_gethdr(MT_DATA); 274 if(copy) { 275 copy->m_data += AdditionalOverhead(); 276 copy->m_pkthdr.len = copy->m_len = packet->m_len; 277 memcpy(copy->m_data, packet->m_data, copy->m_len); 278 } 279 280 if(ntohs(data->length) < 4) 281 return B_ERROR; 282 283 bool handled = true; 284 285 switch(data->code) { 286 case PPP_CONFIGURE_REQUEST: 287 StateMachine().RCREvent(packet); 288 break; 289 290 case PPP_CONFIGURE_ACK: 291 StateMachine().RCAEvent(packet); 292 break; 293 294 case PPP_CONFIGURE_NAK: 295 case PPP_CONFIGURE_REJECT: 296 StateMachine().RCNEvent(packet); 297 break; 298 299 case PPP_TERMINATE_REQUEST: 300 StateMachine().RTREvent(packet); 301 break; 302 303 case PPP_TERMINATE_ACK: 304 StateMachine().RTAEvent(packet); 305 break; 306 307 case PPP_CODE_REJECT: 308 StateMachine().RXJEvent(packet); 309 break; 310 311 case PPP_PROTOCOL_REJECT: 312 StateMachine().RXJEvent(packet); 313 break; 314 315 case PPP_ECHO_REQUEST: 316 case PPP_ECHO_REPLY: 317 case PPP_DISCARD_REQUEST: 318 StateMachine().RXREvent(packet); 319 break; 320 321 default: 322 m_freem(packet); 323 handled = false; 324 } 325 326 packet = copy; 327 328 if(!packet) 329 return handled ? B_OK : B_ERROR; 330 331 status_t result = B_OK; 332 333 // Try to find LCP extensions that can handle this code. 334 // We must duplicate the packet in order to ask all handlers. 335 int32 index = 0; 336 KPPPLCPExtension *lcpExtension = LCPExtensionFor(data->code, &index); 337 for(; lcpExtension; lcpExtension = LCPExtensionFor(data->code, &(++index))) { 338 if(!lcpExtension->IsEnabled()) 339 continue; 340 341 result = lcpExtension->Receive(packet, data->code); 342 343 // check return value and return it on error 344 if(result == B_OK) 345 handled = true; 346 else if(result != PPP_UNHANDLED) { 347 m_freem(packet); 348 return result; 349 } 350 } 351 352 if(!handled) { 353 StateMachine().RUCEvent(packet, PPP_LCP_PROTOCOL, PPP_CODE_REJECT); 354 return PPP_REJECTED; 355 } 356 357 m_freem(packet); 358 359 return result; 360 } 361 362 363 //! Calls \c Pulse() for each LCP extension. 364 void 365 KPPPLCP::Pulse() 366 { 367 StateMachine().TimerEvent(); 368 369 for(int32 index = 0; index < CountLCPExtensions(); index++) 370 LCPExtensionAt(index)->Pulse(); 371 } 372