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