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, PPP_PROTOCOL_LEVEL, 22 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 bool 191 KPPPLCP::Up() 192 { 193 return true; 194 } 195 196 197 bool 198 KPPPLCP::Down() 199 { 200 return true; 201 } 202 203 204 status_t 205 KPPPLCP::Send(struct mbuf *packet, uint16 protocolNumber = PPP_LCP_PROTOCOL) 206 { 207 if(Target()) 208 return Target()->Send(packet, PPP_LCP_PROTOCOL); 209 else 210 return Interface().Send(packet, PPP_LCP_PROTOCOL); 211 } 212 213 214 status_t 215 KPPPLCP::Receive(struct mbuf *packet, uint16 protocolNumber) 216 { 217 if(!packet) 218 return B_ERROR; 219 220 if(protocolNumber != PPP_LCP_PROTOCOL) { 221 dprintf("KPPPLCP::Receive(): wrong protocol number!\n"); 222 return PPP_UNHANDLED; 223 } 224 225 ppp_lcp_packet *data = mtod(packet, ppp_lcp_packet*); 226 227 // remove padding 228 int32 length = packet->m_len; 229 if(packet->m_flags & M_PKTHDR) 230 length = packet->m_pkthdr.len; 231 length -= ntohs(data->length); 232 if(length) 233 m_adj(packet, -length); 234 235 struct mbuf *copy = m_gethdr(MT_DATA); 236 if(copy) { 237 copy->m_data += AdditionalOverhead(); 238 copy->m_pkthdr.len = copy->m_len = packet->m_len; 239 memcpy(copy->m_data, packet->m_data, copy->m_len); 240 } 241 242 if(ntohs(data->length) < 4) 243 return B_ERROR; 244 245 bool handled = true; 246 247 switch(data->code) { 248 case PPP_CONFIGURE_REQUEST: 249 StateMachine().RCREvent(packet); 250 break; 251 252 case PPP_CONFIGURE_ACK: 253 StateMachine().RCAEvent(packet); 254 break; 255 256 case PPP_CONFIGURE_NAK: 257 case PPP_CONFIGURE_REJECT: 258 StateMachine().RCNEvent(packet); 259 break; 260 261 case PPP_TERMINATE_REQUEST: 262 StateMachine().RTREvent(packet); 263 break; 264 265 case PPP_TERMINATE_ACK: 266 StateMachine().RTAEvent(packet); 267 break; 268 269 case PPP_CODE_REJECT: 270 StateMachine().RXJEvent(packet); 271 break; 272 273 case PPP_PROTOCOL_REJECT: 274 StateMachine().RXJEvent(packet); 275 break; 276 277 case PPP_ECHO_REQUEST: 278 case PPP_ECHO_REPLY: 279 case PPP_DISCARD_REQUEST: 280 StateMachine().RXREvent(packet); 281 break; 282 283 default: 284 m_freem(packet); 285 handled = false; 286 } 287 288 packet = copy; 289 290 if(!packet) 291 return handled ? B_OK : B_ERROR; 292 293 status_t result = B_OK; 294 295 // Try to find LCP extensions that can handle this code. 296 // We must duplicate the packet in order to ask all handlers. 297 int32 index = 0; 298 KPPPLCPExtension *lcpExtension = LCPExtensionFor(data->code, &index); 299 for(; lcpExtension; lcpExtension = LCPExtensionFor(data->code, &(++index))) { 300 if(!lcpExtension->IsEnabled()) 301 continue; 302 303 result = lcpExtension->Receive(packet, data->code); 304 305 // check return value and return it on error 306 if(result == B_OK) 307 handled = true; 308 else if(result != PPP_UNHANDLED) { 309 m_freem(packet); 310 return result; 311 } 312 } 313 314 if(!handled) { 315 StateMachine().RUCEvent(packet, PPP_LCP_PROTOCOL, PPP_CODE_REJECT); 316 return PPP_REJECTED; 317 } 318 319 m_freem(packet); 320 321 return result; 322 } 323 324 325 void 326 KPPPLCP::Pulse() 327 { 328 StateMachine().TimerEvent(); 329 330 for(int32 index = 0; index < CountLCPExtensions(); index++) 331 LCPExtensionAt(index)->Pulse(); 332 } 333