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