Skip to content

Commit

Permalink
Implemented USB incoming bulk transfers and SMSC95xx ethernet packet …
Browse files Browse the repository at this point in the history
…receiving.

Added the netrecv program to receive packets from a libnet device and dump its contents.
Modified the USBDevice implementation to actually get the full configuration descriptor
with interface and endpoint descriptors appended.
Added check for vendor and product id of SMSC95xx in the USBHub (temporary).
  • Loading branch information
nieklinnenbank committed Jan 11, 2016
1 parent 3b10413 commit 58d6671
Show file tree
Hide file tree
Showing 13 changed files with 487 additions and 23 deletions.
24 changes: 24 additions & 0 deletions bin/netrecv/Main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (C) 2015 Niek Linnenbank
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "NetReceive.h"

int main(int argc, char **argv)
{
NetReceive app(argc, argv);
return app.run();
}
171 changes: 171 additions & 0 deletions bin/netrecv/NetReceive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
/*
* Copyright (C) 2015 Niek Linnenbank
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <FreeNOS/System.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <ARP.h>
#include <Ethernet.h>
#include <MemoryBlock.h>
#include "NetReceive.h"

//
// Send manual formatted network packets:
//
// $ netsend smsc --arp --dest=192.168.1.123
//
// Receive and dump network packets:
//
// $ netrecv smsc
//
// Change device parameters:
//
// $ devctl smsc ip_address=192.168.1.2 ether_address=00:11:22:33:44:55
// $ devctl serial0 baudrate=9600
//
// Show device status and statistics:
//
// $ devstat smsc
// $ devstat serial0
//

NetReceive::NetReceive(int argc, char **argv)
: POSIXApplication(argc, argv)
{
m_socket = 0;

m_parser.setDescription("receive network packets");
m_parser.registerPositional("DEVICE", "device name of network adapter");
m_parser.registerPositional("ARGS", "optional key=value arguments", 0);
m_parser.registerFlag('a', "arp", "receive ARP packet(s)");
}

NetReceive::~NetReceive()
{
}

NetReceive::Result NetReceive::initialize()
{
DEBUG("");

for (HashIterator<String, Argument *> it(m_arguments.getFlags());
it.hasCurrent(); it++)
{
printf("key = '%s' value = '%s'\n",
*it.key(), it.current()->getName());
}

for (Size i = 0; i < m_arguments.getPositionals().count(); i++)
{
printf("pos[%d]: %s = %s\n", i, m_arguments.getPositionals()[i]->getName(),
m_arguments.getPositionals()[i]->getValue());
}

//const String *dev = m_arguments.get("device");
//if (dev)
// DEBUG("sending on device: " << **dev);

IPV4::Address ipAddr = (192 << 24) | (168 << 16) | (1 << 8) | (123);
Ethernet::Address etherAddr;

receiveArp();

return Success;
}

NetReceive::Result NetReceive::exec()
{
DEBUG("");
return Success;
}

NetReceive::Result NetReceive::receiveArp()
{
u8 packet[1500];// sizeof(Ethernet::Header) +
// sizeof(ARP::Header) ];

while (true)
{
receivePacket(packet, sizeof(packet));

Ethernet::Header *ether = (Ethernet::Header *) packet;
ARP::Header *arp = (ARP::Header *) (ether+1);

if (be16_to_cpu(ether->type) == Ethernet::ARP)
{
printf("ARP: hw=%u proto=%u hwlen=%u protolen=%u op=%u\n",
be16_to_cpu(arp->hardwareType),
be16_to_cpu(arp->protocolType),
arp->hardwareLength,
arp->protocolLength,
be16_to_cpu(arp->operation));
printf("ARP: mac src=%x", arp->etherSource.addr[0]);

for (int i = 1; i < 6; i++)
printf(":%x", arp->etherSource.addr[i]);

printf(" mac dest=%x", arp->etherDestination.addr[0]);
for (int i = 1; i < 6; i++)
printf(":%x", arp->etherSource.addr[i]);

printf("\n");

printf("ARP: ip src=%x ip dst=%x\n", be32_to_cpu(arp->ipSource), be32_to_cpu(arp->ipDestination));
return Success;
}
else
printf("skipped (not ARP, type %x)\n", be16_to_cpu(ether->type));
}
return Success;
}

NetReceive::Result NetReceive::receivePacket(u8 *packet, Size size)
{

DEBUG("");

// Receive on physical device
const char *device = m_arguments.getPositionals()[0]->getValue();
int fd = open(device, O_RDWR);
int result;

if (fd < 0)
{
printf("failed to open device '%s': %s\n", device, strerror(errno));
exit(EXIT_FAILURE);
}
printf("receiving on device: %s\n", device);

if ((result = read(fd, packet, size)) <= 0)
{
printf("failed to receive packet on device '%s': %s\n",
device, strerror(errno));
exit(EXIT_FAILURE);
}
printf("received %d bytes\n", result);

for (int i = 0; i < result; i++)
printf("%x ", packet[i]);
printf("\n");

// Done
return Success;
}
61 changes: 61 additions & 0 deletions bin/netrecv/NetReceive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2015 Niek Linnenbank
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __BIN_NETRECEIVE_H
#define __BIN_NETRECEIVE_H

#include <IPV4.h>
#include <Ethernet.h>
#include <POSIXApplication.h>

/**
* Network receive application.
*/
class NetReceive : public POSIXApplication
{
public:

/**
* Class constructor.
*/
NetReceive(int argc, char **argv);

/**
* Class destructor.
*/
virtual ~NetReceive();

/**
* Initialize the application.
*/
virtual Result initialize();

/**
* Execute the application event loop.
*/
virtual Result exec();

private:

Result receiveArp();
Result receivePacket(u8 *packet, Size size);

/** Socket */
int m_socket;
};

