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 с адаптером можно здесь USBASP USBISP 3.3 с адаптером

Ethernet LAN Сетевой Модуль можно купить здесь ENC28J60 Ethernet LAN Сетевой Модуль.

 

 

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

 

AVR LAN. ENC28J60

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

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

*