uIP 1.0
C:/asm/STM32-ethernet/ENC28J60prj/uip-master/uip/uip_arp.c
См. документацию.
00001 /**
00002  * \addtogroup uip
00003  * @{
00004  */
00005 
00006 /**
00007  * \defgroup uiparp uIP Address Resolution Protocol
00008  * @{
00009  *
00010  * Протокол разрешения адреса (Address Resolution Protocol, ARP)
00011  * используется для определения соответствия между адресами IP
00012  * и адресами уровня линка, такими как адреса Ethernet MAC. ARP
00013  * использует щироковещательные запросы (broadcast), чтобы запросить
00014  * адрес уровня линка для известного адреса IP, и хост, который
00015  * с конфигурирован на тот адрес IP, которому предназначен запрос,
00016  * ответит на него своим адресом уровня линка (т. е. передаст
00017  * свой MAC-адрес).
00018  *
00019  * \note Эта реализация ARP поддерживает только Ethernet.
00020  */
00021  
00022 /**
00023  * \file
00024  * Реализация ARP Address Resolution Protocol.
00025  * \author Adam Dunkels <adam@dunkels.com>
00026  *
00027  */
00028 
00029 /*
00030  * Copyright (c) 2001-2003, Adam Dunkels.
00031  * Все права зарезервированы. *
00032  * Повторное распространение, использование в исходном и двоичном виде,
00033  * с модификацией или без - разрешается, если выполняются следующие
00034  * условия:
00035  * 1. Распространение исходного кода должно сохранить вышеуказанную пометку
00036  *    копирайта, этот список условий и следующую правовую оговорку.
00037  * 2. Распространение исходного кода должно сохранить вышеуказанную пометку
00038  *    копирайта, этот список условий и следующую правовую оговорку в
00039  *    документации и/или других материалах, которые будут предоставлены
00040  *    вместе с распространяемыми материалами.
00041  * 3. Имя автора не может использоваться, чтобы подтвердить или продвинуть
00042  *    продукты, написанные с использованием этого программного обеспечения
00043  *    без специального на то разрешения.
00044  *
00045  * ЭТО ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ АВТОРОМ ``КАК ЕСТЬ'', БЕЗ
00046  * КАКОЙ-ЛИБО ЛЮБОЙ РАСШИРЕННОЙ ИЛИ ПОДРАЗУМЕВАЕМОЙ ГАРАНТИИ, ВКЛЮЧАЯ,
00047  * НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ГАРАНТИИ ВЫСОКОГО СПРОСА И ПРИГОДНОСТИ
00048  * ДЛЯ КОНКРЕТНОЙ ЦЕЛИ. АВТОР НИ ПРИ КАКИХ УСЛОВИЯХ НЕ ОТВЕТСТВЕНЕН
00049  * ЗА ЛЮБЫЕ УБЫТКИ - ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОБРАЗЦОВЫЕ
00050  * ИЛИ ПОСЛЕДОВАТЕЛЬНЫЕ (ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ ЭТИМ, ТРЕБОВАНИЯ
00051  * ЗАМЕНЫ ТОВАРА ИЛИ СЕРВИСА; ПОТЕРИ ИСПОЛЬЗОВАНИЯ, ДАННЫХ ИЛИ ВЫГОДЫ;
00052  * ИЛИ ПРЕКРАЩЕНИЕ БИЗНЕСА), ОДНАКО ВЫЗВАННЫЕ ПО ЛЮБОЙ ТЕОРИИ ОТВЕТСТВЕННОСТИ,
00053  * ЛИБО В КОНТРАКТЕ, ПРЯМОЙ ОТВЕТСТВЕННОСТИ, ЛИБО В НАРУШЕНИИ ЗАКОННЫХ ПРАВ
00054  * (ВКЛЮЧАЯ ТАК ИЛИ ИНАЧЕ НЕБРЕЖНОСТЬ), ВОЗНИКАЮЩИЕ ВСЕГДА ИЗ ИСПОЛЬЗОВАНИЯ
00055  * ЭТОГО ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, ДАЖЕ ЕСЛИ БЫЛО ПРЕДУПРЕЖДЕНИЕ О ВОЗМОЖНОСТИ
00056  * ТАКОГО ПОВРЕЖДЕНИЯ.
00057  *
00058  * Этот файл является частью стека uIP TCP/IP.
00059  *
00060  * $Id: uip_arp.c,v 1.8 2006/06/02 23:36:21 adam Exp $
00061  *
00062  */
00063 
00064 
00065 #include "uip_arp.h"
00066 
00067 #include <string.h>
00068 
00069 struct arp_hdr {
00070   struct uip_eth_hdr ethhdr;
00071   u16_t hwtype;
00072   u16_t protocol;
00073   u8_t hwlen;
00074   u8_t protolen;
00075   u16_t opcode;
00076   struct uip_eth_addr shwaddr;
00077   u16_t sipaddr[2];
00078   struct uip_eth_addr dhwaddr;
00079   u16_t dipaddr[2];
00080 };
00081 
00082 struct ethip_hdr {
00083   struct uip_eth_hdr ethhdr;
00084   /* IP header. */
00085   u8_t vhl,
00086     tos,
00087     len[2],
00088     ipid[2],
00089     ipoffset[2],
00090     ttl,
00091     proto;
00092   u16_t ipchksum;
00093   u16_t srcipaddr[2],
00094     destipaddr[2];
00095 };
00096 
00097 #define ARP_REQUEST 1
00098 #define ARP_REPLY   2
00099 
00100 #define ARP_HWTYPE_ETH 1
00101 
00102 struct arp_entry {
00103   u16_t ipaddr[2];
00104   struct uip_eth_addr ethaddr;
00105   u8_t time;
00106 };
00107 
00108 static const struct uip_eth_addr broadcast_ethaddr =
00109   {{0xff,0xff,0xff,0xff,0xff,0xff}};
00110 static const u16_t broadcast_ipaddr[2] = {0xffff,0xffff};
00111 
00112 static struct arp_entry arp_table[UIP_ARPTAB_SIZE];
00113 static u16_t ipaddr[2];
00114 static u8_t i, c;
00115 
00116 static u8_t arptime;
00117 static u8_t tmpage;
00118 
00119 #define BUF   ((struct arp_hdr *)&uip_buf[0])
00120 #define IPBUF ((struct ethip_hdr *)&uip_buf[0])
00121 /*-----------------------------------------------------------------------------------*/
00122 /**
00123  * Инициализирует модуль ARP.
00124  *
00125  */
00126 /*-----------------------------------------------------------------------------------*/
00127 void
00128 uip_arp_init(void)
00129 {
00130   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00131     memset(arp_table[i].ipaddr, 0, 4);
00132   }
00133 }
00134 /*-----------------------------------------------------------------------------------*/
00135 /**
00136  * Функция периодической обработки ARP.
00137  *
00138  * Эта функция выполняет периодические обработки по таймеру для модуля ARP, и она
00139  * должна вызываться с регулярными интервалами. Рекомендованный интервал между
00140  * вызовами 10 секунд.
00141  *
00142  */
00143 /*-----------------------------------------------------------------------------------*/
00144 void
00145 uip_arp_timer(void)
00146 {
00147   struct arp_entry *tabptr;
00148   
00149   ++arptime;
00150   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00151     tabptr = &arp_table[i];
00152     if((tabptr->ipaddr[0] | tabptr->ipaddr[1]) != 0 &&
00153        arptime - tabptr->time >= UIP_ARP_MAXAGE) {
00154       memset(tabptr->ipaddr, 0, 4);
00155     }
00156   }
00157 
00158 }
00159 /*-----------------------------------------------------------------------------------*/
00160 static void
00161 uip_arp_update(u16_t *ipaddr, struct uip_eth_addr *ethaddr)
00162 {
00163   register struct arp_entry *tabptr;
00164   /* Просмотр таблицы ARP и попытка найти запись для обновления
00165      Если таковая не найдена, привязка IP -> MAC будет вставлена
00166      в таблицу ARP. */
00167   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00168 
00169     tabptr = &arp_table[i];
00170     /* Проверка только тех записей, которые реально используются. */
00171     if(tabptr->ipaddr[0] != 0 &&
00172        tabptr->ipaddr[1] != 0) {
00173 
00174       /* Проверка - соответствует ли адрес источника (source IP) приходящего
00175          пакета адресу IP в этой записи таблицы ARP. */
00176       if(ipaddr[0] == tabptr->ipaddr[0] &&
00177          ipaddr[1] == tabptr->ipaddr[1]) {
00178          /* Найдена старая запись, обновление её и возврат. */
00179          memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
00180          tabptr->time = arptime;
00181          return;
00182       }
00183     }
00184   }
00185 
00186   /* Если мы оказались тут, то в таблице ARP не было найдено существующей
00187      записи, так что мы создадим её. */
00188 
00189   /* Сначала попробуем найти незадействованную запись в таблице ARP. */
00190   for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00191     tabptr = &arp_table[i];
00192     if(tabptr->ipaddr[0] == 0 &&
00193        tabptr->ipaddr[1] == 0) {
00194        break;
00195     }
00196   }
00197 
00198   /* Если незадействованных записей не найдено, мы попробуем найти самую
00199      старую запись, и отбросим её. */
00200   if(i == UIP_ARPTAB_SIZE) {
00201     tmpage = 0;
00202     c = 0;
00203     for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00204       tabptr = &arp_table[i];
00205       if(arptime - tabptr->time > tmpage) {
00206          tmpage = arptime - tabptr->time;
00207          c = i;
00208       }
00209     }
00210     i = c;
00211     tabptr = &arp_table[i];
00212   }
00213 
00214   /* Теперь заполним запись таблицы ARP новой информацией. */
00215   memcpy(tabptr->ipaddr, ipaddr, 4);
00216   memcpy(tabptr->ethaddr.addr, ethaddr->addr, 6);
00217   tabptr->time = arptime;
00218 }
00219 /*-----------------------------------------------------------------------------------*/
00220 /**
00221  * Обработка ARP для приходящих пакетов IP
00222  *
00223  * Эта функция должна вызваться драйвером устройства, когда принят пакет IP.
00224  * Функция проверит, есть ли адрес в кэше (в таблице) ARP, и если это так,
00225  * то запись ARP будет обновлена в кэше (в таблице ARP). Если запись ARP 
00226  * в кэше не найдена, то будет создана новая запись.
00227  *
00228  * Эта функция подразумевает наличие в буфере uip_buf[] пакета IP с предварительно
00229  * ожидаемым заголовком Ethernet, и длина пакета должна быть в глобальной переменной
00230  * uip_len.
00231  */
00232 /*-----------------------------------------------------------------------------------*/
00233 #if 0
00234 void
00235 uip_arp_ipin(void)
00236 {
00237   uip_len -= sizeof(struct uip_eth_hdr);
00238    
00239   /* Запись будет вставляться или обновляться только тогда, когда адрес источника
00240      (source IP) в пришедшем пакете IP поступил от хоста из локальной сети. */
00241   if((IPBUF->srcipaddr[0] & uip_netmask[0]) !=
00242      (uip_hostaddr[0] & uip_netmask[0])) {
00243     return;
00244   }
00245   if((IPBUF->srcipaddr[1] & uip_netmask[1]) !=
00246      (uip_hostaddr[1] & uip_netmask[1])) {
00247     return;
00248   }
00249   uip_arp_update(IPBUF->srcipaddr, &(IPBUF->ethhdr.src));
00250   
00251   return;
00252 }
00253 #endif /* 0 */
00254 /*-----------------------------------------------------------------------------------*/
00255 /**
00256  * Обработка ARP для приходящих пакетов ARP.
00257  *
00258  * Эта функция должна быть вызвана драйвером устройства, когда принят пакет ARP.
00259  * Функция будет работать по-разному, в зависимости от типа пакета ARP: если это
00260  * ответ на запрос (ARP reply), который был отослан ранее, то кэш ARP будет заполнен
00261  * значением из ответа. Если входящий ARP пакет является запросом (ARP request) на
00262  * наш адрес IP, то будет создан пакет ответа (ARP reply) и помещен в буфер uip_buf[].
00263  *
00264  * Когда функция делает возврат, значение глобальной переменной uip_len показывает,
00265  * должен или нет драйвер устройства отправить пакет. Если uip_len равна 0, то 
00266  * пакет отправлять не нужно. Если uip_len не равна 0, то она содержит длину 
00267  * исходящего пакета, который находится в буфере uip_buf[].
00268  *
00269  * Эта функция подразумевает на входе наличия пакета ARP с предварительно ожидаемым
00270  * заголовком Ethernet в буфере uip_buf[], и длину пакета в глобальной переменной
00271  * uip_len.
00272  */
00273 /*-----------------------------------------------------------------------------------*/
00274 void
00275 uip_arp_arpin(void)
00276 {
00277   
00278   if(uip_len < sizeof(struct arp_hdr)) {
00279     uip_len = 0;
00280     return;
00281   }
00282   uip_len = 0;
00283   
00284   switch(BUF->opcode) {
00285   case HTONS(ARP_REQUEST):
00286     /* Запрос ARP. Если запрашивается наш адрес, то отправим обратно
00287        ответ. */
00288     if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
00289       /* Сначала зарегистрируем в нашей таблице ARP того, кто сделал
00290          запрос, поскольку вероятно в будущем с этим хостом возможен
00291          обмен данными. */
00292       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
00293       
00294       /* Код ответа (reply opcode) равен 2. */
00295       BUF->opcode = HTONS(2);
00296 
00297       memcpy(BUF->dhwaddr.addr, BUF->shwaddr.addr, 6);
00298       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
00299       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00300       memcpy(BUF->ethhdr.dest.addr, BUF->dhwaddr.addr, 6);
00301       
00302       BUF->dipaddr[0] = BUF->sipaddr[0];
00303       BUF->dipaddr[1] = BUF->sipaddr[1];
00304       BUF->sipaddr[0] = uip_hostaddr[0];
00305       BUF->sipaddr[1] = uip_hostaddr[1];
00306 
00307       BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
00308       uip_len = sizeof(struct arp_hdr);
00309     }
00310     break;
00311   case HTONS(ARP_REPLY):
00312     /* Это был ответ (ARP reply). Добавим или обновим запись в таблице ARP,
00313        если ответ предназначался нам. */
00314     if(uip_ipaddr_cmp(BUF->dipaddr, uip_hostaddr)) {
00315       uip_arp_update(BUF->sipaddr, &BUF->shwaddr);
00316     }
00317     break;
00318   }
00319 
00320   return;
00321 }
00322 /*-----------------------------------------------------------------------------------*/
00323 /**
00324  * Ожидается наличие присоединенного заголовка Ethernet к исходящему пакету IP,
00325  * и делается проверка, нужно или нет отправить запрос ARP.
00326  *
00327  * Эта функция должна быть вызвана перед отправкой пакета IP. Функция
00328  * проверяет адрес назначения (destination IP) пакета IP, чтобы посмотреть,
00329  * какой адрес Ethernet MAC должен быть использован в качестве адреса назначения
00330  * (destination MAC) в сети Ethernet.
00331  *
00332  * Если адрес destination IP находится в локальной сети (это определяется
00333  * путем операции логического И над сетевой маской и нашим адресом IP), функция
00334  * проверит кэш ARP, чтобы посмотреть имеется ли в ней запись для адреса 
00335  * destination IP. Если есть, то функция вернет присоединенный заголовок Ethernet.
00336  * Если в кэше ARP не найдена запись с адресом destination IP, то данные пакета
00337  * в буфере uip_buf[] будут заменены на пакет запроса (ARP request) на адрес
00338  * destination IP. Пакет IP отбрасывается, и подразумевается, что протоколы
00339  * более высокого уровня (например TCP) по необходимости сделают повторную 
00340  * передачу отброшенного пакета.
00341  *
00342  * Если адрес destination IP находится не в локальной сети, вместо этого будет
00343  * использоваться адрес IP шлюза по умолчанию (default router).
00344  *
00345  * Когда функция делает возврат, в буфере uip_buf[] находится пакет, и длина
00346  * пакета находится в глобальной переменной uip_len.
00347  */
00348 /*-----------------------------------------------------------------------------------*/
00349 void
00350 uip_arp_out(void)
00351 {
00352   struct arp_entry *tabptr;
00353   
00354   /* Ищет адрес назначения (destination IP) в таблице ARP, и конструирует
00355      заголовок Ethernet. Если destination IP находится не в локальной сети,
00356      будем использовать вместо него адрес IP шлюза по умолчанию (default router).
00357 
00358      Если в таблице ARP не найдена соответствующая запись, то перезапишем
00359      оригинальный пакет IP запросом ARP на адрес IP. */
00360 
00361   /* Сначала проверим адрес назначения, попадает ли он в локальное
00362      широковещание (local broadcast). */
00363   if(uip_ipaddr_cmp(IPBUF->destipaddr, broadcast_ipaddr)) {
00364     memcpy(IPBUF->ethhdr.dest.addr, broadcast_ethaddr.addr, 6);
00365   } else {
00366     /* Проверка - принадлежит ли адрес назначения локальной сети. */
00367     if(!uip_ipaddr_maskcmp(IPBUF->destipaddr, uip_hostaddr, uip_netmask)) {
00368       /* Адрес назначения был не в локальной сети, поэтому вместо него нужно
00369          использовать адрес IP шлюза по умолчанию, когда определяем
00370          MAC-адрес. */
00371       uip_ipaddr_copy(ipaddr, uip_draddr);
00372     } else {
00373       /* Иначе будет использовать адрес IP назначения. */
00374       uip_ipaddr_copy(ipaddr, IPBUF->destipaddr);
00375     }
00376       
00377     for(i = 0; i < UIP_ARPTAB_SIZE; ++i) {
00378       tabptr = &arp_table[i];
00379       if(uip_ipaddr_cmp(ipaddr, tabptr->ipaddr)) {
00380          break;
00381       }
00382     }
00383 
00384     if(i == UIP_ARPTAB_SIZE) {
00385       /* Адрес назначения отсутствует в нашей таблице ARP, поэтому
00386          перезапишем пакет IP пакетом запроса ARP. */
00387 
00388       memset(BUF->ethhdr.dest.addr, 0xff, 6);
00389       memset(BUF->dhwaddr.addr, 0x00, 6);
00390       memcpy(BUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00391       memcpy(BUF->shwaddr.addr, uip_ethaddr.addr, 6);
00392     
00393       uip_ipaddr_copy(BUF->dipaddr, ipaddr);
00394       uip_ipaddr_copy(BUF->sipaddr, uip_hostaddr);
00395       BUF->opcode = HTONS(ARP_REQUEST); /* ARP request. */
00396       BUF->hwtype = HTONS(ARP_HWTYPE_ETH);
00397       BUF->protocol = HTONS(UIP_ETHTYPE_IP);
00398       BUF->hwlen = 6;
00399       BUF->protolen = 4;
00400       BUF->ethhdr.type = HTONS(UIP_ETHTYPE_ARP);
00401 
00402       uip_appdata = &uip_buf[UIP_TCPIP_HLEN + UIP_LLH_LEN];
00403     
00404       uip_len = sizeof(struct arp_hdr);
00405       return;
00406     }
00407 
00408     /* Создание заголовка Ethernet. */
00409     memcpy(IPBUF->ethhdr.dest.addr, tabptr->ethaddr.addr, 6);
00410   }
00411   memcpy(IPBUF->ethhdr.src.addr, uip_ethaddr.addr, 6);
00412   
00413   IPBUF->ethhdr.type = HTONS(UIP_ETHTYPE_IP);
00414 
00415   uip_len += sizeof(struct uip_eth_hdr);
00416 }
00417 /*-----------------------------------------------------------------------------------*/
00418 
00419 /** @} */
00420 /** @} */