The Pedigree Project  0.1
Ne2k.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 "Ne2k.h"
21 #include "Ne2kConstants.h"
22 #include "modules/system/network-stack/NetworkStack.h"
23 #include "pedigree/kernel/LockGuard.h"
24 #include "pedigree/kernel/Log.h"
25 #include "pedigree/kernel/machine/Device.h"
26 #include "pedigree/kernel/machine/IrqManager.h"
27 #include "pedigree/kernel/machine/Machine.h"
28 #include "pedigree/kernel/machine/Network.h"
29 #include "pedigree/kernel/network/IpAddress.h"
30 #include "pedigree/kernel/network/MacAddress.h"
31 #include "pedigree/kernel/process/Thread.h"
32 #include "pedigree/kernel/processor/IoBase.h"
33 #include "pedigree/kernel/processor/Processor.h"
34 #include "pedigree/kernel/processor/ProcessorInformation.h"
35 #include "pedigree/kernel/utilities/MemoryPool.h"
36 #include "pedigree/kernel/utilities/Vector.h"
37 #include "pedigree/kernel/utilities/utility.h"
38 
39 // #define NE2K_NO_THREADS
40 
42  : Network(pDev), m_pBase(0), m_NextPacket(0), m_PacketQueueSize(0),
43  m_PacketQueue(), m_PacketQueueLock()
44 {
45  setSpecificType(String("ne2k-card"));
46 
47  // grab the ports
48  m_pBase = m_Addresses[0]->m_Io;
49 
50  // Reset the card, and clear interrupts
51  // m_pBase->write8(m_pBase->read8(NE_RESET), NE_RESET);
52  // while((m_pBase->read8(NE_ISR) & 0x80) == 0);
53  // m_pBase->write8(0xff, NE_ISR);
54 
55  // reset command
56  m_pBase->write8(0x21, NE_CMD);
57 
58  // 16-bit transfer, monitor to avoid recv, loopback just in case
59  // because we don't want to receive packets yet
60  m_pBase->write8(0x09, NE_DCR);
61  m_pBase->write8(0x20, NE_RCR);
62  m_pBase->write8(0x02, NE_TCR);
63 
64  // turn off interrupts
65  m_pBase->write8(0xff, NE_ISR);
66  m_pBase->write8(0x00, NE_IMR);
67 
68  // get the MAC from PROM
69  m_pBase->write8(0x00, NE_RSAR0);
70  m_pBase->write8(0x00, NE_RSAR1);
71 
72  m_pBase->write8(32, NE_RBCR0); // 32 bytes of data
73  m_pBase->write8(0, NE_RBCR1);
74 
75  m_pBase->write8(0x0a, NE_CMD); // remote read, STOP
76 
77  uint16_t prom[16];
78  int i;
79  for (i = 0; i < 16; i++)
80  prom[i] = m_pBase->read16(NE_DATA);
81 
82  // set the MAC address in the card itself
83  m_pBase->write8(0x61, NE_CMD);
84  for (i = 0; i < 6; i++)
85  {
86  m_StationInfo.mac.setMac(prom[i] & 0xff, i);
87  m_pBase->write8(prom[i] & 0xff, NE_PAR + i);
88  }
89 
90  WARNING(
91  "NE2K: MAC is " << m_StationInfo.mac[0] << ":" << m_StationInfo.mac[1]
92  << ":" << m_StationInfo.mac[2] << ":"
93  << m_StationInfo.mac[3] << ":" << m_StationInfo.mac[4]
94  << ":" << m_StationInfo.mac[5] << ".");
95 
96  // reset current page, put the card into normal mode, and set
97  // packet buffer information
98  m_pBase->write8(0x61, NE_CMD);
99  m_pBase->write8(PAGE_RX + 1, NE_CURR);
100 
101  m_NextPacket = PAGE_RX + 1;
102 
103  m_pBase->write8(0x21, NE_CMD);
104 
105  m_pBase->write8(PAGE_RX, NE_PSTART);
106  m_pBase->write8(PAGE_RX, NE_BNDRY);
107  m_pBase->write8(PAGE_STOP, NE_PSTOP);
108 
109  // accept multicast, broadcast, and runt packets (<64 bytes)
111  m_pBase->write8(0x14, NE_RCR);
112  m_pBase->write8(0x00, NE_TCR);
113 
114  // Accept all multicast packets. Once we have an API for multicast
115  // subscription this will be different, as we may not want to receive every
116  // single multicast packet that arrives.
117  uint8_t tmp = m_pBase->read8(NE_CMD);
118  m_pBase->write8(tmp | 0x40, NE_CMD);
119  for (i = 0; i < MAR_SIZE; i++)
120  m_pBase->write8(0xFF, NE_MAR + i);
121  m_pBase->write8(tmp, NE_CMD);
122 
123 // register the packet queue handler before we install the IRQ
124 #ifdef THREADS
125  Thread *pThread = new Thread(
126  Processor::information().getCurrentThread()->getParent(), &trampoline,
127  reinterpret_cast<void *>(this));
128  pThread->detach();
129 #endif
130 
131  // install the IRQ
132  NOTICE("NE2K: IRQ is " << getInterruptNumber());
133  Machine::instance().getIrqManager()->registerIsaIrqHandler(
134  getInterruptNumber(), static_cast<IrqHandler *>(this));
135 
136  // clear interrupts and enable the ones we want
137  m_pBase->write8(0xff, NE_ISR);
138  m_pBase->write8(0x3D, NE_IMR); // No IRQ for "packet transmitted"
139 
140  // start the card working properly
141  m_pBase->write8(0x22, NE_CMD);
142 
144 }
145 
146 Ne2k::~Ne2k()
147 {
148 }
149 
150 bool Ne2k::send(size_t nBytes, uintptr_t buffer)
151 {
152  if (nBytes > 0xffff)
153  {
154  ERROR("NE2K: Attempt to send a packet with size > 64 KB");
155  return false;
156  }
157 
158  // length & address for the write
159  m_pBase->write8(0, NE_RSAR0);
160  m_pBase->write8(PAGE_TX, NE_RSAR1);
161 
162  m_pBase->write8(
163  (nBytes > 64) ? nBytes & 0xff : 64,
164  NE_RBCR0); // always send at least 64 bytes
165  m_pBase->write8(nBytes >> 8, NE_RBCR1);
166 
167  m_pBase->write8(0x12, NE_CMD); // write, start
168 
169  uint16_t *data = reinterpret_cast<uint16_t *>(buffer);
170  size_t i;
171  for (i = 0; (i + 1) < nBytes; i += 2)
172  m_pBase->write16(data[i / 2], NE_DATA);
173 
174  // handle odd byte
175  if (nBytes & 1)
176  {
177  if (nBytes < 64)
178  {
179  m_pBase->write8(data[i / 2] & 0xff, NE_DATA);
180  i += 2;
181  }
182  else
183  {
184  m_pBase->write8(data[i / 2] & 0xff, NE_DATA);
185  i++;
186  }
187  }
188 
189  // pad the packet to 64 bytes
190  for (; i < 64; i += 2)
191  m_pBase->write16(0, NE_DATA);
192 
193  // let it complete
194  while (!(m_pBase->read8(NE_ISR) & 0x40))
195  ;
196  m_pBase->write8(0x40, NE_ISR);
197 
198  // execute the transmission
199  m_pBase->write8((nBytes > 64) ? nBytes & 0xff : 64, NE_TBCR0);
200  m_pBase->write8(nBytes >> 8, NE_TBCR1);
201 
202  m_pBase->write8(PAGE_TX, NE_TPSR);
203 
204  m_pBase->write8(0x26, NE_CMD);
205 
206  // success!
207  return true;
208 }
209 
210 void Ne2k::recv()
211 {
212  // Grab the current buffer in the ring
213  m_pBase->write8(0x61, NE_CMD);
214  uint8_t current = m_pBase->read8(NE_CURR);
215  m_pBase->write8(0x21, NE_CMD);
216 
217  // Read packets until the current packet
218  while (m_NextPacket != current)
219  {
220  // Want status and length
221  m_pBase->write8(0, NE_RSAR0);
222  m_pBase->write8(m_NextPacket, NE_RSAR1);
223  m_pBase->write8(4, NE_RBCR0);
224  m_pBase->write8(0, NE_RBCR1);
225  m_pBase->write8(0x0a, NE_CMD); // Read, Start
226 
227  // Grab the information we want
228  uint16_t status = m_pBase->read16(NE_DATA);
229  uint16_t length = m_pBase->read16(NE_DATA);
230 
231  if (!length)
232  {
233  ERROR("NE2K: length of packet is invalid!");
234  continue;
235  }
236 
237  // Remove the status and length bytes
238  length -= 3;
239 
240  // packet buffer
241  uint8_t *tmp = reinterpret_cast<uint8_t *>(
243  uint16_t *packBuffer = reinterpret_cast<uint16_t *>(tmp);
244  ByteSet(tmp, 0, length);
245 
246  // check status, new read for the rest of the packet
247  while (!(m_pBase->read8(NE_ISR) & 0x40))
248  ;
249  m_pBase->write8(0x40, NE_ISR);
250 
251  m_pBase->write8(4, NE_RSAR0);
252  m_pBase->write8(m_NextPacket, NE_RSAR1);
253  m_pBase->write8((length) &0xff, NE_RBCR0);
254  m_pBase->write8((length) >> 8, NE_RBCR1);
255  m_pBase->write8(0x0a, NE_CMD);
256 
257  // read the packet
258  int i, words = length / 2, oddbytes = length % 2;
259  for (i = 0; i < words; ++i)
260  packBuffer[i] = m_pBase->read16(NE_DATA);
261  if (oddbytes)
262  {
263  for (i = 0; i < oddbytes; ++i)
264  tmp[(length - oddbytes) + i] =
265  m_pBase->read16(NE_DATA) &
266  0xFF; // odd packet length handler
267  }
268 
269  // check status once again
270  while (!(m_pBase->read8(NE_ISR) & 0x40))
271  ; // no interrupts at all, this wastes time...
272  m_pBase->write8(0x40, NE_ISR);
273 
274  // set the next packet, inform the card of the new boundary
275  m_NextPacket = status >> 8;
276  m_pBase->write8(
277  (m_NextPacket == PAGE_RX) ? (PAGE_STOP - 1) : (m_NextPacket - 1),
278  NE_BNDRY);
279 
280  // push onto the queue
281  packet *p = new packet;
282  p->ptr = reinterpret_cast<uintptr_t>(packBuffer);
283  p->len = length;
284 
285 #ifdef NE2K_NO_THREADS
286 
287  NetworkStack::instance().receive(p->len, p->ptr, this, 0);
288 
290  delete p;
291 
292 #else
293 
294  {
295  LockGuard<Spinlock> guard(m_PacketQueueLock);
296  m_PacketQueue.pushBack(p);
297  m_PacketQueueSize.release();
298  }
299 
300 #endif
301  }
302 }
303 
304 int Ne2k::trampoline(void *p)
305 {
306  Ne2k *pNe = reinterpret_cast<Ne2k *>(p);
307  pNe->receiveThread();
308 }
309 
310 void Ne2k::receiveThread()
311 {
312  while (true)
313  {
314  // handle the incoming packet
315  m_PacketQueueSize.acquire();
316 
317  // grab from the front
318  packet *p = 0;
319  {
320  LockGuard<Spinlock> guard(m_PacketQueueLock);
321  p = m_PacketQueue.popFront();
322  }
323 
324  if (!p)
325  continue;
326  else if (!p->ptr || !p->len)
327  continue;
328 
329  // pass to the network stack
330  NetworkStack::instance().receive(p->len, p->ptr, this, 0);
331 
332  // destroy the buffer now that it's handled
334  delete p;
335  }
336 }
337 
339 {
340  // free the old DNS servers list, if there is one
341  if (m_StationInfo.dnsServers)
342  delete[] m_StationInfo.dnsServers;
343 
344  // MAC isn't changeable, so set it all manually
345  m_StationInfo.ipv4 = info.ipv4;
346  NOTICE(
347  "NE2K: Setting ipv4, " << info.ipv4.toString() << ", "
348  << m_StationInfo.ipv4.toString() << "...");
349 
350  m_StationInfo.ipv6 = info.ipv6;
351  m_StationInfo.nIpv6Addresses = info.nIpv6Addresses;
352  NOTICE("NE2K: Copied " << info.nIpv6Addresses << " IPv6 addresses.");
353 
354  m_StationInfo.subnetMask = info.subnetMask;
355  NOTICE(
356  "NE2K: Setting subnet mask, " << info.subnetMask.toString() << ", "
357  << m_StationInfo.subnetMask.toString()
358  << "...");
359  m_StationInfo.gateway = info.gateway;
360  NOTICE(
361  "NE2K: Setting gateway, " << info.gateway.toString() << ", "
362  << m_StationInfo.gateway.toString() << "...");
363 
364  // Callers do not free their dnsServers memory
365  m_StationInfo.dnsServers = info.dnsServers;
366  m_StationInfo.nDnsServers = info.nDnsServers;
367  NOTICE(
368  "NE2K: Setting DNS servers [" << Dec << m_StationInfo.nDnsServers << Hex
369  << " servers being set]...");
370 
371  return true;
372 }
373 
375 {
376  return m_StationInfo;
377 }
378 
379 bool Ne2k::irq(irq_id_t number, InterruptState &state)
380 {
381  // Grab the interrupt status
382  uint8_t irqStatus = m_pBase->read8(NE_ISR);
383 
384  // Handle packet received - recv will handle all interim packets as well
385  // as the one which triggered the IRQ
386  if (irqStatus & 0x05)
387  {
388  m_pBase->write8(0x3D, NE_IMR); // RECV
389  recv();
390  m_pBase->write8(0x3D, NE_IMR); // Enable recv interrupts again
391  }
392 
393  // Handle packet transmitted
394  if (irqStatus & 0x0A)
395  {
396  // Failure?
397  if (irqStatus & 0x8)
398  WARNING("NE2K: Packet transmit failed!");
399  }
400 
401  // Overflows
403  if (irqStatus & 0x10)
404  {
405  WARNING("NE2K: Receive buffer overflow");
406  }
407  if (irqStatus & 0x20)
408  {
409  WARNING("NE2K: Counter overflow");
410  }
411 
412  // Ack all status items
413  m_pBase->write8(irqStatus, NE_ISR);
414 
415  return true;
416 }
417 
419 {
420  // The NE2K chip doesn't support detecting the link state, so we have to
421  // just assume the link is active.
422  return true;
423 }
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition: Semaphore.h:62
Ne2k(Network *pDev)
Definition: Ne2k.cc:41
virtual void write8(uint8_t value, size_t offset=0)=0
virtual uint16_t read16(size_t offset=0)=0
Definition: String.h:49
IpAddress gateway
Automatically calculated?
static ProcessorInformation & information()
Definition: Processor.cc:45
virtual uintptr_t getInterruptNumber()
Definition: Device.h:262
void receive(size_t nBytes, uintptr_t packet, Network *pCard, uint32_t offset)
size_t nDnsServers
Can contain IPv6 addresses.
Definition: Ne2k.h:41
virtual const StationInfo & getStationInfo()
Definition: Ne2k.cc:374
virtual void write16(uint16_t value, size_t offset=0)=0
MemoryPool & getMemPool()
Definition: NetworkStack.h:81
#define WARNING(text)
Definition: Log.h:78
virtual void setSpecificType(String str)
Definition: Device.h:174
void release(size_t n=1)
Definition: Semaphore.cc:239
#define NOTICE(text)
Definition: Log.h:74
uintptr_t allocate()
Definition: MemoryPool.cc:176
Definition: Log.h:136
virtual bool setStationInfo(const StationInfo &info)
Definition: Ne2k.cc:338
static NetworkStack & instance()
Definition: NetworkStack.h:47
void registerDevice(Network *pDevice)
Vector< Address * > m_Addresses
Definition: Device.h:362
Definition: Thread.h:54
virtual irq_id_t registerIsaIrqHandler(uint8_t irq, IrqHandler *handler, bool bEdge=false)=0
virtual uint8_t read8(size_t offset=0)=0
void free(uintptr_t buffer)
Frees an allocated buffer, allowing it to be used elsewhere.
Definition: MemoryPool.cc:251
#define ERROR(text)
Definition: Log.h:82
bool detach()
Definition: Thread.cc:885
Definition: Log.h:138
virtual bool irq(irq_id_t number, InterruptState &state)
Definition: Ne2k.cc:379
bool isConnected()
Definition: Ne2k.cc:418
Device * getParent() const
Definition: Device.h:149
virtual bool send(size_t nBytes, uintptr_t buffer)
Definition: Ne2k.cc:150