2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
3 * Distributed under the terms of the MIT License.
6 #include <KernelExport.h>
7 #include <driver_settings.h>
10 #include <util/AutoLock.h>
11 #include <ByteOrder.h>
13 #include <net/if_types.h>
14 #include <net/if_dl.h>
16 #include <sys/sockio.h>
18 #include <net_buffer.h>
19 #include <net_datalink.h> // for get_interface and control
20 #include <net_stack.h>
21 #include <NetBufferUtilities.h>
23 #include <KPPPInterface.h>
24 #include <KPPPModule.h>
25 #include <KPPPUtils.h>
27 #include "PPPoEDevice.h"
28 #include "DiscoveryPacket.h"
31 typedef struct pppoe_query
{
32 net_device
*ethernetIfnet
;
37 #define PPPoE_MODULE_NAME "network/ppp/pppoe"
39 net_stack_module_info
*gStackModule
= NULL
;
40 net_buffer_module_info
*gBufferModule
= NULL
;
41 net_datalink_module_info
*sDatalinkModule
= NULL
;
43 static int32 sHostUniq
= 0;
44 status_t
std_ops(int32 op
, ...);
46 // static mutex sLock("PPPoEList");
48 static TemplateList
<PPPoEDevice
*> *sDevices
;
49 static TemplateList
<pppoe_query
*> *sQueries
;
54 SendQueryPacket(pppoe_query
*query
, DiscoveryPacket
& discovery
)
56 char data
[PPPoE_QUERY_REPORT_SIZE
];
57 uint32 position
= sizeof(uint32
);
58 pppoe_tag
*acName
= discovery
.TagWithType(AC_NAME
);
61 if (acName
->length
>= PPPoE_QUERY_REPORT_SIZE
)
64 memcpy(data
+ position
, acName
->data
, acName
->length
);
65 position
+= acName
->length
;
71 for (int32 index
= 0; index
< discovery
.CountTags(); index
++) {
72 tag
= discovery
.TagAt(index
);
73 if (tag
&& tag
->type
== SERVICE_NAME
) {
74 if (position
+ tag
->length
>= PPPoE_QUERY_REPORT_SIZE
)
77 memcpy(data
+ position
, tag
->data
, tag
->length
);
78 position
+= tag
->length
;
83 memcpy(data
, &position
, sizeof(uint32
));
84 // add the total length
86 send_data_with_timeout(query
->receiver
, PPPoE_QUERY_REPORT
, data
,
87 PPPoE_QUERY_REPORT_SIZE
, 700000);
92 get_interface_by_name(net_domain
*domain
, const char *name
)
95 memset(&request
, 0, sizeof(request
));
96 size_t size
= sizeof(request
);
98 strlcpy(request
.ifr_name
, name
, IF_NAMESIZE
);
100 if (sDatalinkModule
->control(domain
, SIOCGIFINDEX
, &request
, &size
) != B_OK
) {
101 TRACE("sDatalinkModule->control failure\n");
104 return sDatalinkModule
->get_interface(domain
, request
.ifr_index
);
109 FindPPPoEInterface(const char *name
)
114 net_interface
* ethernetInterfaceOfPPPOE
= NULL
;
115 net_domain
* domain
= NULL
;
117 domain
= gStackModule
->get_domain(AF_INET
);
118 ethernetInterfaceOfPPPOE
= get_interface_by_name(domain
, name
);
120 if (ethernetInterfaceOfPPPOE
== NULL
) {
121 TRACE("get_interface_by_name can not find eth\n");
125 if (ethernetInterfaceOfPPPOE
->device
)
126 return ethernetInterfaceOfPPPOE
->device
;
135 return (uint32
) atomic_add(&sHostUniq
, 1);
140 add_device(PPPoEDevice
*device
)
142 TRACE("PPPoE: add_device()\n");
144 // MutexLocker locker(sLock);
145 if (!sDevices
->HasItem(device
))
146 sDevices
->AddItem(device
);
151 remove_device(PPPoEDevice
*device
)
153 TRACE("PPPoE: remove_device()\n");
155 // MutexLocker locker(sLock);
156 sDevices
->RemoveItem(device
);
161 pppoe_input(void *cookie
, net_device
*_device
, net_buffer
*packet
)
166 NetBufferHeaderReader
<pppoe_header
> bufferheader(packet
);
167 if (bufferheader
.Status() != B_OK
)
170 pppoe_header
&header
= bufferheader
.Data();
172 // remove the following lines when pppoe server is enabled
173 if (header
.code
== PADI
) {
174 TRACE("PADI packet received, ignoreing!\n");
175 gBufferModule
->free(packet
);
179 if (header
.code
== PADO
|| header
.code
== PADR
|| header
.code
== PADS
|| header
.code
== PADT
)
181 uint8 peerEtherAddr
[ETHER_ADDRESS_LENGTH
];
182 struct sockaddr_dl
& source
= *(struct sockaddr_dl
*)packet
->source
;
183 memcpy(peerEtherAddr
, source
.sdl_data
, ETHER_ADDRESS_LENGTH
);
184 const char *str
= header
.code
== PADI
? "PADI" :
185 header
.code
== PADO
? "PADO" :
186 header
.code
== PADR
? "PADR" :
187 header
.code
== PADS
? "PADS" :
190 dprintf("%s from:%02x:%02x:%02x:%02x:%02x:%02x code:%02x\n", str
,
191 peerEtherAddr
[0], peerEtherAddr
[1], peerEtherAddr
[2],
192 peerEtherAddr
[3], peerEtherAddr
[4], peerEtherAddr
[5],
199 sockaddr_dl
& linkAddress
= *(sockaddr_dl
*)packet
->source
;
200 int32 specificType
= B_NET_FRAME_TYPE(linkAddress
.sdl_type
,
201 ntohs(linkAddress
.sdl_e_type
));
203 // MutexLocker locker(sLock);
205 if (specificType
== B_NET_FRAME_TYPE_PPPOE_DISCOVERY
206 && ntohs(header
.length
) <= PPPoE_QUERY_REPORT_SIZE
) {
207 for (int32 index
= 0; index
< sDevices
->CountItems(); index
++) {
208 query
= sQueries
->ItemAt(index
);
210 if (query
) {// && query->ethernetIfnet == sourceIfnet) {
211 if (header
.code
== PADO
) {
212 DiscoveryPacket
discovery(packet
, ETHER_HDR_LEN
);
213 if (discovery
.InitCheck() != B_OK
) {
214 ERROR("PPPoE: received corrupted discovery packet!\n");
215 // gBufferModule->free(packet);
219 pppoe_tag
*hostTag
= discovery
.TagWithType(HOST_UNIQ
);
220 if (hostTag
&& hostTag
->length
== 4
221 && *((uint32
*)hostTag
->data
) == query
->hostUniq
) {
222 SendQueryPacket(query
, discovery
);
223 // gBufferModule->free(packet);
231 TRACE("in pppoed processing sDevices->CountItems(): %" B_PRId32
"\n",
232 sDevices
->CountItems());
234 for (int32 index
= 0; index
< sDevices
->CountItems(); index
++) {
235 device
= sDevices
->ItemAt(index
);
237 TRACE("device->SessionID() %d, header.sessionID: %d\n", device
->SessionID(),
240 if (device
) { // && device->EthernetIfnet() == sourceIfnet) {
241 if (specificType
== B_NET_FRAME_TYPE_PPPOE
242 && header
.sessionID
== device
->SessionID()) {
243 TRACE("PPPoE: session packet\n");
244 device
->Receive(packet
);
248 if (specificType
== B_NET_FRAME_TYPE_PPPOE_DISCOVERY
249 && header
.code
!= PADI
250 && header
.code
!= PADR
251 && !device
->IsDown()) {
252 TRACE("PPPoE: discovery packet\n");
254 DiscoveryPacket
discovery(packet
, ETHER_HDR_LEN
);
255 if (discovery
.InitCheck() != B_OK
) {
256 ERROR("PPPoE: received corrupted discovery packet!\n");
257 gBufferModule
->free(packet
);
261 pppoe_tag
*tag
= discovery
.TagWithType(HOST_UNIQ
);
262 if (header
.code
== PADT
|| (tag
&& tag
->length
== 4
263 && *((uint32
*)tag
->data
) == device
->HostUniq())) {
264 device
->Receive(packet
);
271 ERROR("PPPoE: No device found for packet from: %s\n", "ethernet");
272 // gBufferModule->free(packet);
279 add_to(KPPPInterface
& mainInterface
, KPPPInterface
*subInterface
,
280 driver_parameter
*settings
, ppp_module_key_type type
)
282 if (mainInterface
.Mode() != PPP_CLIENT_MODE
|| type
!= PPP_DEVICE_KEY_TYPE
)
288 device
= new PPPoEDevice(*subInterface
, settings
);
289 success
= subInterface
->SetDevice(device
);
291 device
= new PPPoEDevice(mainInterface
, settings
);
292 success
= mainInterface
.SetDevice(device
);
295 TRACE("PPPoE: add_to(): %s\n",
296 success
&& device
&& device
->InitCheck() == B_OK
? "OK" : "ERROR");
298 return success
&& device
&& device
->InitCheck() == B_OK
;
304 control(uint32 op
, void *data
, size_t length
)
307 case PPPoE_GET_INTERFACES
: {
308 int32 position
= 0, count
= 0;
309 char *names
= (char*) data
;
311 net_device
*current
= NULL
; // get_interfaces();
312 for (; current
; current
= NULL
) {
313 if (current
->type
== IFT_ETHER
&& current
->name
) {
314 if (position
+ strlen(current
->name
) + 1 > length
)
317 strcpy(names
+ position
, current
->name
);
318 position
+= strlen(current
->name
);
319 names
[position
++] = 0;
327 case PPPoE_QUERY_SERVICES
: {
328 // XXX: as all modules are loaded on-demand we must wait for the results
330 if (!data
|| length
!= sizeof(pppoe_query_request
))
333 pppoe_query_request
*request
= (pppoe_query_request
*) data
;
336 query
.ethernetIfnet
= FindPPPoEInterface(request
->interfaceName
);
337 if (!query
.ethernetIfnet
)
340 query
.hostUniq
= NewHostUniq();
341 query
.receiver
= request
->receiver
;
344 // MutexLocker tlocker(sLock);
345 TRACE("add query\n");
346 sQueries
->AddItem(&query
);
350 // wait two seconds for results
352 // MutexLocker tlocker(sLock);
353 TRACE("remove query\n");
354 sQueries
->RemoveItem(&query
);
366 static ppp_module_info pppoe_module
= {
379 std_ops(int32 op
, ...)
383 if (get_module(NET_STACK_MODULE_NAME
,
384 (module_info
**)&gStackModule
) != B_OK
)
387 if (get_module(NET_DATALINK_MODULE_NAME
,
388 (module_info
**)&sDatalinkModule
) != B_OK
) {
389 put_module(NET_STACK_MODULE_NAME
);
393 if (get_module(NET_BUFFER_MODULE_NAME
,
394 (module_info
**)&gBufferModule
) != B_OK
) {
395 put_module(NET_DATALINK_MODULE_NAME
);
396 put_module(NET_STACK_MODULE_NAME
);
400 // set_max_linkhdr(2 + PPPoE_HEADER_SIZE + ETHER_HDR_LEN);
401 // 2 bytes for PPP header
402 sDevices
= new TemplateList
<PPPoEDevice
*>;
403 sQueries
= new TemplateList
<pppoe_query
*>;
405 TRACE("PPPoE: Registered PPPoE receiver.\n");
408 case B_MODULE_UNINIT
:
411 TRACE("PPPoE: Unregistered PPPoE receiver.\n");
412 put_module(NET_BUFFER_MODULE_NAME
);
413 put_module(NET_DATALINK_MODULE_NAME
);
414 put_module(NET_STACK_MODULE_NAME
);
426 module_info
*modules
[] = {
427 (module_info
*) &pppoe_module
,