xref: /haiku/src/add-ons/kernel/network/ppp/pppoe/pppoe.cpp (revision 01b25646004ff628ecad0281a9795e5e90f71746)
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 *sEthernet;
34 static int32 sHostUniq = 0;
35 status_t std_ops(int32 op, ...);
36 
37 static BLocker sLock;
38 static TemplateList<PPPoEDevice*> *sDevices;
39 
40 
41 uint32
42 NewHostUniq()
43 {
44 	return (uint32) atomic_add(&sHostUniq, 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(sLock);
56 	sDevices->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(sLock);
68 	sDevices->RemoveItem(device);
69 }
70 
71 
72 static
73 void
74 pppoe_input(struct mbuf *packet)
75 {
76 	if(!packet)
77 		return;
78 
79 	ifnet *sourceIfnet = packet->m_pkthdr.rcvif;
80 	complete_pppoe_header *header = mtod(packet, complete_pppoe_header*);
81 	PPPoEDevice *device;
82 
83 	LockerHelper locker(sLock);
84 
85 	for(int32 index = 0; index < sDevices->CountItems(); index++) {
86 		device = sDevices->ItemAt(index);
87 
88 		if(device && device->EthernetIfnet() == sourceIfnet) {
89 			if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOE
90 					&& header->pppoeHeader.sessionID == device->SessionID()) {
91 #if DEBUG
92 				printf("PPPoE: session packet\n");
93 #endif
94 				device->Receive(packet);
95 				return;
96 			} else if(header->ethernetHeader.ether_type == ETHERTYPE_PPPOEDISC
97 					&& header->pppoeHeader.code != PADI
98 					&& header->pppoeHeader.code != PADR
99 					&& !device->IsDown()) {
100 #if DEBUG
101 				printf("PPPoE: discovery packet\n");
102 #endif
103 				DiscoveryPacket discovery(packet, ETHER_HDR_LEN);
104 				if(discovery.InitCheck() != B_OK) {
105 					printf("PPPoE: received corrupted discovery packet!\n");
106 					return;
107 				}
108 
109 				pppoe_tag *tag = discovery.TagWithType(HOST_UNIQ);
110 				if(header->pppoeHeader.code == PADT || (tag && tag->length == 4
111 						&& *((uint32*)tag->data) == device->HostUniq())) {
112 					device->Receive(packet);
113 					return;
114 				}
115 			}
116 		}
117 	}
118 
119 	printf("PPPoE: No device found for packet from: %s\n", sourceIfnet->if_name);
120 	m_freem(packet);
121 }
122 
123 
124 static
125 bool
126 add_to(PPPInterface& mainInterface, PPPInterface *subInterface,
127 	driver_parameter *settings, ppp_module_key_type type)
128 {
129 	if(mainInterface.Mode() != PPP_CLIENT_MODE || type != PPP_DEVICE_KEY_TYPE)
130 		return B_ERROR;
131 
132 	PPPoEDevice *device;
133 	bool success;
134 	if(subInterface) {
135 		device = new PPPoEDevice(*subInterface, settings);
136 		success = subInterface->SetDevice(device);
137 	} else {
138 		device = new PPPoEDevice(mainInterface, settings);
139 		success = mainInterface.SetDevice(device);
140 	}
141 
142 #if DEBUG
143 	printf("PPPoE: add_to(): %s\n",
144 		success && device && device->InitCheck() == B_OK ? "OK" : "ERROR");
145 #endif
146 
147 	return success && device && device->InitCheck() == B_OK;
148 }
149 
150 
151 static ppp_module_info pppoe_module = {
152 	{
153 		PPPoE_MODULE_NAME,
154 		0,
155 		std_ops
156 	},
157 	NULL,
158 	add_to
159 };
160 
161 
162 _EXPORT
163 status_t
164 std_ops(int32 op, ...)
165 {
166 	switch(op) {
167 		case B_MODULE_INIT:
168 			if(get_module(NET_CORE_MODULE_NAME, (module_info**)&core) != B_OK)
169 				return B_ERROR;
170 
171 			if(get_module(NET_ETHERNET_MODULE_NAME,
172 					(module_info**) &sEthernet) != B_OK) {
173 				put_module(NET_CORE_MODULE_NAME);
174 				return B_ERROR;
175 			}
176 
177 			sDevices = new TemplateList<PPPoEDevice*>;
178 
179 			sEthernet->set_pppoe_receiver(pppoe_input);
180 
181 #if DEBUG
182 			printf("PPPoE: Registered PPPoE receiver.\n");
183 #endif
184 		return B_OK;
185 
186 		case B_MODULE_UNINIT:
187 			delete sDevices;
188 			sEthernet->unset_pppoe_receiver();
189 #if DEBUG
190 			printf("PPPoE: Unregistered PPPoE receiver.\n");
191 #endif
192 			put_module(NET_CORE_MODULE_NAME);
193 			put_module(NET_ETHERNET_MODULE_NAME);
194 		break;
195 
196 		default:
197 			return B_ERROR;
198 	}
199 
200 	return B_OK;
201 }
202 
203 
204 _EXPORT
205 module_info *modules[] = {
206 	(module_info*) &pppoe_module,
207 	NULL
208 };
209