xref: /haiku/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp (revision d5cd5d63ff0ad395989db6cf4841a64d5b545d1d)
1 //----------------------------------------------------------------------
2 //  This software is part of the OpenBeOS distribution and is covered
3 //  by the OpenBeOS license.
4 //
5 //  Copyright (c) 2003 Waldemar Kornewald, Waldemar.Kornewald@web.de
6 //---------------------------------------------------------------------
7 
8 #include <core_funcs.h>
9 #include <KernelExport.h>
10 #include <driver_settings.h>
11 
12 #include <ethernet_module.h>
13 
14 #include <KPPPInterface.h>
15 #include <KPPPModule.h>
16 #include <LockerHelper.h>
17 
18 #include "PPPoEDevice.h"
19 #include "DiscoveryPacket.h"
20 
21 
22 #ifdef _KERNEL_MODE
23 	#define spawn_thread spawn_kernel_thread
24 	#define printf dprintf
25 #else
26 	#include <cstdio>
27 #endif
28 
29 
30 #define PPPoE_MODULE_NAME		"network/ppp/pppoe"
31 
32 struct core_module_info *core = NULL;
33 static struct ethernet_module_info *ethernet;
34 static int32 host_uniq = 0;
35 status_t std_ops(int32 op, ...);
36 
37 static BLocker lock;
38 static List<PPPoEDevice*> *devices;
39 
40 
41 uint32
42 NewHostUniq()
43 {
44 	return (uint32) atomic_add(&host_uniq, 1);
45 }
46 
47 
48 void
49 add_device(PPPoEDevice *device)
50 {
51 #if DEBUG
52 	printf("PPPoE: add_device()\n");
53 #endif
54 
55 	LockerHelper locker(lock);
56 	devices->AddItem(device);
57 }
58 
59 
60 void
61 remove_device(PPPoEDevice *device)
62 {
63 #if DEBUG
64 	printf("PPPoE: remove_device()\n");
65 #endif
66 
67 	LockerHelper locker(lock);
68 	devices->RemoveItem(device);
69 }
70 
71 
72 static
73 void
74 pppoe_input(struct mbuf *packet)
75 {
76 	if(!packet)
77 		return;
78 
79 #if DEBUG
80 //	dump_packet(packet);
81 #endif
82 
83 	ifnet *sourceIfnet = packet->m_pkthdr.rcvif;
84 	complete_pppoe_header *header = mtod(packet, complete_pppoe_header*);
85 	PPPoEDevice *device;
86 
87 	LockerHelper locker(lock);
88 
89 	for(int32 index = 0; index < devices->CountItems(); index++) {
90 		device = devices->ItemAt(index);
91 
92 		if(device && device->EthernetIfnet() == sourceIfnet) {
93 			if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE
94 					&& header->pppoeHeader.sessionID == device->SessionID()) {
95 #if DEBUG
96 				printf("PPPoE: session packet\n");
97 #endif
98 				device->Receive(packet);
99 				return;
100 			} else if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOEDISC
101 					&& header->pppoeHeader.code != PADI
102 					&& header->pppoeHeader.code != PADR
103 					&& !device->IsDown()) {
104 #if DEBUG
105 				printf("PPPoE: discovery packet\n");
106 #endif
107 				DiscoveryPacket discovery(packet, ETHER_HDR_LEN);
108 				if(discovery.InitCheck() != B_OK) {
109 					printf("PPPoE: received corrupted discovery packet!\n");
110 					return;
111 				}
112 
113 				pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ);
114 				if(header->pppoeHeader.code == PADT || (tag && tag->length == 4
115 						&& *((uint32*)tag->data) == device->HostUniq())) {
116 					device->Receive(packet);
117 					return;
118 				}
119 			}
120 		}
121 	}
122 
123 	printf("PPPoE: No device found for packet from: %s\n", sourceIfnet->if_name);
124 	m_freem(packet);
125 }
126 
127 
128 static
129 bool
130 add_to(PPPInterface& mainInterface, PPPInterface *subInterface,
131 	driver_parameter *settings, ppp_module_key_type type)
132 {
133 	if(type != PPP_DEVICE_KEY_TYPE)
134 		return B_ERROR;
135 
136 	PPPoEDevice *device;
137 	bool success;
138 	if(subInterface) {
139 		device = new PPPoEDevice(*subInterface, settings);
140 		success = subInterface->SetDevice(device);
141 	} else {
142 		device = new PPPoEDevice(mainInterface, settings);
143 		success = mainInterface.SetDevice(device);
144 	}
145 
146 #if DEBUG
147 	printf("PPPoE: add_to(): %s\n",
148 		success && device && device->InitCheck() == B_OK ? "OK" : "ERROR");
149 #endif
150 
151 	return success && device && device->InitCheck() == B_OK;
152 }
153 
154 
155 static ppp_module_info pppoe_module = {
156 	{
157 		PPPoE_MODULE_NAME,
158 		0,
159 		std_ops
160 	},
161 	NULL,
162 	add_to
163 };
164 
165 
166 _EXPORT
167 status_t
168 std_ops(int32 op, ...)
169 {
170 	switch(op) {
171 		case B_MODULE_INIT:
172 			if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK)
173 				return B_ERROR;
174 
175 			if(get_module(NET_ETHERNET_MODULE_NAME,
176 					(module_info**) &ethernet) != B_OK) {
177 				put_module(NET_CORE_MODULE_NAME);
178 				return B_ERROR;
179 			}
180 
181 			devices = new List<PPPoEDevice*>;
182 
183 			ethernet->set_pppoe_receiver(pppoe_input);
184 
185 #if DEBUG
186 			printf("PPPoE: Registered PPPoE receiver.\n");
187 #endif
188 		return B_OK;
189 
190 		case B_MODULE_UNINIT:
191 			delete devices;
192 			ethernet->unset_pppoe_receiver();
193 #if DEBUG
194 			printf("PPPoE: Unregistered PPPoE receiver.\n");
195 #endif
196 			put_module(NET_CORE_MODULE_NAME);
197 			put_module(NET_ETHERNET_MODULE_NAME);
198 		break;
199 
200 		default:
201 			return B_ERROR;
202 	}
203 
204 	return B_OK;
205 }
206 
207 
208 _EXPORT
209 module_info *modules[] = {
210 	(module_info*) &pppoe_module,
211 	NULL
212 };
213