vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / network / ppp / pppoe / pppoe.cpp
blob870908ae505467aaa22a0fd9923f93697d8c8d07
1 /*
2 * Copyright 2003-2006, Waldemar Kornewald <wkornew@gmx.net>
3 * Distributed under the terms of the MIT License.
4 */
6 #include <KernelExport.h>
7 #include <driver_settings.h>
9 #include <lock.h>
10 #include <util/AutoLock.h>
11 #include <ByteOrder.h>
13 #include <net/if_types.h>
14 #include <net/if_dl.h>
15 #include <net/if.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;
33 uint32 hostUniq;
34 thread_id receiver;
35 } pppoe_query;
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;
52 static
53 void
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);
60 if (acName) {
61 if (acName->length >= PPPoE_QUERY_REPORT_SIZE)
62 return;
64 memcpy(data + position, acName->data, acName->length);
65 position += acName->length;
68 data[position++] = 0;
70 pppoe_tag *tag;
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)
75 return;
77 memcpy(data + position, tag->data, tag->length);
78 position += tag->length;
79 data[position++] = 0;
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);
91 net_interface *
92 get_interface_by_name(net_domain *domain, const char *name)
94 ifreq request;
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");
102 return NULL;
104 return sDatalinkModule->get_interface(domain, request.ifr_index);
108 net_device*
109 FindPPPoEInterface(const char *name)
111 if (!name)
112 return NULL;
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");
122 return NULL;
125 if (ethernetInterfaceOfPPPOE->device)
126 return ethernetInterfaceOfPPPOE->device;
128 return NULL;
132 uint32
133 NewHostUniq()
135 return (uint32) atomic_add(&sHostUniq, 1);
139 void
140 add_device(PPPoEDevice *device)
142 TRACE("PPPoE: add_device()\n");
144 // MutexLocker locker(sLock);
145 if (!sDevices->HasItem(device))
146 sDevices->AddItem(device);
150 void
151 remove_device(PPPoEDevice *device)
153 TRACE("PPPoE: remove_device()\n");
155 // MutexLocker locker(sLock);
156 sDevices->RemoveItem(device);
160 status_t
161 pppoe_input(void *cookie, net_device *_device, net_buffer *packet)
163 if (!packet)
164 return B_ERROR;
166 NetBufferHeaderReader<pppoe_header> bufferheader(packet);
167 if (bufferheader.Status() != B_OK)
168 return B_ERROR;
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);
176 return B_OK;
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" :
188 "PADT" ;
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],
193 header.code);
196 PPPoEDevice *device;
197 pppoe_query *query;
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);
216 return B_ERROR;
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);
224 return B_ERROR;
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(),
238 header.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);
245 return B_OK;
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);
258 return B_OK;
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);
265 return B_OK;
271 ERROR("PPPoE: No device found for packet from: %s\n", "ethernet");
272 // gBufferModule->free(packet);
273 return B_ERROR;
277 static
278 bool
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)
283 return B_ERROR;
285 PPPoEDevice *device;
286 bool success;
287 if (subInterface) {
288 device = new PPPoEDevice(*subInterface, settings);
289 success = subInterface->SetDevice(device);
290 } else {
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;
302 static
303 status_t
304 control(uint32 op, void *data, size_t length)
306 switch (op) {
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)
315 return B_NO_MEMORY;
317 strcpy(names + position, current->name);
318 position += strlen(current->name);
319 names[position++] = 0;
320 ++count;
324 return count;
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))
331 return B_ERROR;
333 pppoe_query_request *request = (pppoe_query_request*) data;
335 pppoe_query query;
336 query.ethernetIfnet = FindPPPoEInterface(request->interfaceName);
337 if (!query.ethernetIfnet)
338 return B_BAD_VALUE;
340 query.hostUniq = NewHostUniq();
341 query.receiver = request->receiver;
344 // MutexLocker tlocker(sLock);
345 TRACE("add query\n");
346 sQueries->AddItem(&query);
349 snooze(2000000);
350 // wait two seconds for results
352 // MutexLocker tlocker(sLock);
353 TRACE("remove query\n");
354 sQueries->RemoveItem(&query);
356 } break;
358 default:
359 return B_ERROR;
362 return B_OK;
366 static ppp_module_info pppoe_module = {
368 PPPoE_MODULE_NAME,
370 std_ops
372 control,
373 add_to
377 _EXPORT
378 status_t
379 std_ops(int32 op, ...)
381 switch(op) {
382 case B_MODULE_INIT:
383 if (get_module(NET_STACK_MODULE_NAME,
384 (module_info**)&gStackModule) != B_OK)
385 return B_ERROR;
387 if (get_module(NET_DATALINK_MODULE_NAME,
388 (module_info **)&sDatalinkModule) != B_OK) {
389 put_module(NET_STACK_MODULE_NAME);
390 return B_ERROR;
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);
397 return B_ERROR;
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");
406 return B_OK;
408 case B_MODULE_UNINIT:
409 delete sQueries;
410 delete sDevices;
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);
415 break;
417 default:
418 return B_ERROR;
421 return B_OK;
425 _EXPORT
426 module_info *modules[] = {
427 (module_info*) &pppoe_module,
428 NULL