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