#endif /* __BIN_NETRECEIVE_H */
23 changes: 23 additions & 0 deletions bin/netrecv/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Copyright (C) 2010 Niek Linnenbank
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

Import('build_env')

env = build_env.Clone()
env.UseLibraries([ 'libposix', 'liballoc', 'libstd', 'libexec', 'libarch', 'libnet', 'libipc' ])
env.UseServers(['core'])
env.TargetProgram('netrecv', Glob('*.cpp'), env['bin'])
2 changes: 2 additions & 0 deletions lib/libipc/ChannelClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ ChannelClient::Result ChannelClient::syncReceiveFrom(void *buffer, ProcessID pid
if (!ch)
return NotFound;

#warning use Sleep instead to avoid unneeded spinning

while (ch->read(buffer) != Channel::Success)
ProcessCtl(SELF, Schedule, 0);

Expand Down
3 changes: 3 additions & 0 deletions lib/libnet/Ethernet.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
*/
namespace Ethernet
{
/** Size of the CRC checksum (which is set after the payload) */
static const Size CRCSize = 4;

/**
* Ethernet network address
*/
Expand Down
51 changes: 50 additions & 1 deletion lib/libnet/SMSC95xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,56 @@ Error SMSC95xx::initialize()

Error SMSC95xx::read(IOBuffer & buffer, Size size, Size offset)
{
return ENOTSUP;
DEBUG("size = " << size);

// Check packet size
if (size > m_packetSize - ReceiveCommandSize)
{
ERROR("packet size too large: " << size);
return ERANGE;
}
#warning TODO: implement this in a separate circular buffer which is always processed by the driver
#warning and then copied to the user (via filter rules etc) when needed
DEBUG("begin receive transfer at endpoint addr: " << (m_endpoints[0].endpointAddress & 0xf) << " maxpacketsize: " << m_endpoints[0].maxPacketSize);

Size rxSize = SMSC9512_DEFAULT_HS_BURST_CAP_SIZE; //size + ReceiveCommandSize;
Size frameLength = 0;
u8 *data = m_packet;

Error r = transfer(USBTransfer::Bulk,
USBTransfer::In,
m_endpoints[0].endpointAddress & 0xf,
m_packet,
rxSize,
m_endpoints[0].maxPacketSize);

if (r != ESUCCESS)
{
ERROR("receive packet bulk in transfer failed");
return r;
}

#warning How to represent multiple packets in one buffer? Perhaps pad each packet to PAGESIZE boundaries, or prefix with a libnet specific header?

// Extract packets and copy to the user
for (Size i = 0; i < rxSize; i += frameLength)
{
u32 receiveCmd = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;
frameLength = (receiveCmd & RxCommandFrameLength) >> 16;

if (frameLength == 0)
{
ERROR("invalid zero framelength");
return EIO;
}
DEBUG("packet is " << frameLength << " bytes long");
buffer.write(data + ReceiveCommandSize, frameLength);
return frameLength;
}

// TODO: extract frame info. copy to the user
DEBUG("done with result: " << (int) r);
return r;
}

Error SMSC95xx::write(IOBuffer & buffer, Size size, Size offset)
Expand Down
24 changes: 24 additions & 0 deletions lib/libnet/SMSC95xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,30 @@ class SMSC95xx : public USBDevice
/** Transmit Command Word size. */
static const Size TransmitCommandSize = 8;

/**
* Receive Command Words.
*/
enum ReceiveCommand
{
RxCommandFilterFail = 0x40000000,
RxCommandFrameLength = 0x3fff0000,
RxCommandErrorSummary = 0x00008000,
RxCommandBroadcastFrame = 0x00002000,
RxCommandLengthError = 0x00001000,
RxCommandRuntFrame = 0x00000800,
RxCommandMulticastFrame = 0x00000400,
RxCommandFrameTooLong = 0x00000080,
RxCommandFrameCollision = 0x00000040,
RxCommandFrameType = 0x00000020,
RxCommandReceiveWatchdog = 0x00000010,
RxCommandMIIError = 0x00000008,
RxCommandDribbling = 0x00000004,
RxCommandCRCError = 0x00000002
};

/** Receive Command Word size. */
static const Size ReceiveCommandSize = 4;

public:

/**
Expand Down
Loading

0 comments on commit 58d6671

Please sign in to comment.