AVR Урок 40. LAN. ENC28J60. Часть 8

 

 

 

 

Урок 40

 

Часть 8

 

LAN. ENC28J60

 

 

В предыдущей части нашего урока мы написали ещё две нужные функции и код для отображения некоторых частей заголовка ARP-запроса.

 

В функии arp_send занесём в ARP-заголовок код ответа ARP

 

void arp_send(enc28j60_frame_ptr *frame)

{

  arp_msg_ptr *msg = (void*)(frame->data);

  msg->op = ARP_REPLY;

 

Занесём также в заголовок физические адреса

 

msg->op = ARP_REPLY;

memcpy(msg->macaddr_dst, msg->macaddr_src, 6);

memcpy(msg->macaddr_src, macaddr, 6);

 

Затем занесём IP-адреса

 

memcpy(msg->macaddr_src, macaddr, 6);

msg->ipaddr_dst = msg->ipaddr_src;

msg->ipaddr_src = IP_ADDR;

 

И в завершении функции отправим пакет

 

  msg->ipaddr_src = IP_ADDR;

  eth_send(frame, sizeof(arp_msg_ptr));

}

 

В функции eth_read ответим на ARP-запрос

 

if(arp_read(frame, len sizeof(enc28j60_frame_ptr)))

{

  arp_send(frame);

}

 

Соберём код, прошьём контроллер. Для того, чтобы увидеть наш ответ, желательно установить бесплатную программу Wireshark. Это анализатор сетевых пакетов.

Установим в данной программе фильтр только на пакеты arp

 

image05

 

Пропинугем наш IP-адрес таким же образом, как и прежде. Ответа на пинг мы не получим, но на запрос ARP в утилите мы увидим ответ

 

image06

Можно также открыть и посмотреть структуру пакета ARP

 

image07

 

 

Также в таблице соответствия адресов ARP компьютера мы видим теперь наши данные

 

image09

 

ARP-ответ мы отправили, хотелось бы ещё отвечать на пинги, но это не так просто. Нужно научиться работать с протоколом ICMP (Internet Control Message Protocol — протоеол межсетевых управляющих сообщений), находящимся между сетевым уровнем и транспортным. А чтобы работать с протоколом ICMP, необходимо разобраться ещё с протоколом IP. Вот с него мы пока и начнём.

Протокол IP является более тяжёлым, нежели протокол ARP, так как перед ним стоит много задач. Одна из них — найти маршрут, по которому нужно отправить пакет, также пакет может состоять из нескольких фрагментов, находящихся в различных фреймах. Но ничего, потихоньку разберёмся.

В функции eth_read добавим в условие распознавания протокола IP фигурные скобки и условие if исправим на else if

 

else if (frame->type==ETH_IP)

{

  USART_TX((uint8_t*)"; ip",4);

}

 

Над этой функцией добавим ещё функцию чтения пакета IP

 

//———————————————————

uint8_t ip_read(enc28j60_frame_ptr *frame, uint16_t len)

{

}

//———————————————————

 

Вот формат заголовка пакета IP

 

image10

 

Первое поле — номер версии, в нашем случае 4, так как версия протокола у нас IPv4, в которой IP-адрес состоит из 4 байтов.

Дальше идет длина заголовка, измеряемая в 4-байтных величинах или в двойных словах (DWORD), поэтому заголовок IP должен быть кратным 4 байтам. В нашем случае без параметров и доп. опций здесь будет цифра 5.

Тип обслуживания — в данный момент практически не используется.

Общая длина — это суммарная длина пакета вместе с данными. Нам она важна, так как мы из-за выравнивания пакетов её не знаем. Измеряется в байтах. Максимальное значение — 65535 байт. Но на практике не превышает 1500 из-за максимальной длины кадра Ethernet.

Идентификатор пакета, флаги и смещение фрагмента используются для фрагментации, мы её пока не рассматриваем.

Время жизни — это количество хопов (прыжков). После прохождения каждого маршрутизатора уменьшается на единицу, чтобы всякие левые пакеты не гуляли вечно по сети.

Тип протокола — пример — TCP — 6, UDP — 17, ICMP — 1.

Контрольная сумма заголовка — это хитро рассчитанная величина, которая служит для проверки дохождения пакета до получателя. Расчитывается и на приёмнике и на источнике и сравнивается. Также контрольная сумма меняется после прохождения через маршрутизатор, так как там время жизни уменьшается на 1 и поле меняется.

А дальше понятно — IP-адреса отправителя и получателя.

Добавим структуру для пакте IP в файл net.h

 

//——————————————

typedef struct ip_pkt {

  uint8_t verlen; //версия протокола и длина заголовка

  uint8_t ts; //тип сервиса

  uint16_t len; //длина

  uint16_t id; //идентификатор пакета

  uint16_t fl_frg_of; //флаги и смещение фрагмента

  uint8_t ttl; //время жизни

  uint8_t prt; //тип протокола

  uint16_t cs; //контрольная сумма заголовка

  uint32_t ipaddr_src; //IP-адрес отправителя

  uint32_t ipaddr_dst; //IP-адрес получателя

  uint8_t data[]; //данные

} ip_pkt_ptr;

//——————————————

 

Ещё напишем макросы для типов протоколов

 

//——————————————

#define IP_ICMP 1

#define IP_TCP 6

#define IP_UDP 17

//——————————————

 

В следующей части нашего урока мы напишем функцию расчета контрольной суммы, а также напишем функцию чтения IP-пакетов.

 

Предыдущая часть Программирование МК AVR Следующая часть

 

 

Техническая документация:

Документация на микросхему ENC28J60

Перечень ошибок ENC28J60 (Errata)

 

 

Приобрести плату Atmega 328p Pro Mini можно здесь.

Программатор (продавец надёжный) USBASP USBISP 2.0

Ethernet LAN Сетевой Модуль можно купить здесь (модуль SD SPI в подарок) ENC28J60 Ethernet LAN Сетевой Модуль.

 

 

Смотреть ВИДЕОУРОК (нажмите на картинку)

 

AVR LAN. ENC28J60

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

*