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