Format du paquet ARP Ethernet
Le protocole ARP (Address Resolution Protocol) permet de mapper une adresse IP vers une adresse MAC dans un réseau local. Le format d’un paquet ARP encapsulé dans une trame Ethernet suit la structure suivatne :
- Adresse MAC destination : 6 octets – généralement l’adresse physique du destinataire, ou l’adresse de diffusion
FF:FF:FF:FF:FF:FFsi inconnue. - Adresse MAC source : 6 octets – identifie l’émetteur.
- Type de trame : 2 octets – indique le protocole supérieur. Pour ARP, la valeur est
0x0806. - Type de matériel : 2 octets – pour Ethernet, fixé à
0x0001. - Type de protocole : 2 octets – spécifie le protocole réseau (ex. IPv4 =
0x0800). - Taille de l'adresse matérielle : 1 octet – vaut
6pour une adresse MAC. - Taille de l'adresse protocole : 1 octet – vaut
4pour IPv4. - Opération : 2 octets –
0x0001pour requête ARP,0x0002pour réponse. - Adresse MAC émetteur : 6 octets.
- Adresse IP émetteur : 4 octets.
- Adresse MAC cible : 6 octets – mise à zéro dans les requêtes.
- Adresse IP cible : 4 octets.
Gestion des opérations ARP sur microcontrôleur LPC1850
Le code ci-dessous illustre l’initialisation d’un périphérique basé sur le microcontrôleur NXP LPC1850 afin d’émettre des requêtes ARP et traiter les réponses reçues via l’interface EMAC (Ethernet MAC).
Fonction principale d'initialisation
#include "LPC18xx.h"
#include "led.h"
extern void taskEth(void);
int main(void)
{
SystemInit();
ledInit();
SysTick_Config(SystemCoreClock / 1000); // Intervalle d'interruption toutes les ms
taskEth();
while (1);
}
void SysTick_Handler(void)
{
static uint32_t tick = 0;
if (++tick >= 1000) {
tick = 0;
// Exemple : clignotement LED toutes les secondes
}
}
Tâche principale réseau
La fonction taskEth configure l’interface Ethernet, assigne une adresse MAC/IP locale, puis envoie une requête ARP au démarrage. Elle surveille ensuite les trames entrantes.
#include <stdlib.h>
#include "lpc18xx_emac.h"
#include "lpc18xx_debug.h"
extern void ipInit(uint8_t *mac, uint32_t ip);
extern uint32_t ipRcvMacFrame(uint8_t *buf, uint32_t len);
extern void arpSndRsp1(uint32_t dstIp, uint32_t srcIp, uint8_t *dstMac, uint8_t *srcMac);
static volatile uint8_t frameReady = 0;
static uint8_t rxBuffer[2048];
static uint8_t localMac[6] = {0x11, 0x1F, 0xE0, 0x12, 0x1E, 0x0F};
static uint8_t broadcastMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
void ethDataReadyCb(void)
{
frameReady = 1;
}
void taskEth(void)
{
debugComInit();
uartPrint("UART ready\r\n");
while (!ethInit(ethDataReadyCb, localMac));
uartPrint("EMAC initialized\r\n");
ipInit(localMac, 0xC0A801BE); // 192.168.1.190
arpSndRsp1(0xC0A80102, 0xC0A801BE, broadcastMac, localMac); // Requête vers 192.168.1.2
while (1) {
if (!frameReady) continue;
uint32_t length = ethRead(rxBuffer, sizeof(rxBuffer));
if (length > 0) {
ipRcvMacFrame(rxBuffer, length);
}
frameReady = 0;
}
}
Émission d'une requête ou réponse ARP
La fonction arpSndRsp1 construit manuellement une trame ARP selon les spécifications. Elle gère aussi bien les requêtes que les réponses.
static uint32_t txPacket[64];
void arpSndRsp1(uint32_t targetIp, uint32_t senderIp, uint8_t *dstMac, uint8_t *srcMac)
{
uint8_t *frame = (uint8_t*)txPacket;
memcpy(frame + 0, dstMac, 6); // Dest MAC
memcpy(frame + 6, srcMac, 6); // Source MAC
*(uint16_t*)(frame + 12) = htons(0x0806); // Type ARP
// Entête ARP
*(uint16_t*)(frame + 14) = htons(0x0001); // Ethernet
*(uint16_t*)(frame + 16) = htons(0x0800); // IPv4
frame[18] = 6; // Taille MAC
frame[19] = 4; // Taille IP
*(uint16_t*)(frame + 20) = htons(0x0001); // Requête ARP
memcpy(frame + 22, srcMac, 6); // Expéditeur MAC
*(uint32_t*)(frame + 28) = senderIp; // Expéditeur IP
memcpy(frame + 32, dstMac, 6); // Cible MAC (inconnue → 0)
*(uint32_t*)(frame + 38) = targetIp; // Cible IP
memset(frame + 42, 0, 18); // Remplissage jusqu'à 60 octets minimum
ethWrite(frame, 60);
uartPrint("ARP sent\r\n");
}
Traitement des trames reçues
La fonction ipRcvMacFrame filtre les trames entrantes par type (ARP ou IP) et déclenche le traitement approprié.
uint32_t ipRcvMacFrame(uint8_t *buf, uint32_t len)
{
if (len < 14) return 0;
uint16_t etherType = ntohs(*(uint16_t*)(buf + 12));
switch (etherType) {
case 0x0806: // ARP
arpRcv(buf + 14, len - 14);
break;
case 0x0800: // IPv4
ipRcv(buf + 14, len - 14, buf + 6);
break;
default:
break;
}
return 1;
}
Analyse d’une requête ARP entrante
La fonction arpRcv extrait les adresses IP/MAC et vérifie si la requête concerne l’appareil local. Si une réponse est nécessaire, elle peut être générée via arpSndRsp.
void arpRcv(uint8_t *payload, uint32_t plen)
{
if (plen < 28) return;
uint16_t operation = ntohs(*(uint16_t*)(payload + 6));
uint32_t targetIp = *(uint32_t*)(payload + 24);
// Vérifier si l'IP cible correspond à celle du périphérique
if (targetIp != g_ethIpAddr) return;
if (operation == 0x0001) { // Requête ARP
uint8_t *senderMac = payload + 8;
uint32_t senderIp = *(uint32_t*)(payload + 14);
uartPrint("ARP Request from %d.%d.%d.%d\r\n",
(senderIp>>0)&0xFF, (senderIp>>8)&0xFF,
(senderIp>>16)&0xFF, (senderIp>>24)&0xFF);
// Envoyer une réponse ARP
arpSndRsp(senderIp, senderMac);
}
}
Réponse ARP automatique
Lorsqu’une requête ARP est reçue, une réponse est envoyée avec l’adresse MAC locale.
void arpSndRsp(uint32_t dstIp, uint8_t *dstMac)
{
uint8_t *frame = (uint8_t*)txPacket;
memcpy(frame + 0, dstMac, 6);
memcpy(frame + 6, g_ethMacAddr, 6);
*(uint16_t*)(frame + 12) = htons(0x0806);
// En-tête ARP
*(uint16_t*)(frame + 14) = htons(0x0001);
*(uint16_t*)(frame + 16) = htons(0x0800);
frame[18] = 6; frame[19] = 4;
*(uint16_t*)(frame + 20) = htons(0x0002); // Réponse
memcpy(frame + 22, g_ethMacAddr, 6);
*(uint32_t*)(frame + 28) = g_ethIpAddr;
memcpy(frame + 32, dstMac, 6);
*(uint32_t*)(frame + 38) = dstIp;
memset(frame + 42, 0, 18);
ethWrite(frame, 60);
}
Initialisation des paramètres réseau
Associe une adresse MAC et IP au contexte global du module réseau.
void ipInit(uint8_t *mac, uint32_t ip)
{
memcpy(g_ethMacAddr, mac, 6);
g_ethIpAddr = ip;
}
Utilitaires de conversion et checksum
Les fonctions htons, ntohs assurent la conversion entre ordre des octets hôte et réseau. La somme de contrôle IP est calculée sur 16 bits.
uint16_t htons(uint16_t val)
{
return (val << 8) | (val >> 8);
}
uint16_t calcChecksum(uint16_t *data, uint32_t size)
{
uint32_t sum = 0;
while (size > 1) {
sum += *data++;
size -= 2;
}
if (size) sum += *(uint8_t*)data;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return ~sum;
}
Ce système permet à un microcontrôleur LPC1850 de participer activement à la résolution d’adresses dans un réseau Ethernet local via le protocole ARP, en émettant des requêtes et en répondant correctement aux sollicitations.