ICMP запросы (Ping) на uIP

Стек uIP умеет только отвечать на ICMP запросы (если его пингуют, к примеру), но не умеет их отправлять. Исправим это.

Составляем IP заголовок
#define ICMPBUF ((struct uip_icmpip_hdr *)&uip_buf[UIP_LLH_LEN])

ICMPBUF->vhl = 0x45;
ICMPBUF->tos = 0;
uint16_t len = sizeof(struct uip_icmpip_hdr); // длина будет равна заголовку ip + icmp
ICMPBUF->len[0] = len >> 8;
ICMPBUF->len[1] = len & 0xff;
uint16_t ipid = 0;
ICMPBUF->ipid[0] = ipid >> 8;
ICMPBUF->ipid[1] = ipid & 0xff;
ICMPBUF->ipoffset[0] = ICMPBUF->ipoffset[1] = 0;
ICMPBUF->ttl = UIP_TTL;
ICMPBUF->proto = UIP_PROTO_ICMP;
// указываем свой ip и ip удаленного устройства.
uip_gethostaddr(ICMPBUF->srcipaddr);
uip_ipaddr(&ICMPBUF->destipaddr, 192, 168, 1, 1); // адрес, который будем пинговать

ICMPBUF->ipchksum = 0;
ICMPBUF->ipchksum = ~(uip_ipchksum());

ICMPBUF->type = 8; //ICMP_ECHO;
ICMPBUF->icode = 0;
ICMPBUF->icmpchksum = 0;
ICMPBUF->icmpchksum = uip_chksum((uint16_t*)&ICMPBUF->type, 8);
ICMPBUF->icmpchksum = ~((ICMPBUF->icmpchksum == 0) ? 0xffff : ICMPBUF->icmpchksum);

uip_len = UIP_IPH_LEN + 8; // длина равна заголовку ip + заголовку icmp

Далее пуляем arp
uip_arp_out();


И отправляем пакет
enc28j60_send_packet((uint8_t *) uip_buf, uip_len);

Здесь надо учесть, что если текущего IP нет в ARP таблице, то на данном этапе будет отправлен ARP запрос. Чтобы понять, отправлен ARP или сформированный нами запрос, перепишем немного uip_arp_out
// Если запись в arp таблице не найдена, вернет 0. При этом данные в буффере будут заменены на arp запрос
uint8_t uip_arp_out(void)
{
struct arp_entry *tabptr;

/* Find the destination IP address in the ARP table and construct
the Ethernet header. If the destination IP addres isn't on the
local network, we use the default router's IP address instead.

If not ARP table entry is found, we overwrite the original IP
packet with an ARP request for the IP address. */

// First check if destination is a local broadcast.
if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
} else {
// Check if the destination address is on the local network.
if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
/* Destination address was not on the local network, so we need to
use the default router's IP address instead of the destination
address when determining the MAC address. */
uip_ipaddr_copy(ipaddr, uip_draddr);
} else
// Else, we use the destination IP address.
uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);

for(i = 0; i < UIP_ARPTAB_SIZE; ++i) { tabptr = &arp_table[i]; if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) break;
}

if(i == UIP_ARPTAB_SIZE) {
// The destination address was not in our ARP table, so we overwrite the IP packet with an ARP request.

memset(BUF->ethhdr.dest.addr, 0xff, 6);
memset(BUF->dhwaddr.addr, 0x00, 6);
memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);

uip_ipaddr_copy(BUF->dipaddr, ipaddr);
uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
BUF->protocol = HTONS(UIP_ETHTYPE_IP);
BUF->hwlen = 6;
BUF->protolen = 4;
BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);

uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];

uip_len = sizeof(struct arp_hdr);
return 0;
}

// Build an ethernet header.
memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
}
memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);

IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);

uip_len += sizeof(struct uip_eth_hdr);
return 1;
}


Готово!

Комментарии

  1. ICMP differs from transport protocols such as TCP and UDP in that it is not typically used to exchange data between systems, nor is it regularly employed by end-user network applications (with the exception of some diagnostic tools like ping and traceroute ).

    ОтветитьУдалить

Отправить комментарий

Популярные сообщения из этого блога

Прием команд с пульта дистанционного управления

STM32F4. Обновление прошивки с карты памяти (Bootloader SD)

Работа с шиной 1-wire. Подключение термодатчика DS18B20 к AVR