Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ip #355

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Ip #355

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 45 additions & 2 deletions src/EtherCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,11 @@
*/
#define ETHERCARD_STASH 1

/** Set ARP cache max entry count */
#ifndef ETHERCARD_ARP_STORE_SIZE
# define ETHERCARD_ARP_STORE_SIZE 4
#endif


/** This type definition defines the structure of a UDP server event handler callback function */
typedef void (*UdpServerCallback)(
Expand All @@ -100,6 +105,7 @@ typedef void (*DhcpOptionCallback)(
const byte* data, ///< DHCP option data
uint8_t len); ///< Length of the DHCP option data

typedef void (*IcmpCallback)(const uint8_t *src_ip);


/** This class provides the main interface to a ENC28J60 based network interface card and is the class most users will use.
Expand Down Expand Up @@ -190,6 +196,16 @@ class EtherCard : public Ethernet {
*/
static void updateBroadcastAddress();

/** @brief Request the IP associated hardware address (ARP lookup). Use
* clientWaitIp(ip) to get the ARP lookup status
*/
static void clientResolveIp(const uint8_t *ip);

/** @brief Check if got IP associated hardware address (ARP lookup)
* @return <i>unit8_t</i> True if gateway found
*/
static uint8_t clientWaitIp(const uint8_t *ip);

/** @brief Check if got gateway hardware address (ARP lookup)
* @return <i>unit8_t</i> True if gateway found
*/
Expand Down Expand Up @@ -283,7 +299,7 @@ class EtherCard : public Ethernet {
/** @brief Resister the function to handle ping events
* @param cb Pointer to function
*/
static void registerPingCallback (void (*cb)(uint8_t*));
static void registerPingCallback (const IcmpCallback cb);

/** @brief Send ping
* @param destip Pointer to 4 byte destination IP address
Expand Down Expand Up @@ -342,7 +358,7 @@ class EtherCard : public Ethernet {
* @param len Not used
* @return <i>bool</i> True if packet processed
*/
static bool udpServerHasProcessedPacket(uint16_t len); //called by tcpip, in packetLoop
static bool udpServerHasProcessedPacket(const IpHeader &ip, const uint8_t *iter, const uint8_t *last); //called by tcpip, in packetLoop

// dhcp.cpp
/** @brief Update DHCP state
Expand Down Expand Up @@ -484,6 +500,33 @@ class EtherCard : public Ethernet {
/** @brief Return the payload length of the current Tcp package
*/
static uint16_t getTcpPayloadLength();

/** @brief Check if IP is in ARP store
* @param ip IP to check (size must be IP_LEN)
* @return <i>bool</i> True if IP is in ARP store
*/
static bool arpStoreHasMac(const uint8_t *ip);

/** @brief convert IP into associated MAC address
* @param ip IP to convert to MAC address (size must be IP_LEN)
* @return <i>uint8_t *</i> mac MAC address or NULL if not found
*/
static const uint8_t *arpStoreGetMac(const uint8_t *ip);

/** @brief set/refresh new couple IP/MAC addresses into ARP store
* @param ip IP address
* @param mac MAC address
*/
static void arpStoreSet(const uint8_t *ip, const uint8_t *mac);

/** @brief remove IP from ARP store
* @param ip IP address to remove
*/
static void arpStoreInvalidIp(const uint8_t *ip);

private:
static void packetLoopIdle();
static void packetLoopArp(const uint8_t *first, const uint8_t *last);
};

extern EtherCard ether; //!< Global presentation of EtherCard class
Expand Down
93 changes: 93 additions & 0 deletions src/arp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include "EtherCard.h"

struct ArpEntry
{
uint8_t ip[IP_LEN];
uint8_t mac[ETH_LEN];
uint8_t count;
};

static ArpEntry store[ETHERCARD_ARP_STORE_SIZE];

static void incArpEntry(ArpEntry &e)
{
if (e.count < 0xFF)
++e.count;
}

// static ArpEntry print_store()
// {
// Serial.println("ARP store: ");
// for (ArpEntry *iter = store, *last = store + ETHERCARD_ARP_STORE_SIZE;
// iter != last; ++iter)
// {
// ArpEntry &e = *iter;
// Serial.print('\t');
// EtherCard::printIp(e.ip);
// Serial.print(' ');
// for (int i = 0; i < ETH_LEN; ++i)
// {
// if (i > 0)
// Serial.print(':');
// Serial.print(e.mac[i], HEX);
// }
// Serial.print(' ');
// Serial.println(e.count);
// }
// }

static ArpEntry *findArpStoreEntry(const uint8_t *ip)
{
for (ArpEntry *iter = store, *last = store + ETHERCARD_ARP_STORE_SIZE;
iter != last; ++iter)
{
if (memcmp(ip, iter->ip, IP_LEN) == 0)
return iter;
}
return NULL;
}

bool EtherCard::arpStoreHasMac(const uint8_t *ip)
{
return findArpStoreEntry(ip) != NULL;
}

const uint8_t *EtherCard::arpStoreGetMac(const uint8_t *ip)
{
ArpEntry *e = findArpStoreEntry(ip);
if (e)
return e->mac;
return NULL;
}

void EtherCard::arpStoreSet(const uint8_t *ip, const uint8_t *mac)
{
ArpEntry *e = findArpStoreEntry(ip);
if (!e)
{
// find less used entry
e = store;
for (ArpEntry *iter = store + 1, *last = store + ETHERCARD_ARP_STORE_SIZE;
iter != last; ++iter)
{
if (iter->count < e->count)
e = iter;
}

// and replace it with new ip/mac
copyIp(e->ip, ip);
e->count = 1;
}
else
incArpEntry(*e);

copyMac(e->mac, mac);
// print_store();
}

void EtherCard::arpStoreInvalidIp(const uint8_t *ip)
{
ArpEntry *e = findArpStoreEntry(ip);
if (e)
memset(e, 0, sizeof(ArpEntry));
}
176 changes: 140 additions & 36 deletions src/net.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,55 @@
#ifndef NET_H
#define NET_H

// macro to swap bytes from 2 bytes value
#define BSWAP_16(x) \
( \
(uint16_t) \
( \
((x & 0xFF) << 8) \
| ((x >> 8) & 0xFF) \
) \
)

// macro to swap bytes from 4 bytes value
#define BSWAP_32(x) \
( \
(uint32_t) \
( \
((x & 0xFF) << 24) \
| ((x & 0xFF00) << 8) \
| ((x & 0xFF0000) >> 8) \
| ((x & 0xFF000000) >> 24) \
) \
)

#ifndef __BYTE_ORDER__
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define HTONS(x) BSWAP_16(x)
#define HTONL(x) BSWAP_32(x)
#define NTOHS(x) BSWAP_16(x)
#define NTOHL(x) BSWAP_32(x)
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define HTONS(x) x
#define HTONL(x) x
#define NTOHS(x) x
#define NTOHL(x) x
#else
# error __BYTE_ORDER__ not defined! PLease define it for your platform
#endif

inline uint16_t htons(const uint16_t v)
{ return HTONS(v); }

inline uint32_t htonl(const uint32_t v)
{ return HTONL(v); }

inline uint16_t ntohs(const uint16_t v)
{ return NTOHS(v); }

inline uint32_t ntohl(const uint32_t v)
{ return NTOHL(v); }

// ******* SERVICE PORTS *******
#define HTTP_PORT 80
#define DNS_PORT 53
Expand All @@ -22,10 +71,8 @@
#define ETH_HEADER_LEN 14
#define ETH_LEN 6
// values of certain bytes:
#define ETHTYPE_ARP_H_V 0x08
#define ETHTYPE_ARP_L_V 0x06
#define ETHTYPE_IP_H_V 0x08
#define ETHTYPE_IP_L_V 0x00
#define ETHTYPE_ARP_V HTONS(0x0806)
#define ETHTYPE_IP_V HTONS(0x0800)
// byte positions in the ethernet frame:
//
// Ethernet type field (2bytes):
Expand All @@ -36,46 +83,103 @@
#define ETH_SRC_MAC 6


// ******* ARP *******
#define ETH_ARP_OPCODE_REPLY_H_V 0x0
#define ETH_ARP_OPCODE_REPLY_L_V 0x02
#define ETH_ARP_OPCODE_REQ_H_V 0x0
#define ETH_ARP_OPCODE_REQ_L_V 0x01
// start of arp header:
#define ETH_ARP_P 0xe
//
#define ETHTYPE_ARP_L_V 0x06
// arp.dst.ip
#define ETH_ARP_DST_IP_P 0x26
// arp.opcode
#define ETH_ARP_OPCODE_H_P 0x14
#define ETH_ARP_OPCODE_L_P 0x15
// arp.src.mac
#define ETH_ARP_SRC_MAC_P 0x16
#define ETH_ARP_SRC_IP_P 0x1c
#define ETH_ARP_DST_MAC_P 0x20
#define ETH_ARP_DST_IP_P 0x26
// Ethernet II header
struct EthHeader
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This struct should also be __attribute__((__packed__)), right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is EtherCard support something else than 8 bits controllers? If yes then we need this attribute

Copy link
Contributor

@nuno-silva nuno-silva Feb 7, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, but even if that's not the case, there's no harm in adding it for future proof :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am aiming to add support for a wider range of devices, including the 32-bit ones, such as the Arduino M0.

The biggest blocker is the SPI interface - I have a half-complete branch using the Arduino SPI library - see #335.

{
uint8_t thaddr[ETH_LEN]; // target MAC address
uint8_t shaddr[ETH_LEN]; // source MAC address
uint16_t etype; // Ethertype
};


// ******* IP *******
#define IP_HEADER_LEN 20
#define IP_LEN 4
// ip.src
#define IP_SRC_P 0x1a
#define IP_DST_P 0x1e
#define IP_HEADER_LEN_VER_P 0xe
#define IP_CHECKSUM_P 0x18
#define IP_TTL_P 0x16
#define IP_FLAGS_P 0x14
#define IP_P 0xe
#define IP_TOTLEN_H_P 0x10
#define IP_TOTLEN_L_P 0x11

#define IP_PROTO_P 0x17
#define IP_V4 0x4
#define IP_IHL 0x5

enum IpFlags
{
IP_DF = 1 << 1,
IP_MF = 1 << 0,
};

#define IP_PROTO_ICMP_V 1
#define IP_PROTO_TCP_V 6
// 17=0x11
#define IP_PROTO_UDP_V 17

struct IpHeader
{
uint8_t versionIhl;
uint8_t dscpEcn;
uint16_t totalLen;
uint16_t identification;
uint16_t flagsFragmentOffset;
uint8_t ttl;
uint8_t protocol;
uint16_t hchecksum;
uint8_t spaddr[IP_LEN];
uint8_t tpaddr[IP_LEN];

static uint8_t version_mask() { return 0xF0; }
uint8_t version() const { return (versionIhl & version_mask()) >> 4; }
void version(const uint8_t v)
{
versionIhl &= ~version_mask();
versionIhl |= (v << 4) & version_mask();
}

uint8_t ihl() const { return versionIhl & 0xF; }
void ihl(const uint8_t i)
{
versionIhl &= version_mask();
versionIhl |= i & ~version_mask();
}

static uint16_t flags_mask() { return HTONS(0xE000); }

void flags(const uint16_t f)
{
flagsFragmentOffset &= ~flags_mask();
flagsFragmentOffset |= HTONS(f << 13) & flags_mask();
}
void fragmentOffset(const uint16_t o)
{
flagsFragmentOffset &= flags_mask();
flagsFragmentOffset |= HTONS(o) & ~flags_mask();
}

} __attribute__((__packed__));


// ******* ARP *******
// ArpHeader.htypeH/L
#define ETH_ARP_HTYPE_ETHERNET HTONS(0x0001)

// ArpHeader.ptypeH/L
#define ETH_ARP_PTYPE_IPV4 HTONS(0x0800)

// ArpHeader.opcodeH/L
#define ETH_ARP_OPCODE_REPLY HTONS(0x0002)
#define ETH_ARP_OPCODE_REQ HTONS(0x0001)

struct ArpHeader
{
uint16_t htype; // hardware type
uint16_t ptype; // protocol type
uint8_t hlen; // hardware address length
uint8_t plen; // protocol address length
uint16_t opcode; // operation

// only htype "ethernet" and ptype "IPv4" is supported for the moment,
// so hardcode addresses' lengths
uint8_t shaddr[ETH_LEN];
uint8_t spaddr[IP_LEN];
uint8_t thaddr[ETH_LEN];
uint8_t tpaddr[IP_LEN];
};


// ******* ICMP *******
#define ICMP_TYPE_ECHOREPLY_V 0
#define ICMP_TYPE_ECHOREQUEST_V 8
Expand Down
Loading