Today I’m posting the MAC layer. The stack is written like, well a stack. This layer (MAC) sits on top of the ENC layer that controls the ethernet controller. Above the MAC layer sits the IP layer which I’ll post next.
Previously in the Embedded Ethernet Series…
Part 1
Part 2
MAC.h
// MAC.h
#ifndef _H_MAC
#define _H_MAC
#include <p32xxxx.h>
#include "../globals.h"
#include "../static.h"
#include "../GenericTypeDefs.h"
#include "../controlboard.h"
#include "../ENCDefs.h"
typedef union _ET
{
WORD w;
BYTE v[2];
} ET;
typedef struct _MAC_HEADER
{
BYTE D_MAC[6];
BYTE S_MAC[6];
ET EtherType;
WORD PayLen;
} MAC_HEADER;
#include "IPSuite.h"
void MAC_FormHeader(MAC_HEADER*, BYTE*, WORD);
void MAC_TxHeader(MAC_HEADER*);
void MAC_TxArray(unsigned char*, unsigned int);
void MAC_Flush(void);
void MAC_TxPredefined(void);
void MAC_ParseBuffer(void);
void MAC_PrintHeader(MAC_HEADER *);
void MAC_Encapsulate(unsigned char *, unsigned short, unsigned char *, unsigned int);
#endif
MAC.c
// MAC.c
#include "MAC.h"
// from control.c
extern unsigned char HW_ADDRESS[6];
extern unsigned char HW_BROADCAST[6];
//from ENC28J60.c
extern unsigned char rx_buffer[4][2048];
extern unsigned char rx_buffer_rd;
//! Forms a MAC_HEADER (initializes)
/*!
\param hdr Pointer to MAC_HEADER
\param dmac Destination MAC Address (6 byte array)
\param ET EtherType
*/
void MAC_FormHeader(MAC_HEADER* hdr, BYTE* dmac, WORD ET)
{
unsigned char i;
// Copy Destination MAC
for(i=0; i<6; i++){ hdr->D_MAC[i] = dmac[i]; }
// Copy Source MAC (use own)
for(i=0; i<6; i++){ hdr->S_MAC[i] = HW_ADDRESS[i]; }
// Copy EtherType
hdr->EtherType.w = ET;
}
//! Transmits a MAC_HEADER
/*!
All data must be in the MAC_HEADER, this just transmits what is there.
\param hdr MAC_HEADER to transmit
*/
void MAC_TxHeader(MAC_HEADER* hdr)
{
unsigned char i;
// Reset ENC
ENC_TxPrepare();
// Destination MAC
for(i=0; i<6; i++){ ENC_WriteBufferMemory(hdr->D_MAC[i]); }
// Source MAC
for(i=0; i<6; i++){ ENC_WriteBufferMemory(hdr->S_MAC[i]); }
// Ethertype
ENC_WriteBufferMemory(hdr->EtherType.v[1]);
ENC_WriteBufferMemory(hdr->EtherType.v[0]);
}
//! Transmits an array of bytes to the PHY’s TxBuffer (ENC Controller)
/*!
A MAC_HEADER must be transmitted first via the MAC_TxHeader() call.
\param a Array
\param len Length of Array
\sa MAC_TxHeader()
*/
void MAC_TxArray(unsigned char* a, unsigned int len)
{
unsigned int i;
for(i=0; i<len; i++)
{
ENC_WriteBufferMemory(a[i]);
}
}
//! Initiates the PHY to send
/*!
\param a Array
\param len Length of Array
*/
void MAC_Flush(void)
{
ENC_TxSend();
}
//! Creates and sends a predefined packet
void MAC_TxPredefined(void)
{
unsigned char PredefinedPacket[2] = {0×57, 0×57};
MAC_HEADER MAC_Head;
MAC_FormHeader(&MAC_Head, HW_BROADCAST, sizeof(PredefinedPacket));
MAC_TxHeader(&MAC_Head);
// Payload
MAC_TxArray(PredefinedPacket, 2);
MAC_Flush();
}
//! Parses an array into a MAC_PACKET (Header and Payload)
/*!
Called when a buffer has been passed up from the PHY (ENC Controller), parse it
*/
void MAC_ParseBuffer(void)
{
unsigned int i, ptr;
unsigned char lo = 2; // Length offset
#ifdef DEBUG_RXRING
printf("Handling Buffer %d\r\n", rx_buffer_rd);
#endif
unsigned int len = form16(rx_buffer[rx_buffer_rd][0], rx_buffer[rx_buffer_rd][1]);
//printf("[[%04x]]\r\n", len);
RXSTATUS RX_Status;
MAC_HEADER MAC_H;
ptr = lo;
for(i=0; i<4; i++){
RX_Status.v[i] = rx_buffer[rx_buffer_rd][ptr];
ptr++;
}
for(i=0; i<6; i++){
MAC_H.D_MAC[i] = rx_buffer[rx_buffer_rd][ptr];
ptr++;
}
for(i=0; i<6; i++){
MAC_H.S_MAC[i] = rx_buffer[rx_buffer_rd][ptr];
ptr++;
}
for(i=0; i<2; i++){
MAC_H.EtherType.v[i] = rx_buffer[rx_buffer_rd][ptr];
ptr++;
}
MAC_H.EtherType.w = swaps(MAC_H.EtherType.w);
// Take out the Check Sequence (4 bytes)
MAC_H.PayLen = (len-ptr)-4;
#if DL_MAC == 6
MAC_PrintHeader(&MAC_H);
#endif
#if DL_MAC == 8
print_array(rx_buffer[rx_buffer_rd], lo, lo+len, 16);
#endif
//if(array_compare(MAC_H.D_MAC, HW_ADDRESS, 6))
if((array_compare(MAC_H.D_MAC, HW_ADDRESS, 6)) || (array_compare(MAC_H.D_MAC, HW_BROADCAST, 6)))
{
if(array_compare(MAC_H.D_MAC, HW_ADDRESS, 6))
{
#if DL_MAC == 4
MAC_PrintHeader(&MAC_H);
print_array(rx_buffer[rx_buffer_rd], lo, lo+len, 16);
#endif
}
switch(MAC_H.EtherType.w)
{
case MAC_ET_IP:
#ifdef DEBUG_MAC_PrintType
printf("IP Packet.\r\n");
#endif
IP_ParsePayload(&MAC_H, (unsigned char*)((rx_buffer[rx_buffer_rd])+ptr), MAC_H.PayLen);
break;
case MAC_ET_ARP:
#ifdef DEBUG_MAC_PrintType
printf("ARP Packet.\r\n");
#endif
ARP_ParsePayload(&MAC_H, (unsigned char*)((rx_buffer[rx_buffer_rd])+ptr), MAC_H.PayLen);
break;
case MAC_ET_VLAN:
#ifdef DEBUG_MAC_PrintType
printf("VLAN-Tagged Frame (Network Bridge).\r\n");
#endif
break;
case MAC_ET_IPv6:
#ifdef DEBUG_MAC_PrintType
printf("IPv6 Packet.\r\n");
#endif
break;
case MAC_ET_VOIP:
#ifdef DEBUG_MAC_PrintType
printf("LLDP VOIP Discovery Packet.\r\n");
#endif
break;
default:
#ifdef DEBUG_MAC_PrintType
printf("Unknown Packet Type (%04x).\r\n", MAC_H.EtherType.w);
#endif
break;
}
}
rx_buffer_rd++;
if(rx_buffer_rd >= 4){ rx_buffer_rd = 0; }
}
//! Prints a MAC_HEADER
/*!
\param h MAC_HEADER to be printed
*/
void MAC_PrintHeader(MAC_HEADER *h)
{
unsigned int i;
printf("Print MAC Packet\r\n");
printf(" Destination MAC:………"); printsep(h->D_MAC, 6, ‘x’, ‘-’); printf("\r\n");
printf(" Source MAC:………….."); printsep(h->S_MAC, 6, ‘x’, ‘-’); printf("\r\n");
printf(" EtherType:……………%04x\r\n", h->EtherType.w);
printf(" Payload Length:……….%04x\r\n", h->PayLen);
printf("\r\n");
}
void MAC_Encapsulate(unsigned char *DestIP, unsigned short ET, unsigned char *data, unsigned int datalen)
{
unsigned int row;
unsigned char THA[6];
// Determine MAC
if(ARP_Find(DestIP))
{
// If I got here, there is a ARP entry
row = ARP_Table_Locate(DestIP);
ARP_Fetch(row, THA);
// Create MAC Header
MAC_HEADER h_m;
MAC_FormHeader(&h_m, THA, ET);
h_m.PayLen = datalen + 6 + 6 + 2;
// Print MAC Header
#ifdef DOUT_MAC
printf("Outgoing Header:\r\n");
MAC_PrintHeader(&h_m);
#endif
// Transmit MAC Header
MAC_TxHeader(&h_m);
// Transmit MAC Payload (IP / ARP Packet)
MAC_TxArray(data, datalen);
// Initiate Transmission
MAC_Flush();
}
else
{
printf("MAC: Attempted to Encapsulate a Packet with no ARP Entry. \r\n");
}
}
RSS Feed
THANKS FOR THE GREAT BLOG, LOOKING FORWARD TO SEE IP LAYER CODE.