In the receival state, the endPointer of the buffer refers to the first byte after the CRC of the ethernet frame [Stevens96] p.23. The CRC of the ethernet frame is not to be sent into the instance of the LLC class.
In the transmit state on the other hand, the endPointer of the buffer refers to the last byte in the packet, i.e. the CRC will be added after the present address the endPointer refers to. The CRC is added automatically and is not the responsibility of the Ethernet instance.
The pointer theFrame could also be called theParent. It is used by an upper layer in order to return a reply to a lower layer. In the lowest base layer theFrame should be set to zero since there is no underlying frame that may be referred to, it has no parent. For example, a new instance of an LLCInPacket has this as one of the inparameters to the constructor, where this refers to the instance of the EthernetInPacket
ethernet.cc:
void
EthernetInPacket::decode()
{
...
LLCInPacket* aPacket = new
LLCInPacket(/* Inparameters */);
aPacket->decode();
...
}
void
EthernetInPacket::answer(byte*
theData, udword theLength)
{
...
}
Somewhere in the instance of the LLCInPacket the method decode returns a reply to the instance of EthernetInPacket by calling myFrame->answer, where myFrame is a reference corresponding to the pointer this sent by the instance of EthernetInPacket. In this example, the upper layer is the instance of the LLCInPacket and the lower layer is the instance of the EthernetInPacket.
llc.cc:
void
LLCInPacket::decode()
{
...
myFrame->answer(/*
data */, /* data len */);
...
}
In principle, yes! The solution depends on some dangerous assumptions about the target system where the code will be executed. Thus, the code will be non-portable. This is not the appropriate way to use C++. The reason for the cast in this projects source code is for educational purposes. It becomes very clear what actually happens when different parts of the packet are handled.
Which are the dangerous assumptions? The first is related to the compiler aspects.
The second assumption is based on different data representations of integers.
The solution with a cast is used in the EthernetInPacket::decode
method in order to extract information from the ethernet frame
received. Translation between big and little endian is explained
by the example
uword myTypeLen = ((aHeader->typeLen & 0x00ff) << 8) |
((aHeader->typeLen & 0xff00) >> 8);
which should be a clarifying excersise for the interested student.
The reason to set R_REC_END to refer to the second last block is because ETRAX writes in the block after R_REC_END in certain situations [EtraxDesignRef] pp.41-46.
It should be used whenever an I/O unit, an I/O port, or any other similar address is referenced or declared.
Packets shorter than 64 byte (14 byte Ethernet header, 46 byte data, 4 byte checksum) cannot be transmitted on an Ethernet network. The reason is that a packet must extend over the entire physical network in order to provide a chance for other units to detect collisions.
What is meant by padding is that if one byte of data is to be transmitted, an additional 63 byte of data must be included in the packet. The easiest way to do this is to move the endPointer, which is the pointer to the end of the packet in the buffer, 63 byte. The additional data sent will be without significance for the information content of the packet.
All memory dynamically allocated with new should be returned to the system by delete as soon as possible, i.e. as soon as the allocated memory is no longer needed. For example,
void
llcInPacket::decode()
{
...
// It is an ARP packet of some kind - create an instance
ARPInPacket* anARPPacket = new ARPInPacket((myData +
llcHeaderLength),
(myLength -
llcHeaderLength),
this,
myFrameType);
anARPPacket->decode();
// It is no longer needed - delete it
delete anARPPacket;
...
}
instead of allocating memory on the heap, the stack could be used
void
llcInPacket::decode()
{
...
// It is an ARP packet of some kind - declare an instance
ARPInPacket anARPPacket(myData + llcHeaderLength,
myLength - llcHeaderLength,
this,
myFrameType);
anARPPacket.decode();
...
} // As this scope is left at the end of the method decode the
// destructor is executed automatically
All destructors should always be declared as virtual in order to avoid difficult debugging at a later stage in the development process. This is an excerpt from a set of coding rules. Most companies and organisations use similar rules.
Rule 4.5
All classes should define a virtual destructor, even if empty. If
a class, having virtual functions but without virtual
destructors, is used as a base class, there may be a surprise if
pointers to the class are used. If such a pointer is assigned to
an instance of a derived class and if delete is then used on this
pointer, only the base class' destructor will be invoked. If the
program depends on the derived class' destructor being invoked,
the program will fail.
The data returned by the instance of LLCInPacket has been dynamically allocated locally and must be returned to the system by a delete at some lower level as soon as it is not being used any more.
An incomplete Ethernet-frame is returned from LLCInPacket where the Ethernet-header is missing. Thus, an Ethernet-header must be added in front of the returned data by some means.