]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/net/arp.c
Initial revision
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / net / arp.c
1 //==========================================================================
2 //
3 //      net/arp.c
4 //
5 //      Stand-alone ARP support for RedBoot
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2002, 2003 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas
46 // Date:         2000-07-14
47 // Purpose:      
48 // Description:  
49 //              
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #include <net/net.h>
57
58 static struct {
59     int      waiting;
60     char     *eth;
61     char     *ip;
62 } arp_req;
63
64 /*
65  * Handle incoming ARP packets.
66  */
67 void
68 __arp_handler(pktbuf_t *pkt)
69 {
70     arp_header_t *arp = pkt->arp_hdr;
71     int hw_type, protocol;
72
73     /*
74      * Only handle ethernet hardware and IP protocol.
75      */
76     protocol = ntohs(arp->protocol);
77     hw_type = ntohs(arp->hw_type);
78     if ((hw_type == ARP_HW_ETHER) && (protocol == ETH_TYPE_IP)) {
79         /*
80          * Handle requests for our ethernet address.
81          */
82         if (!memcmp(arp->target_ip, __local_ip_addr, 4)) {
83             if (ntohs(arp->opcode) == ARP_REQUEST) {
84                 /* format response. */
85                 arp->opcode = htons(ARP_REPLY);
86                 memcpy(arp->target_ip, arp->sender_ip,
87                        sizeof(ip_addr_t));
88                 memcpy(arp->target_enet, arp->sender_enet,
89                        sizeof(enet_addr_t));
90                 memcpy(arp->sender_ip, __local_ip_addr,
91                        sizeof(ip_addr_t));
92                 memcpy(arp->sender_enet, __local_enet_addr,
93                        sizeof(enet_addr_t));
94                 pkt->pkt_bytes = sizeof(arp_header_t);
95                 __enet_send(pkt, &arp->target_enet, ETH_TYPE_ARP);
96
97             } else if (ntohs(arp->opcode) == ARP_REPLY && arp_req.waiting) {
98                 if (!memcmp(arp_req.ip, arp->sender_ip, sizeof(ip_addr_t))) {
99                     memcpy(arp_req.eth, arp->sender_enet, sizeof(enet_addr_t));
100                     arp_req.waiting = 0;
101                 }
102             }
103         }
104     }
105     __pktbuf_free(pkt);
106 }
107
108
109 /* 
110  * Find the ethernet address of the machine with the given
111  * ip address.
112  * Return 0 and fills in 'eth_addr' if successful,
113  *       -1 if unsuccessful.
114  */
115 int
116 __arp_request(ip_addr_t *ip_addr, enet_addr_t *eth_addr, int allow_self)
117 {
118     pktbuf_t *pkt;
119     arp_header_t *arp;
120     unsigned long retry_start;
121     enet_addr_t   bcast_addr;
122     int           retry;
123
124     if (!allow_self) {
125         // Special case request for self
126         if (!memcmp(ip_addr, __local_ip_addr, 4)) {
127             memcpy(eth_addr, __local_enet_addr, sizeof(enet_addr_t));
128             return 0;
129         }
130     }
131
132     /* just fail if can't get a buffer */
133     if ((pkt = __pktbuf_alloc(ARP_PKT_SIZE)) == NULL)
134         return -1;
135
136     arp = pkt->arp_hdr;
137     arp->opcode = htons(ARP_REQUEST);
138     arp->hw_type = htons(ARP_HW_ETHER);
139     arp->protocol = htons(0x800);
140     arp->hw_len = sizeof(enet_addr_t);
141     arp->proto_len = sizeof(ip_addr_t);
142
143     memcpy(arp->sender_ip, __local_ip_addr, sizeof(ip_addr_t));
144     memcpy(arp->sender_enet, __local_enet_addr, sizeof(enet_addr_t));
145     memcpy(arp->target_ip, ip_addr, sizeof(ip_addr_t));
146
147     bcast_addr[0] = 255;
148     bcast_addr[1] = 255;
149     bcast_addr[2] = 255;
150     bcast_addr[3] = 255;
151     bcast_addr[4] = 255;
152     bcast_addr[5] = 255;
153
154     arp_req.eth = (char *)eth_addr;
155     arp_req.ip = (char *)ip_addr;
156     arp_req.waiting = 1;
157
158     retry = 8;
159     while (retry-- > 0) {
160
161         /* send the packet */
162         pkt->pkt_bytes = sizeof(arp_header_t);
163         __enet_send(pkt, &bcast_addr, ETH_TYPE_ARP);
164
165         retry_start = MS_TICKS();
166         while ((MS_TICKS_DELAY() - retry_start) < 250) {
167             __enet_poll();
168             if (!arp_req.waiting) {
169                 __pktbuf_free(pkt);
170                 return 0;
171             }
172         }
173     }
174     __pktbuf_free(pkt);
175     return -1;
176 }
177
178 #define NUM_ARP 16
179 static ip_route_t routes[NUM_ARP];
180
181 int
182 __arp_lookup(ip_addr_t *host, ip_route_t *rt)
183 {
184     int i;
185     static int next_arp = 0;
186
187     for (i = 0;  i < NUM_ARP;  i++) {
188         if (memcmp(host, &routes[i].ip_addr, sizeof(*host)) == 0) {
189             // This is a known host
190             memcpy(rt, &routes[i], sizeof(*rt));
191             return 0;
192         }
193     }
194     memcpy(&rt->ip_addr, host, sizeof(*host));
195     if (((*host)[0] == 0xFF) && ((*host)[1] == 0xFF) && ((*host)[2] == 0xFF)) {
196         memset(&rt->enet_addr, 0xFF, sizeof(rt->enet_addr));
197         return 0;
198 #ifdef CYGSEM_REDBOOT_NETWORKING_USE_GATEWAY
199     } else if (!__ip_addr_local(host)) {
200         // non-local IP address -- look up Gateway's Ethernet address
201         host = &__local_ip_gate;
202 #endif
203     }
204     if (__arp_request(host, &rt->enet_addr, 0) < 0) {
205         return -1;
206     } else {
207         memcpy(&routes[next_arp], rt, sizeof(*rt));
208         if (++next_arp == NUM_ARP) next_arp = 0;
209         return 0;
210     }
211 }
212