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 "modules/Module.h"
21 #include "modules/system/network-stack/Filter.h"
22 #include "pedigree/kernel/LockGuard.h"
23 #include "pedigree/kernel/Log.h"
24 #include "pedigree/kernel/compiler.h"
25 #include "pedigree/kernel/machine/Machine.h"
26 #include "pedigree/kernel/machine/Serial.h"
27 #include "pedigree/kernel/process/Mutex.h"
28 #include "pedigree/kernel/processor/types.h"
29 #include "pedigree/kernel/time/Time.h"
30 
31 struct PcapHeader
32 {
33  uint32_t magic;
34  uint16_t major;
35  uint16_t minor;
36  uint32_t tz;
37  uint32_t sigfig;
38  uint32_t caplen;
39  uint32_t network;
40 };
41 
42 struct PcapRecord
43 {
44  uint32_t ts_sec;
45  uint32_t ts_usec;
46  uint32_t stored_length;
47  uint32_t orig_length;
48 };
49 
50 #define PCAP_MAGIC 0xa1b2c3d4
51 
52 #define PCAP_MAJOR 2
53 #define PCAP_MINOR 4
54 
55 #define PCAP_NETWORK 1
56 
57 static size_t g_FilterEntry = 0;
58 
59 static Mutex g_PcapMutex(false);
60 
61 static Serial *getSerial() PURE;
62 static Serial *getSerial()
63 {
64  // Ignore if we don't have a machine abstraction yet.
65  if (!Machine::instance().isInitialised())
66  {
67  return 0;
68  }
69 
70  // Serial port to write PCAP data to.
71  if (Machine::instance().getNumSerial() < 3)
72  {
73  return 0;
74  }
75 
76  return Machine::instance().getSerial(2);
77 }
78 
79 bool pcapLogPacket(uintptr_t packet, size_t size)
80 {
81  LockGuard<Mutex> guard(g_PcapMutex);
82 
83  Serial *pSerial = getSerial();
84  if (!pSerial)
85  {
86  return true;
87  }
88 
89  // 256K is the max packet we ever want to capture.
90  if (size >= 262144)
91  {
92  ERROR("pcap: packet is way too big - size is " << size);
93  return true; // don't write to the serial port at all.
94  }
95 
96  static uint64_t time = 0;
97 
98  // Time::Timestamp time = Time::getTimeNanoseconds();
99 
100  // Don't care about timing in Wireshark but do care about ordering, and
101  // so we want timestamps to always increase.
102  time += Time::Multiplier::Millisecond;
103 
104  PcapRecord header;
105  header.ts_sec = time / Time::Multiplier::Second;
106  header.ts_usec =
107  (time % Time::Multiplier::Second) / Time::Multiplier::Microsecond;
108  header.stored_length = size;
109  header.orig_length = size;
110 
111  // Write the pcap record header.
112  const uint8_t *headerData = reinterpret_cast<const uint8_t *>(&header);
113  for (size_t i = 0; i < sizeof(header); ++i)
114  {
115  pSerial->write(headerData[i]);
116  }
117 
118  // Write the packet data now.
119  const uint8_t *data = reinterpret_cast<const uint8_t *>(packet);
120  for (size_t i = 0; i < size; ++i)
121  {
122  pSerial->write(data[i]);
123  }
124 
125  // Always let the packet through.
126  return true;
127 }
128 
129 static bool entry()
130 {
131  LockGuard<Mutex> guard(g_PcapMutex);
132 
133  Serial *pSerial = getSerial();
134  if (!pSerial)
135  {
136  NOTICE("pcap: could not find a useful serial port");
137  return false;
138  }
139 
140  g_FilterEntry = NetworkFilter::instance().installCallback(1, pcapLogPacket);
141  if (g_FilterEntry == static_cast<size_t>(-1))
142  {
143  NOTICE("pcap: could not install callback");
144  return false;
145  }
146 
147  PcapHeader header;
148  header.magic = PCAP_MAGIC;
149  header.major = PCAP_MAJOR;
150  header.minor = PCAP_MINOR;
151  header.tz = 0;
152  header.sigfig = 0;
153  header.caplen = 0xFFFF;
154  header.network = PCAP_NETWORK;
155 
156  const uint8_t *data = reinterpret_cast<const uint8_t *>(&header);
157  for (size_t i = 0; i < sizeof(header); ++i)
158  {
159  pSerial->write(data[i]);
160  }
161 
162  return true;
163 }
164 
165 static void exit()
166 {
167  NetworkFilter::instance().removeCallback(1, g_FilterEntry);
168 }
169 
170 MODULE_INFO("pcap", &entry, &exit, "network-stack");
virtual Serial * getSerial(size_t n)=0
void removeCallback(size_t level, size_t id)
Definition: Filter.cc:106
Definition: Mutex.h:58
#define NOTICE(text)
Definition: Log.h:74
size_t installCallback(size_t level, bool(*callback)(uintptr_t, size_t))
Definition: Filter.cc:63
#define ERROR(text)
Definition: Log.h:82
static NetworkFilter & instance()
Definition: Filter.h:40