The Pedigree Project 0.1
NetworkStack.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include "NetworkStack.h"
21#include "pedigree/kernel/LockGuard.h"
22#include "pedigree/kernel/Log.h"
23#include "pedigree/kernel/Metrics.h"
24#include "pedigree/kernel/processor/Processor.h"
25
26#include "Filter.h"
27#include "modules/Module.h"
35
36NetworkStack* NetworkStack::stack = 0;
37
38static NetworkStack* g_NetworkStack = 0;
39
41 explicit DeviceRegistration(struct netif* registeredInterface)
42 : interface(registeredInterface), readers() {}
43
44 struct netif* interface;
45 OperationBarrier readers;
46};
47
48NetworkStack::DeviceLease::DeviceLease() : m_Device(nullptr), m_Interface(nullptr), m_Lease() {}
49
50NetworkStack::DeviceLease::DeviceLease(Network* device, struct netif* interface,
52 : m_Device(device), m_Interface(interface), m_Lease(pedigree_std::move(lease)) {}
53
54NetworkStack::DeviceLease::DeviceLease(DeviceLease&& other)
55 : m_Device(other.m_Device),
56 m_Interface(other.m_Interface),
57 m_Lease(pedigree_std::move(other.m_Lease)) {
58 other.m_Device = nullptr;
59 other.m_Interface = nullptr;
60}
61
62NetworkStack::DeviceLease::~DeviceLease() {}
63
64NetworkStack::DeviceLease& NetworkStack::DeviceLease::operator=(DeviceLease&& other) {
65 if (this != &other) {
66 m_Lease = pedigree_std::move(other.m_Lease);
67 m_Device = other.m_Device;
68 m_Interface = other.m_Interface;
69 other.m_Device = nullptr;
70 other.m_Interface = nullptr;
71 }
72 return *this;
73}
74
75#if PEDIGREE_HOSTED_NETWORK_REGRESSION
76extern bool runHostedNetworkStackRegressions();
77#endif
78
79static err_t linkOutput(struct netif* netif, struct pbuf* p) {
80 Network* pDevice = reinterpret_cast<Network*>(netif->state);
81
82 size_t totalLength = p->tot_len;
83
84 // pull the chain of pbufs into a single packet to transmit
85 size_t offset = 0;
86 char* output = new char[totalLength];
87
88 pbuf_copy_partial(p, output, totalLength, 0);
89
90 // Check for filtering
91 if (!NetworkFilter::instance().filter(1, reinterpret_cast<uintptr_t>(output), totalLength)) {
92 Metrics::increment(Metrics::NetworkTxFiltered);
93 pDevice->droppedPacket();
94 delete[] output;
95 return ERR_IF; // Drop the packet.
96 }
97
98 // transmit!
99 err_t e = ERR_OK;
100 if (!pDevice->send(totalLength, reinterpret_cast<uintptr_t>(output))) {
101 Metrics::increment(Metrics::NetworkTxSendFailed);
102 e = ERR_IF;
103 } else {
104 Metrics::increment(Metrics::NetworkTxAccepted);
105 Metrics::add(Metrics::NetworkTxBytes, totalLength);
106 }
107
108 delete[] output;
109
110 return e;
111}
112
113static void netifStatusUpdate(struct netif* netif) {
114 if (netif_is_up(netif)) {
115 NOTICE("netif " << String(netif->name, 2) << Dec << netif->num << ": is now up");
116 } else {
117 NOTICE("netif " << String(netif->name, 2) << Dec << netif->num << ": is now down");
118 }
119}
120
121static void netifLinkUpdate(struct netif* netif) {
122 if (netif_is_link_up(netif)) {
123 NOTICE("netif " << String(netif->name, 2) << Dec << netif->num << ": link is now up");
124 } else {
125 NOTICE("netif " << String(netif->name, 2) << Dec << netif->num << ": link is now down");
126 }
127}
128
129static err_t netifInit(struct netif* netif) {
130 Network* pDevice = reinterpret_cast<Network*>(netif->state);
131 StationInfo info = pDevice->getStationInfo();
132
134 netif->hwaddr_len = 6;
135 MemoryCopy(netif->hwaddr, info.mac.getMac(), 6);
136 netif->mtu = 1400;
137 netif->flags =
139 netif->linkoutput = linkOutput;
140 netif->output = etharp_output;
141 netif->output_ip6 = ethip6_output;
142
143 netif_set_status_callback(netif, netifStatusUpdate);
144 netif_set_link_callback(netif, netifLinkUpdate);
145
146 return ERR_OK;
147}
148
149static void removeInterface(void* context) {
150 struct netif* iface = reinterpret_cast<struct netif*>(context);
151#if LWIP_DHCP
152 dhcp_stop(iface);
153#endif
154#if LWIP_AUTOIP
155 autoip_stop(iface);
156#endif
157 netif_remove(iface);
158}
159
161 struct netif* iface;
162 const ip4_addr_t* ipaddr;
163 const ip4_addr_t* netmask;
164 const ip4_addr_t* gateway;
165 Network* device;
166 struct netif* result;
167};
168
169static void addInterface(void* context) {
170 AddInterfaceContext* add = reinterpret_cast<AddInterfaceContext*>(context);
171 add->result = netif_add(add->iface, add->ipaddr, add->netmask, add->gateway, add->device,
172 netifInit, tcpip_input);
173}
174
175NetworkStack::NetworkStack()
176 : m_Children(),
177 m_MemPool("network-pool")
178#if THREADS || UTILITY_LINUX
179 ,
180 m_Lock()
181#endif
182 ,
185 if (__atomic_load_n(&stack, __ATOMIC_ACQUIRE)) {
186 FATAL("NetworkStack created multiple times.");
187 }
188
189 __atomic_store_n(&stack, this, __ATOMIC_RELEASE);
190
191 if (!m_MemPool.initialise(4096, 1600) && !m_MemPool.initialise(2048, 1600) &&
192 !m_MemPool.initialise(1024, 1600)) {
193 ERROR("Couldn't get a valid buffer pool for networking use");
194 }
195}
196
197NetworkStack::~NetworkStack() {
198 Vector<DeviceRegistration*> registrations;
199#if THREADS || UTILITY_LINUX
200 m_Lock.acquire();
201#endif
203 it != m_Registrations.end(); ++it) {
204 DeviceRegistration* registration = it.value();
205 registration->readers.close();
206 registrations.pushBack(registration);
207 }
208 m_Registrations.clear();
210#if THREADS || UTILITY_LINUX
211 m_Lock.release();
212#endif
213
214 for (Vector<DeviceRegistration*>::Iterator it = registrations.begin(); it != registrations.end();
215 ++it) {
216 DeviceRegistration* registration = *it;
217 registration->readers.wait();
218 if (tcpip_callback_wait(removeInterface, registration->interface) != ERR_OK) {
219 FATAL("NetworkStack could not retire a network interface");
220 }
221 delete registration->interface;
222 delete registration;
223 }
224
225 __atomic_store_n(&stack, static_cast<NetworkStack*>(nullptr), __ATOMIC_RELEASE);
226}
227
228void NetworkStack::receive(size_t nBytes, uintptr_t packet, Network* pCard, uint32_t offset) {
230
231 DeviceLease device;
232 if (!acquireDevice(pCard, device)) {
233 Metrics::increment(Metrics::NetworkRxNoDevice);
234 return;
235 }
236
237 receive(nBytes, packet, device, offset);
238}
239
240void NetworkStack::receive(size_t nBytes, uintptr_t packet, const DeviceLease& device,
241 uint32_t offset) {
243 assert(device.device());
244 Network* pCard = device.device();
245 packet += offset;
246
247 const size_t packetLength = nBytes;
248
249 if (!NetworkFilter::instance().filter(1, packet, nBytes)) {
250 Metrics::increment(Metrics::NetworkRxFiltered);
251 pCard->droppedPacket();
252 return; // Drop the packet.
253 }
254
255 struct pbuf* p = pbuf_alloc(PBUF_RAW, nBytes, PBUF_POOL);
256 if (p != 0) {
257 struct pbuf* buf = p;
258 while (buf != nullptr) {
259 MemoryCopy(buf->payload, reinterpret_cast<void*>(packet), buf->len);
260
261 packet += buf->len;
262 nBytes -= buf->len;
263
264 buf = buf->next;
265 }
266 } else {
267 Metrics::increment(Metrics::NetworkRxNoBuffer);
268 ERROR(
269 "Network Stack: Out of memory pool space, dropping incoming "
270 "packet");
271 pCard->droppedPacket();
272 return;
273 }
274
275 struct netif* iface = device.interface();
276 if (iface->input(p, iface) != ERR_OK) {
277 Metrics::increment(Metrics::NetworkRxInputFailed);
278 pbuf_free(p);
279 pCard->droppedPacket();
280 } else {
281 Metrics::increment(Metrics::NetworkRxAccepted);
282 Metrics::add(Metrics::NetworkRxBytes, packetLength);
283 }
284}
285
287#if THREADS || UTILITY_LINUX
288 LockGuard<Mutex> guard(m_Lock);
289#endif
290
291 size_t interfaceNumber = m_NextInterfaceNumber++;
292
293 if (interfaceNumber >= 0xFFU) {
294 FATAL("Too many network interfaces!");
295 }
296
297 struct netif* iface = new struct netif;
298 ByteSet(iface, 0, sizeof(*iface));
299
300 ip4_addr_t ipaddr;
301 ip4_addr_t netmask;
302 ip4_addr_t gateway;
303
304 // for dhcp/auto configuration
305 ByteSet(&ipaddr, 0, sizeof(ipaddr));
306 ByteSet(&netmask, 0, sizeof(netmask));
307 ByteSet(&gateway, 0, sizeof(gateway));
308
309 iface->name[0] = 'e';
310 iface->name[1] = 'n';
311 iface->num = interfaceNumber;
312
313 // netif_add mutates lwIP's global interface list. Keep the registry lock
314 // across this retired callback so deregistration cannot overtake a
315 // half-published device while the tcpip core performs that mutation.
316 AddInterfaceContext add = {iface, &ipaddr, &netmask, &gateway, pDevice, nullptr};
317 if (tcpip_callback_wait(addInterface, &add) != ERR_OK || !add.result) {
318 delete iface;
319 FATAL("NetworkStack could not register a network interface");
320 return;
321 }
322 iface = add.result;
323
324 DeviceRegistration* registration = new DeviceRegistration(iface);
325 m_Children.pushBack(pDevice);
326 m_Registrations.insert(pDevice, registration);
327}
328
330 lease = DeviceLease();
331#if THREADS || UTILITY_LINUX
332 LockGuard<Mutex> guard(m_Lock);
333#endif
334 if (n >= m_Children.count()) {
335 return false;
336 }
337
338 Network* device = m_Children[n];
339 DeviceRegistration* registration = m_Registrations.lookup(device);
341 if (!registration || !registration->readers.tryAcquire(reader)) {
342 return false;
343 }
344
345 lease = DeviceLease(device, registration->interface, pedigree_std::move(reader));
346 return true;
347}
348
350 lease = DeviceLease();
351#if THREADS || UTILITY_LINUX
352 LockGuard<Mutex> guard(m_Lock);
353#endif
354 DeviceRegistration* registration = m_Registrations.lookup(pDevice);
356 if (!registration || !registration->readers.tryAcquire(reader)) {
357 return false;
358 }
359
360 lease = DeviceLease(pDevice, registration->interface, pedigree_std::move(reader));
361 return true;
362}
363
365 DeviceRegistration* registration = nullptr;
366#if THREADS || UTILITY_LINUX
367 m_Lock.acquire();
368#endif
369
370 registration = m_Registrations.lookup(pDevice);
371 if (!registration) {
372#if THREADS || UTILITY_LINUX
373 m_Lock.release();
374#endif
375 return;
376 }
377
378 for (Vector<Network*>::Iterator it = m_Children.begin(); it != m_Children.end(); ++it) {
379 if (*it == pDevice) {
380 m_Children.erase(it);
381 break;
382 }
383 }
384
385 m_Registrations.remove(pDevice);
386 registration->readers.close();
387
388#if THREADS || UTILITY_LINUX
389 m_Lock.release();
390#endif
391
392 registration->readers.wait();
393 // Every admitted receive has finished posting to the lwIP mailbox. Its
394 // FIFO order retires those packets before the interface can be removed.
395 if (tcpip_callback_wait(removeInterface, registration->interface) != ERR_OK) {
396 FATAL("NetworkStack could not retire a network interface");
397 }
398 delete registration->interface;
399 delete registration;
400}
401
402static bool entry() {
403 g_NetworkStack = new NetworkStack();
404
405#if PEDIGREE_HOSTED_NETWORK_REGRESSION
406 if (!runHostedNetworkStackRegressions()) {
407 delete g_NetworkStack;
408 g_NetworkStack = nullptr;
409 return false;
410 }
411#endif
412
413 return true;
414}
415
416static void exit() {
417 delete g_NetworkStack;
418}
419
420// NetManager exposes a Filesystem, and so needs the vfs module.
421MODULE_INFO("network-stack", &entry, &exit, "vfs", "lwip");
static NetworkFilter & instance()
Definition Filter.h:43
size_t m_NextInterfaceNumber
MemoryPool m_MemPool
Tree< Network *, DeviceRegistration * > m_Registrations
void deRegisterDevice(Network *pDevice)
Vector< Network * > m_Children
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
MUST_USE_RESULT bool acquireDevice(size_t n, DeviceLease &lease)
void registerDevice(Network *pDevice)
virtual void droppedPacket()
Called when a packet is dropped by the system.
Definition Network.cc:127
virtual const StationInfo & getStationInfo()
Definition Network.cc:79
virtual bool send(size_t nBytes, uintptr_t buffer)=0
MUST_USE_RESULT bool tryAcquire(Lease &lease)
static bool inDeviceHardIrq()
Definition Processor.h:581
void release(size_t n=1)
Definition Semaphore.cc:549
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:355
An iterator applicable for many data structures.
Definition Iterator.h:147
A vector / dynamic array.
Definition Vector.h:33
Iterator end()
Definition Vector.h:172
T * Iterator
Definition Vector.h:36
Iterator begin()
Definition Vector.h:162
s8_t err_t
Definition err.h:76
@ ERR_IF
Definition err.h:106
@ ERR_OK
Definition err.h:82
@ Dec
Definition Log.h:126
void erase(size_t index)
Definition Vector.h:389
void pushBack(const T &value)
Definition Vector.h:275
void clear(bool freeMem=false)
Definition Vector.h:378
size_t count() const
Definition Vector.h:270
#define NETIF_FLAG_LINK_UP
Definition netif.h:106
#define NETIF_FLAG_ETHERNET
Definition netif.h:114
#define NETIF_FLAG_ETHARP
Definition netif.h:110
#define NETIF_FLAG_BROADCAST
Definition netif.h:100
#define netif_is_up(netif)
Definition netif.h:420
void netif_remove(struct netif *netif)
Definition netif.c:396
struct netif * netif_add(struct netif *netif, void *state, netif_init_fn init, netif_input_fn input)
Definition netif.c:260
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition pbuf.c:267
u8_t pbuf_free(struct pbuf *p)
Definition pbuf.c:734
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
Definition pbuf.c:1034
@ PBUF_POOL
Definition pbuf.h:142
@ PBUF_RAW
Definition pbuf.h:113
#define netif_is_link_up(netif)
Definition netif.h:432
Definition netif.h:244
u8_t flags
Definition netif.h:324
char name[2]
Definition netif.h:326
void * state
Definition netif.h:298
netif_input_fn input
Definition netif.h:263
u8_t num
Definition netif.h:328
u8_t hwaddr[NETIF_MAX_HWADDR_LEN]
Definition netif.h:322
u16_t mtu
Definition netif.h:318
netif_linkoutput_fn linkoutput
Definition netif.h:274
u8_t hwaddr_len
Definition netif.h:320
Definition pbuf.h:161
u16_t tot_len
Definition pbuf.h:175
struct pbuf * next
Definition pbuf.h:163
u16_t len
Definition pbuf.h:178
void * payload
Definition pbuf.h:166
Definition waits.c:9
err_t tcpip_callback_wait(tcpip_callback_fn function, void *ctx)
Definition tcpip.c:365
err_t tcpip_input(struct pbuf *p, struct netif *inp)
Definition tcpip.c:286