EMANE  1.0.1
ethernettransport.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013,2016 - Adjacent Link LLC, Bridgewater, New Jersey
3  * Copyright (c) 2009-2012 - DRS CenGen, LLC, Columbia, Maryland
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * * Neither the name of DRS CenGen, LLC nor the names of its
17  * contributors may be used to endorse or promote products derived
18  * from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "ethernettransport.h"
35 #include "emane/componenttypes.h"
36 
37 
39  PlatformServiceProvider *pPlatformService):
40  Transport(id, pPlatformService),
41  bBroadcastMode_(false),
42  bArpCacheMode_(true)
43 { }
44 
45 
47 { }
48 
49 
51 {
52  // check min header len
53  if(len < Utils::ETH_HEADER_LEN)
54  {
57  "TRANSPORTI %03d EthernetTransport::%s len %zd < min eth header len %d",
58  id_,
59  __func__,
60  len,
62 
63  // error
64  return -1;
65  }
66  else
67  {
68  // eth header
69  const Utils::EtherHeader *pEthHeader = (Utils::EtherHeader *) buf;
70 
71  // eth protocol
72  const std::uint16_t u16ethProtocol = Utils::get_protocol(pEthHeader);
73 
74  // reduce length by eth hdr len
75  len -= Utils::ETH_HEADER_LEN;
76 
77  switch(u16ethProtocol)
78  {
79  // eth ipv4
80  case Utils::ETH_P_IPV4:
81  {
82  // check min len
83  if(len < Utils::IPV4_HEADER_LEN)
84  {
87  "TRANSPORTI %03d EthernetTransport::%s ipv4, len %zu < min len %d",
88  id_,
89  __func__,
90  len,
92 
93  // error
94  return -1;
95  }
96  else
97  {
98  // success
99  return 0;
100  }
101  }
102 
103  // eth ipv6
104  case Utils::ETH_P_IPV6:
105  {
106  // check min len
107  if(len < Utils::IPV6_HEADER_LEN)
108  {
110  ERROR_LEVEL,
111  "TRANSPORTI %03d EthernetTransport::%s ipv6, len %zu < min len %d",
112  id_,
113  __func__,
114  len,
116 
117  // error
118  return -1;
119  }
120  else
121  {
122  // success
123  return 0;
124  }
125  }
126 
127  // eth arp
128  case Utils::ETH_P_ARP:
129  {
130  // check min len
131  if(len < Utils::ETHARP_HEADER_LEN)
132  {
134  ERROR_LEVEL, "TRANSPORTI %03d EthernetTransport::%s arp, len %zu < len %d",
135  id_,
136  __func__,
137  len,
139 
140  // error
141  return -1;
142  }
143  else
144  {
145  // success
146  return 0;
147  }
148  }
149 
150  // unknown protocol
151  default:
153  DEBUG_LEVEL, "TRANSPORTI %03d EthernetTransport::%s allow unknown protocol %02X",
154  id_,
155  __func__,
156  u16ethProtocol);
157 
158  // but not an error
159  return 1;
160  }
161  }
162 }
163 
164 
165 
167  NEMId & rNemDestination,
168  std::uint8_t & rDspc)
169 {
170  // eth protocol
171  const std::uint16_t u16ethProtocol = Utils::get_protocol(pEthHeader);
172 
173  switch(u16ethProtocol)
174  {
175  // eth ipv4
176  case Utils::ETH_P_IPV4:
177  {
178  // ipv4 header
179  const Utils::Ip4Header *pIpHeader = (Utils::Ip4Header*) ((Utils::EtherHeader*) pEthHeader + 1);
180 
181  // broadcast always mode
182  if(bBroadcastMode_)
183  {
184  rNemDestination = NEM_BROADCAST_MAC_ADDRESS;
185  }
186  // check arp cache
187  else if (bArpCacheMode_)
188  {
189  rNemDestination = lookupArpCache(&pEthHeader->dst);
190  }
191  // use ether dst
192  else
193  {
194  rNemDestination = Utils::ethaddr4_to_id(&pEthHeader->dst);
195  }
196 
197  // set the dscp based on ip header
198  rDspc = Utils::get_dscp(pIpHeader);
199 
200  // success
201  return 0;
202  }
203 
204  // eth ipv6
205  case Utils::ETH_P_IPV6:
206  {
207  // ipv6 header
208  const Utils::Ip6Header *pIpHeader = (Utils::Ip6Header*) ((Utils::EtherHeader*) pEthHeader + 1);
209 
210  // broadcast always mode
211  if(bBroadcastMode_)
212  {
213  rNemDestination = NEM_BROADCAST_MAC_ADDRESS;
214  }
215  // check arp cache
216  else if (bArpCacheMode_)
217  {
218  rNemDestination = lookupArpCache(&pEthHeader->dst);
219  }
220  // use ether dst
221  else
222  {
223  rNemDestination = Utils::ethaddr6_to_id(&pEthHeader->dst);
224  }
225 
226  // set the dscp based on ip header
227  rDspc = Utils::get_dscp(pIpHeader);
228 
229  // success
230  return 0;
231  }
232 
233  // eth arp
234  case Utils::ETH_P_ARP:
235  {
236  // broadcast always mode
237  if(bBroadcastMode_)
238  {
239  rNemDestination = NEM_BROADCAST_MAC_ADDRESS;
240  }
241  // check arp cache
242  else if (bArpCacheMode_)
243  {
244  rNemDestination = lookupArpCache(&pEthHeader->dst);
245  }
246  // use ether dst
247  else
248  {
249  rNemDestination = Utils::ethaddr4_to_id(&pEthHeader->dst);
250  }
251 
252  // set dscp to 0 for all arp types
253  rDspc = 0;
254 
255  // success
256  return 0;
257  }
258 
259  // unknown protocol
260  default:
262  DEBUG_LEVEL,
263  "TRANSPORTI %03d EthernetTransport::%s allow unknown protocol %02X",
264  id_,
265  __func__,
266  u16ethProtocol);
267 
268  // broadcast always mode
269  if(bBroadcastMode_)
270  {
271  rNemDestination = NEM_BROADCAST_MAC_ADDRESS;
272  }
273  // check arp cache
274  else if (bArpCacheMode_)
275  {
276  rNemDestination = lookupArpCache(&pEthHeader->dst);
277  }
278  // use the last 2 bytes of the ethernet destination
279  else
280  {
281  rNemDestination = ntohs(pEthHeader->dst.words.word3);
282  }
283 
284  // set dscp to 0
285  rDspc = 0;
286 
287  // but not an error
288  return 1;
289  }
290 }
291 
292 
293 
295 {
296  // not needed in broadcast mode
297  if(bBroadcastMode_)
298  {
299  return;
300  }
301  // not needed if arp cache disabled
302  else if (! bArpCacheMode_)
303  {
304  return;
305  }
306  else
307  {
308 
309  // eth protocol
310  const std::uint16_t u16ethProtocol = Utils::get_protocol(pEthHeader);
311 
312  switch(u16ethProtocol)
313  {
314  // eth arp
315  case Utils::ETH_P_ARP:
316  {
317  const Utils::EtherArpHeader *pEtherArpHeader = (Utils::EtherArpHeader*) ((Utils::EtherHeader*) pEthHeader + 1);
318 
319  const std::uint16_t u16code = Utils::get_code(pEtherArpHeader);
320 
321  // arp type reply or request
322  if((u16code == Utils::ETH_ARPOP_REPLY) || (u16code == Utils::ETH_ARPOP_REQUEST))
323  {
324  addEntry(*Utils::get_srchwaddr(pEtherArpHeader), nemId);
325  }
326  }
327  break;
328 
329  case Utils::ETH_P_IPV6:
330  {
331  const Utils::Ip6Header *pIp6Header = (Utils::Ip6Header*) ((Utils::EtherHeader*) pEthHeader + 1);
332 
333  // check for icmpv6
334  if (pIp6Header->u8Ipv6next == Utils::IPV6_P_ICMP)
335  {
336  const Utils::IP6ICMPHeader *pICMP6Header = (Utils::IP6ICMPHeader*) ((Utils::Ip6Header*) pIp6Header + 1);
337 
338  const std::uint8_t icmpv6Type = pICMP6Header->u8Type;
339 
340  // icmpv6 neighbor solicitation or advertisement
341  if ((icmpv6Type == Utils::IP6_ICMP_NEIGH_SOLICIT) || (icmpv6Type == Utils::IP6_ICMP_NEIGH_ADVERT))
342  {
343  addEntry(pEthHeader->src, nemId);
344  }
345  }
346  }
347  break;
348  }
349  }
350 }
351 
353 {
354  // lock mutex
355  std::lock_guard<std::mutex> m(mutex_);
356 
357  const auto iter = macCache_.find(addr);
358 
359  // new entry
360  if(iter == macCache_.end())
361  {
362  macCache_.insert(std::make_pair(addr, nemId));
363 
365  DEBUG_LEVEL,
366  "TRANSPORTI %03d ARPCache::%s added cache entry %s to nem %hu",
367  id_,
368  __func__,
369  ethaddr_to_string(&addr).c_str(), nemId);
370  }
371  else
372  {
373  // entry found but different nem
374  if(iter->second != nemId)
375  {
377  DEBUG_LEVEL,
378  "TRANSPORTI %03d ARPCache::%s updated cache entry %s from nem %hu to nem %hu",
379  id_,
380  __func__,
381  ethaddr_to_string(&addr).c_str(),
382  iter->second, nemId);
383  // updated nem id
384  iter->second = nemId;
385  }
386  }
387 }
388 
389 
391 {
392  // lock mutex
393  std::lock_guard<std::mutex> m(mutex_);
394 
395  const auto iter = macCache_.find(*pEtherAddr);
396 
397  // entry not found, most likely broadcast
398  if(iter == macCache_.end())
399  {
401  DEBUG_LEVEL,
402  "TRANSPORTI %03d EthernetTransport::%s no nem found for %s, using broadcast mac address",
403  id_,
404  __func__,
405  Utils::ethaddr_to_string(pEtherAddr).c_str());
406 
408  }
409  else
410  {
412  DEBUG_LEVEL,
413  "TRANSPORTI %03d EthernetTransport::%s nem %hu found for %s, using %hu",
414  id_,
415  __func__,
416  iter->second,
417  Utils::ethaddr_to_string(pEtherAddr).c_str(),
418  iter->second);
419 
420  return iter->second;
421  }
422 }
const std::uint16_t ETH_P_ARP
Ethernet arp protocol.
Definition: netutils.h:382
const std::uint16_t ETH_P_IPV6
Ethernet ipv6 protocol.
Definition: netutils.h:389
union EtherAddr src
Definition: netutils.h:436
Definition of the IPv4 header.
Definition: netutils.h:139
struct EtherAddrWords words
Definition: netutils.h:424
Base class for all transports.
Definition: transport.h:49
#define LOGGER_VERBOSE_LOGGING(logger, level, fmt, args...)
std::uint16_t get_code(const EtherArpHeader *arp)
Definition: netutils.h:602
constexpr NEMId NEM_BROADCAST_MAC_ADDRESS
Definition: types.h:69
std::uint16_t get_protocol(const EtherHeader *eth)
Definition: netutils.h:475
virtual int parseFrame(const Utils::EtherHeader *pEthHeader, EMANE::NEMId &dst, std::uint8_t &dscp)
Definition of the IPv6 ICMP header.
Definition: netutils.h:819
std::uint16_t u16code
Definition: netutils.h:513
The PlatformServiceProvider interface provides access to emulator services.
const std::uint16_t ETHARP_HEADER_LEN
Ethernet Arp header length.
Definition: netutils.h:351
Definition of the IPv6 header.
Definition: netutils.h:273
std::uint16_t ethaddr4_to_id(const EtherAddr *addr)
Definition: netutils.h:688
std::uint16_t NEMId
Definition: types.h:52
Definition of the ethernet arp header.
Definition: netutils.h:526
const std::uint16_t ETH_ARPOP_REPLY
Ethernet arp reply.
Definition: netutils.h:676
Definition of the ethernet frame address as an array of 6 bytes or set of 3 words.
Definition: netutils.h:422
const EtherAddr * get_srchwaddr(const EtherArpHeader *arp)
Definition: netutils.h:616
PlatformServiceProvider * pPlatformService_
const std::uint8_t IP6_ICMP_NEIGH_ADVERT
IPv6 ICMP Neighbor Advertisement.
Definition: netutils.h:839
std::uint8_t u8Ipv6next
Definition: netutils.h:282
EMANE::NEMId lookupArpCache(const Utils::EtherAddr *pEthAddr)
const std::uint16_t IPV4_HEADER_LEN
ipv4 header len without options
Definition: netutils.h:158
void addEntry(const Utils::EtherAddr &addr, EMANE::NEMId nemId)
std::uint16_t ethaddr6_to_id(const EtherAddr *addr)
Definition: netutils.h:722
const std::uint16_t ETH_ARPOP_REQUEST
Ethernet arp request.
Definition: netutils.h:668
virtual LogServiceProvider & logService()=0
virtual int verifyFrame(const void *buf, size_t len)
std::string ethaddr_to_string(const EtherAddr *addr)
Definition: netutils.h:508
const std::uint8_t IPV6_P_ICMP
IPv6 ICMP Protocol.
Definition: netutils.h:181
std::uint8_t get_dscp(const Ip4Header *ip)
Definition: netutils.h:233
union EtherAddr dst
Definition: netutils.h:435
EthernetTransport(EMANE::NEMId id, EMANE::PlatformServiceProvider *pPlatformService)
const std::uint16_t ETH_HEADER_LEN
Ethernet header length.
Definition: netutils.h:343
#define LOGGER_STANDARD_LOGGING(logger, level, fmt, args...)
Definition of the ethernet frame header.
Definition: netutils.h:434
void updateArpCache(const Utils::EtherHeader *pEthHeader, EMANE::NEMId nemId)
const std::uint8_t IP6_ICMP_NEIGH_SOLICIT
IPv6 ICMP Neighbor Soliciation.
Definition: netutils.h:832
const std::uint16_t ETH_P_IPV4
Ethernet ipv4 protocol.
Definition: netutils.h:374
const std::uint16_t IPV6_HEADER_LEN
ipv6 header len
Definition: netutils.h:293