1/* 2 * Copyright 2014, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Lin Longzhou, linlongzhou@163.com 7 */ 8 9 10#include <errno.h> 11#include <stdlib.h> 12#include <net/if_dl.h> 13#include <net/if_media.h> 14#include <net/if_types.h> 15#include <new> 16 17#include <ethernet.h> 18#include <ether_driver.h> 19#include <net_buffer.h> 20#include <net_datalink_protocol.h> 21 22#include <NetBufferUtilities.h> 23#include <net_stack.h> 24 25#include <KernelExport.h> 26 27#include <KPPPManager.h> 28#include <ppp_device.h> 29 30#define PPP_HEADER_LENGTH (8 + ETHER_HEADER_LENGTH) 31 32 33net_buffer* create_buffer_for_frame(uint8 *frame, uint16 frame_size); 34 35static const bigtime_t kLinkCheckInterval = 1000000; 36 // 1 second 37 38net_buffer_module_info *gBufferModule; 39ppp_interface_module_info* gPPPInterfaceModule; 40static net_stack_module_info *sStackModule; 41 42static mutex sListLock; 43static DoublyLinkedList<ppp_device> sCheckList; 44static sem_id sLinkChangeSemaphore; 45static thread_id sLinkCheckerThread; 46 47 48// #pragma mark - 49// 50 51status_t 52ppp_init(const char *name, net_device **_device) 53{ 54 // ppp device 55 dprintf("%s: entering!\n", __func__); 56 57 if (strncmp(name, "ppp", 3)) { 58 dprintf("[%s] not ppp device\n", name); 59 return B_BAD_VALUE; 60 } 61 62 dprintf("[%s] is ppp device\n", name); 63 64 status_t status = get_module(NET_BUFFER_MODULE_NAME, (module_info **)&gBufferModule); 65 if (status < B_OK) 66 return status; 67 68 // ppp_device *device = new (std::nothrow) ppp_device; 69 ppp_interface_id idInterface = gPPPInterfaceModule->CreateInterfaceWithName(name, 0); 70 KPPPInterface * pppInterface = gPPPInterfaceModule->GetInterface(idInterface); 71 72 if (idInterface <= 0 || pppInterface == NULL) { 73 if (idInterface <= 0) 74 dprintf("%s: idInterface: %" B_PRIu32 "\n", __func__, idInterface); 75 else 76 dprintf("%s: pppInterface == NULL %" B_PRIu32 "\n", __func__, idInterface); 77 put_module(NET_BUFFER_MODULE_NAME); 78 return B_NO_MEMORY; 79 } 80 81 // Ifnet available until interface up phase 82 ppp_device *device = (ppp_device *)pppInterface->Ifnet(); 83 if (device == NULL) { 84 dprintf("%s: can not get ppp_device\n", __func__); 85 put_module(NET_BUFFER_MODULE_NAME); 86 return B_NO_MEMORY; 87 } 88 89 strcpy(device->name, name); 90 device->flags = (IFF_BROADCAST | IFF_LINK) & (~IFF_UP); 91 device->type = IFT_PPP; 92 device->mtu = 1492; 93 device->frame_size = 1500; 94 device->media = IFM_ACTIVE | IFM_ETHER; 95 device->header_length = PPP_HEADER_LENGTH; 96 97 status =sStackModule->init_fifo(&(device->ppp_fifo), "ppp_fifo", 10 * 1500); 98 // 10 ppp packet at most 99 if (status < B_OK) 100 return(status); 101 102 TRACE("[%s] finish\n", "allocate ppp_device"); 103 *_device = device; 104 105 return B_OK; 106} 107 108 109status_t 110ppp_uninit(net_device *device) 111{ 112 dprintf("%s: uninit ppp\n", __func__); 113 ppp_device *ppp_dev=(ppp_device *)device; 114 115 sStackModule->uninit_fifo(&(ppp_dev->ppp_fifo)); 116 put_module(NET_BUFFER_MODULE_NAME); 117 118 // delete ppp_dev->KPPP_Interface; 119 delete ppp_dev; 120 121 return B_OK; 122} 123 124 125status_t 126ppp_up(net_device *_device) 127{ 128 dprintf("ppp_up\n"); 129 ppp_device *device = (ppp_device *)_device; 130 131 if (device->KPPP_Interface == NULL) { 132 dprintf("%s: warning! can not find pppinterface KPPP_Interface\n", __func__); 133 return B_ERROR; 134 } 135 136 if (device->KPPP_Interface->Up() != true) { 137 dprintf("%s: warning! KPPP_Interface->Up() failure\n", __func__); 138 return B_ERROR; 139 } 140 141 device->mtu = device->frame_size - device->header_length; 142 // s_pppoe_dev = device; 143 144 dprintf("%s: congratulations! Find pppinterface (device->KPPP_Interface)\n", __func__); 145 146 return B_OK; 147} 148 149 150void 151ppp_down(net_device *_device) 152{ 153 dprintf("%s\n", __func__); 154 ppp_device *device = (ppp_device *)_device; 155 device->KPPP_Interface->Down(); 156 157 MutexLocker _(sListLock); 158 159 // if the device is still part of the list, remove it 160 if (device->GetDoublyLinkedListLink()->next != NULL 161 || device->GetDoublyLinkedListLink()->previous != NULL 162 || device == sCheckList.Head()) 163 sCheckList.Remove(device); 164 165 // device->KPPP_Interface = NULL; 166 167 return; 168} 169 170 171status_t 172ppp_control(net_device *_device, int32 op, void *argument, 173 size_t length) 174{ 175 TRACE("%s op:%" B_PRId32 "\n", __func__, op); 176 ppp_device *device = (ppp_device *)_device; 177 178 if (device->KPPP_Interface == NULL) { 179 dprintf("%s: can not find KPPP_Interface for ppp\n", __func__); 180 return B_OK; 181 } 182 183 return device->KPPP_Interface->Control(op, argument, length); 184 185 return B_OK; 186} 187 188 189status_t 190ppp_send_data(net_device *_device, net_buffer *buffer) 191{ 192 TRACE("%s\n", __func__); 193 ppp_device *device = (ppp_device *)_device; 194 195 if (buffer->size > device->frame_size || buffer->size < device->header_length) { 196 dprintf("sorry! fail send ppp packet, size wrong!\n"); 197 return EMSGSIZE; 198 } 199 200 if (device->KPPP_Interface == NULL) { 201 dprintf("Fail send ppp packet, no eth for ppp!\n"); 202 return B_BAD_VALUE; 203 } 204 205 size_t net_buffer_size = buffer->size; 206 // store buffer->size in case buffer freed in KPPP_Interface->Send 207 status_t status = device->KPPP_Interface->Send(buffer, 0x0021); // IP_PROTOCOL 0x0021 208 209 if (status != B_OK) { 210 dprintf("KPPP_Interface->Send(buffer, 0x0021 IP) fail\n"); 211 return B_BAD_VALUE; 212 } 213 214 return B_OK; 215} 216 217 218status_t 219ppp_receive_data(net_device *_device, net_buffer **_buffer) 220{ 221 TRACE("%s\n", __func__); 222 ppp_device *device = (ppp_device *)_device; 223 224 if (device->KPPP_Interface == NULL) 225 return B_FILE_ERROR; 226 227 TRACE("%s: trying fifo_dequeue_buffer\n", __func__); 228 status_t status = sStackModule->fifo_dequeue_buffer(&(device->ppp_fifo), 0, 10000000, _buffer); 229 230 if (status < B_OK) { 231 TRACE("sorry! can not fifo_dequeue_buffer!\n"); 232 return status; 233 } 234 235 // (*_buffer)->interface_address = NULL; // strange need to put here 236 237 return B_OK; 238} 239 240 241status_t 242ppp_set_mtu(net_device *_device, size_t mtu) 243{ 244 ppp_device *device = (ppp_device *)_device; 245 246 if (mtu > device->frame_size - ETHER_HEADER_LENGTH - 8 247 || mtu <= ETHER_HEADER_LENGTH + 8 + 10) 248 return B_BAD_VALUE; 249 250 device->mtu = mtu; 251 return B_OK; 252} 253 254 255status_t 256ppp_set_promiscuous(net_device *_device, bool promiscuous) 257{ 258 return B_NOT_SUPPORTED; 259} 260 261 262status_t 263ppp_set_media(net_device *device, uint32 media) 264{ 265 return B_NOT_SUPPORTED; 266} 267 268 269status_t 270ppp_add_multicast(struct net_device *_device, const sockaddr *_address) 271{ 272 // ppp_device *device = (ppp_device *)_device; 273 274 if (_address->sa_family != AF_LINK) 275 return B_BAD_VALUE; 276 277 const sockaddr_dl *address = (const sockaddr_dl *)_address; 278 if (address->sdl_type != IFT_ETHER) 279 return B_BAD_VALUE; 280 281 return B_NOT_SUPPORTED; 282} 283 284 285status_t 286ppp_remove_multicast(struct net_device *_device, const sockaddr *_address) 287{ 288 // ppp_device *device = (ppp_device *)_device; 289 290 if (_address->sa_family != AF_LINK) 291 return B_BAD_VALUE; 292 293 const sockaddr_dl *address = (const sockaddr_dl *)_address; 294 if (address->sdl_type != IFT_ETHER) 295 return B_BAD_VALUE; 296 297 return B_NOT_SUPPORTED; 298} 299 300 301static status_t 302ppp_std_ops(int32 op, ...) 303{ 304 switch (op) { 305 case B_MODULE_INIT: 306 { 307 status_t status = get_module(NET_STACK_MODULE_NAME, 308 (module_info **)&sStackModule); 309 if (status < B_OK) 310 return status; 311 312 status = get_module(PPP_INTERFACE_MODULE_NAME, 313 (module_info**)&gPPPInterfaceModule); 314 if (status < B_OK) { 315 put_module(NET_STACK_MODULE_NAME); 316 return status; 317 } 318 319 new (&sCheckList) DoublyLinkedList<ppp_device>; 320 // static C++ objects are not initialized in the module startup 321 322 sLinkCheckerThread = -1; 323 324 sLinkChangeSemaphore = create_sem(0, "ppp link change"); 325 if (sLinkChangeSemaphore < B_OK) { 326 put_module(PPP_INTERFACE_MODULE_NAME); 327 put_module(NET_STACK_MODULE_NAME); 328 return sLinkChangeSemaphore; 329 } 330 331 mutex_init(&sListLock, "ppp devices"); 332 333 return B_OK; 334 } 335 336 case B_MODULE_UNINIT: 337 { 338 delete_sem(sLinkChangeSemaphore); 339 340 status_t status; 341 wait_for_thread(sLinkCheckerThread, &status); 342 343 mutex_destroy(&sListLock); 344 345 put_module(PPP_INTERFACE_MODULE_NAME); 346 put_module(NET_STACK_MODULE_NAME); 347 return B_OK; 348 } 349 350 default: 351 return B_ERROR; 352 } 353} 354 355 356net_device_module_info spppModule = { 357 { 358 "network/devices/ppp/v1", 359 0, 360 ppp_std_ops 361 }, 362 ppp_init, 363 ppp_uninit, 364 ppp_up, 365 ppp_down, 366 ppp_control, 367 ppp_send_data, 368 ppp_receive_data, 369 ppp_set_mtu, 370 ppp_set_promiscuous, 371 ppp_set_media, 372 ppp_add_multicast, 373 ppp_remove_multicast, 374}; 375 376 377module_info *modules[] = { 378 (module_info *)&spppModule, 379 NULL 380}; 381