The Pedigree Project 0.1
modules/system/pcap/main.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 "pedigree/kernel/LockGuard.h"
21#include "pedigree/kernel/Log.h"
22#include "pedigree/kernel/compiler.h"
23#include "pedigree/kernel/machine/Machine.h"
24#include "pedigree/kernel/machine/Serial.h"
25#include "pedigree/kernel/process/Mutex.h"
26#include "pedigree/kernel/processor/types.h"
27#include "pedigree/kernel/time/Time.h"
28
29#include "modules/Module.h"
30#include "modules/system/network-stack/Filter.h"
31
32#define PCAP_MAGIC 0xa1b2c3d4
33
34#define PCAP_MAJOR 2
35#define PCAP_MINOR 4
36
37#define PCAP_NETWORK 1
38
39static size_t g_FilterEntry = 0;
40
41static Mutex g_PcapMutex;
42
43static void writePcapUint16(Serial* pSerial, uint16_t value) {
44 pSerial->write(static_cast<char>(value & 0xff));
45 pSerial->write(static_cast<char>((value >> 8) & 0xff));
46}
47
48static void writePcapUint32(Serial* pSerial, uint32_t value) {
49 pSerial->write(static_cast<char>(value & 0xff));
50 pSerial->write(static_cast<char>((value >> 8) & 0xff));
51 pSerial->write(static_cast<char>((value >> 16) & 0xff));
52 pSerial->write(static_cast<char>((value >> 24) & 0xff));
53}
54
55static Serial* getSerial() PURE;
56static Serial* getSerial() {
57 // Ignore if we don't have a machine abstraction yet.
58 if (!Machine::instance().isInitialised()) {
59 return 0;
60 }
61
62 // Serial port to write PCAP data to.
63 if (Machine::instance().getNumSerial() < 3) {
64 return 0;
65 }
66
67 return Machine::instance().getSerial(2);
68}
69
70bool pcapLogPacket(uintptr_t packet, size_t size) {
71 LockGuard<Mutex> guard(g_PcapMutex);
72
73 Serial* pSerial = getSerial();
74 if (!pSerial) {
75 return true;
76 }
77
78 // 256K is the max packet we ever want to capture.
79 if (size >= 262144) {
80 ERROR("pcap: packet is way too big - size is " << size);
81 return true; // don't write to the serial port at all.
82 }
83
84 static uint64_t time = 0;
85
86 // Time::Timestamp time = Time::getTimeNanoseconds();
87
88 // Don't care about timing in Wireshark but do care about ordering, and
89 // so we want timestamps to always increase.
90 time += Time::Multiplier::Millisecond;
91
92 // PCAP readers use the magic to determine byte order. Emit one canonical
93 // little-endian representation rather than relying on the target ABI.
94 writePcapUint32(pSerial, static_cast<uint32_t>(time / Time::Multiplier::Second));
95 writePcapUint32(pSerial, static_cast<uint32_t>((time % Time::Multiplier::Second) /
96 Time::Multiplier::Microsecond));
97 writePcapUint32(pSerial, static_cast<uint32_t>(size));
98 writePcapUint32(pSerial, static_cast<uint32_t>(size));
99
100 // Write the packet data now.
101 const uint8_t* data = reinterpret_cast<const uint8_t*>(packet);
102 for (size_t i = 0; i < size; ++i) {
103 pSerial->write(data[i]);
104 }
105
106 // Always let the packet through.
107 return true;
108}
109
110static bool entry() {
111 LockGuard<Mutex> guard(g_PcapMutex);
112
113 Serial* pSerial = getSerial();
114 if (!pSerial) {
115 NOTICE("pcap: could not find a useful serial port");
116 return false;
117 }
118
119 g_FilterEntry = NetworkFilter::instance().installCallback(1, pcapLogPacket);
120 if (g_FilterEntry == static_cast<size_t>(-1)) {
121 NOTICE("pcap: could not install callback");
122 return false;
123 }
124
125 writePcapUint32(pSerial, PCAP_MAGIC);
126 writePcapUint16(pSerial, PCAP_MAJOR);
127 writePcapUint16(pSerial, PCAP_MINOR);
128 writePcapUint32(pSerial, 0); // UTC timezone
129 writePcapUint32(pSerial, 0); // timestamp accuracy is unspecified
130 writePcapUint32(pSerial, 0xFFFF);
131 writePcapUint32(pSerial, PCAP_NETWORK);
132
133 return true;
134}
135
136static void exit() {
137 NetworkFilter::instance().removeCallback(1, g_FilterEntry);
138}
139
140MODULE_INFO("pcap", &entry, &exit, "network-stack");
virtual Serial * getSerial(size_t n)=0
Definition Mutex.h:56
size_t installCallback(size_t level, bool(*callback)(uintptr_t, size_t))
Definition Filter.cc:141
static NetworkFilter & instance()
Definition Filter.h:43
bool removeCallback(size_t level, size_t id)
Definition Filter.cc:165