embkernel
 All Classes Functions Variables Typedefs Groups Pages
NetArp.cpp
1 //------------------------------------------------------------------------------
2 //This file is part of embKernel.
3 //See license.txt for the full license governing this code.
4 //------------------------------------------------------------------------------
5 
6 #include "NetArp.hpp"
7 #include "LibEndian.hpp"
8 #include "Net.hpp"
9 
10 NetArp::SLOT NetArp::sSlots[NET_CFG_MAX_ARP_ENTRIES];
11 
12 void NetArp::processFrame(NetDefs::FRAME& frame, NetDefs::ARP_HEADER& header) {
13  swapHeader(header);
14 
15  switch (header.operation) {
16  case NetDefs::ARP_OPERATION_REQ:
17  if (header.dstIpAddr == Net::sConfig.ipAddr) {
18  send(frame, header.srcMacAddr, header.srcIpAddr, NetDefs::ARP_OPERATION_RESP);
19  }
20  else {
21  Net::freeFrame(frame);
22  }
23  break;
24  case NetDefs::ARP_OPERATION_RESP: {
25  SLOT* slot = getWaitingSlot(header.srcIpAddr);
26  if (slot) {
27  slot->macAddr = header.srcMacAddr;
28  slot->status = SLOT_RESOLVED;
29  slot->task->resume();
30  }
31  Net::freeFrame(frame);
32  break;
33  }
34  default:
35  Net::freeFrame(frame);
36  break;
37  }
38 
39 }
40 
41 bool NetArp::resolve(NetDefs::IP_ADDR ipAddr, NetDefs::MAC_ADDR& macAddr) {
42  //If broadcast return broadcast MAC
43 
44  if (ipAddr == NetDefs::IP_BROADCAST) {
45  macAddr = NetDefs::MAC_BROADCAST;
46  return true;
47  }
48 
49  if ((Net::getConfig().ipAddr.val ^ ipAddr.val) & Net::getConfig().mask.val) {
50  ipAddr = Net::getConfig().gatewayIpAddr;
51  }
52 
53  if (checkCache(ipAddr, macAddr)) {
54  return true;
55  }
56 
57  SLOT* slot = getFreeSlot();
58 
59  if (!slot) {
60  return false;
61  }
62 
63  NetDefs::FRAME* frame = Net::allocFrame(sizeof(NetDefs::MAC_HEADER) + sizeof(NetDefs::ARP_HEADER));
64  if (!frame) {
65  slot->status = SLOT_EMPTY;
66  return false;
67  }
68 
69  slot->ipAddr = ipAddr;
70  slot->timer = TIMEOUT_SLOT_RESOLVING;
71  slot->status = SLOT_RESOLVING;
72  slot->task = Rtos::getCurrentTask();
73 
74  //Send the request
75  send(*frame, NetDefs::MAC_BROADCAST, ipAddr, NetDefs::ARP_OPERATION_REQ);
76 
77  while (true) {
78  slot->task->suspend();
79  if (slot->status != SLOT_RESOLVING) {
80  if (slot->status == SLOT_RESOLVED) {
81  macAddr = slot->macAddr;
82  slot->timer = TIMEOUT_SLOT_VALID;
83  slot->status = SLOT_VALID;
84  return true;
85  }
86  break;
87  }
88  }
89 
90  slot->status = SLOT_EMPTY;
91 
92  return false;
93 }
94 
95 NetArp::SLOT* NetArp::getFreeSlot() {
96  uint16_t smalestTimer = 0xFFFF;
97  int oldest = -1;
99  for (int i = 0; i < NET_CFG_MAX_ARP_ENTRIES; i++) {
100 
101  if (sSlots[i].status == SLOT_EMPTY) {
102  sSlots[i].status = SLOT_RESERVED;
104  return &sSlots[i];
105  }
106  if (sSlots[i].status == SLOT_VALID) {
107  if (sSlots[i].timer < smalestTimer) {
108  oldest = i;
109  }
110  }
111  }
112  if (oldest >= 0) {
113  sSlots[oldest].status = SLOT_RESERVED;
115  return &sSlots[oldest];
116  }
118  return 0;
119 }
120 
121 NetArp::SLOT* NetArp::getWaitingSlot(const NetDefs::IP_ADDR ipAddr) {
122  for (int i = 0; i < NET_CFG_MAX_ARP_ENTRIES; i++) {
123  if ((sSlots[i].status == SLOT_RESOLVING) && (sSlots[i].ipAddr == ipAddr)) {
124  return &sSlots[i];
125  }
126  }
127  return 0;
128 }
129 
130 bool NetArp::checkCache(const NetDefs::IP_ADDR& ipAddr, NetDefs::MAC_ADDR& macAddr) {
131  for (int i = 0; i < NET_CFG_MAX_ARP_ENTRIES; i++) {
133  if ((sSlots[i].status == SLOT_VALID) && (sSlots[i].ipAddr == ipAddr)) {
134  macAddr = sSlots[i].macAddr;
136  return true;
137  }
139  }
140  return false;
141 }
142 
143 //Every 100ms
144 void NetArp::tick() {
145  for (int i = 0; i < NET_CFG_MAX_ARP_ENTRIES; i++) {
146  if (--sSlots[i].timer == 0) {
148  if ((sSlots[i].status == SLOT_VALID)) {
149  sSlots[i].status = SLOT_EMPTY;
150  }
152 
153  if ((sSlots[i].status == SLOT_RESOLVING)) {
154  sSlots[i].status = SLOT_TIMEOUT;
155  sSlots[i].task->resume();
156  }
157  }
158  }
159 }
160 
161 void NetArp::send(NetDefs::FRAME& frame, const NetDefs::MAC_ADDR& macDst, const NetDefs::IP_ADDR& ipDst, const NetDefs::ARP_OPERATION op) {
162  frame.types.arp.arpHeader.hardwareType = NetDefs::ARP_HW_TYPE_ETHERNET;
163  frame.types.arp.arpHeader.protocol = NetDefs::ARP_PROTOCOL_IP;
164  frame.types.arp.arpHeader.macAddrLen = sizeof(NetDefs::MAC_ADDR);
165  frame.types.arp.arpHeader.protocolLen = sizeof(NetDefs::IP_ADDR);
166 
167  frame.types.arp.arpHeader.operation = op;
168 
169  if (op == NetDefs::ARP_OPERATION_RESP) {
170  frame.types.arp.arpHeader.dstMacAddr = macDst;
171  }
172  else {
173  frame.types.arp.arpHeader.dstMacAddr = NetDefs::MAC_BROADCAST;
174  }
175 
176  frame.types.arp.arpHeader.srcIpAddr = Net::sConfig.ipAddr;
177  frame.types.arp.arpHeader.srcMacAddr = Net::sMacAddr;
178  frame.types.arp.arpHeader.dstIpAddr = ipDst;
179 
180  swapHeader(frame.types.arp.arpHeader);
181 
182  Net::putHeader(frame, frame.types.arp.arpHeader.dstMacAddr, NetDefs::MAC_TYPE_ARP);
183  Net::flush(frame, sizeof(NetDefs::MAC_HEADER) + sizeof(NetDefs::ARP_HEADER), true);
184 }
185 
186 void NetArp::swapHeader(NetDefs::ARP_HEADER& header) {
187  header.hardwareType = (NetDefs::ARP_HW_TYPE) LibEndian::hwToBe((uint16_t) header.hardwareType);
188  header.protocol = (NetDefs::ARP_PROTOCOL) LibEndian::hwToBe((uint16_t) header.protocol);
189  header.operation = (NetDefs::ARP_OPERATION) LibEndian::hwToBe((uint16_t) header.operation);
190 }