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