uIP 1.0
|
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 /** @} */