source: bootcd/isolinux/syslinux-6.03/gpxe/src/net/ndp.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 4.9 KB
RevLine 
[e16e8f2]1#include <stdint.h>
2#include <string.h>
3#include <byteswap.h>
4#include <errno.h>
5#include <gpxe/if_ether.h>
6#include <gpxe/iobuf.h>
7#include <gpxe/ndp.h>
8#include <gpxe/icmp6.h>
9#include <gpxe/ip6.h>
10#include <gpxe/netdevice.h>
11
12/** @file
13 *
14 * Neighbour Discovery Protocol
15 *
16 * This file implements address resolution as specified by the neighbour
17 * discovery protocol in RFC2461. This protocol is part of the IPv6 protocol
18 * family.
19 */
20
21/* A neighbour entry */
22struct ndp_entry {
23        /** Target IP6 address */
24        struct in6_addr in6;
25        /** Link layer protocol */
26        struct ll_protocol *ll_protocol;
27        /** Link-layer address */
28        uint8_t ll_addr[MAX_LL_ADDR_LEN];
29        /** State of the neighbour entry */
30        int state;
31};
32
33/** Number of entries in the neighbour cache table */
34#define NUM_NDP_ENTRIES 4
35
36/** The neighbour cache table */
37static struct ndp_entry ndp_table[NUM_NDP_ENTRIES];
38#define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
39
40static unsigned int next_new_ndp_entry = 0;
41
42/**
43 * Find entry in the neighbour cache
44 *
45 * @v in6       IP6 address
46 */
47static struct ndp_entry *
48ndp_find_entry ( struct in6_addr *in6 ) {
49        struct ndp_entry *ndp;
50
51        for ( ndp = ndp_table ; ndp < ndp_table_end ; ndp++ ) {
52                if ( IP6_EQUAL ( ( *in6 ), ndp->in6 ) &&
53                     ( ndp->state != NDP_STATE_INVALID ) ) {
54                        return ndp;
55                }
56        }
57        return NULL;
58}
59
60/**
61 * Add NDP entry
62 *
63 * @v netdev    Network device
64 * @v in6       IP6 address
65 * @v ll_addr   Link-layer address
66 * @v state     State of the entry - one of the NDP_STATE_XXX values
67 */
68static void
69add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
70                void *ll_addr, int state ) {
71        struct ndp_entry *ndp;
72        ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES];
73
74        /* Fill up entry */
75        ndp->ll_protocol = netdev->ll_protocol;
76        memcpy ( &ndp->in6, &( *in6 ), sizeof ( *in6 ) );
77        if ( ll_addr ) {
78                memcpy ( ndp->ll_addr, ll_addr, netdev->ll_protocol->ll_addr_len );
79        } else {
80                memset ( ndp->ll_addr, 0, netdev->ll_protocol->ll_addr_len );
81        }
82        ndp->state = state;
83        DBG ( "New neighbour cache entry: IP6 %s => %s %s\n",
84              inet6_ntoa ( ndp->in6 ), netdev->ll_protocol->name,
85              netdev->ll_protocol->ntoa ( ndp->ll_addr ) );
86}
87
88/**
89 * Resolve the link-layer address
90 *
91 * @v netdev            Network device
92 * @v dest              Destination address
93 * @v src               Source address
94 * @ret dest_ll_addr    Destination link-layer address or NULL
95 * @ret rc              Status
96 *
97 * This function looks up the neighbour cache for an entry corresponding to the
98 * destination address. If it finds a valid entry, it fills up dest_ll_addr and
99 * returns 0. Otherwise it sends a neighbour solicitation to the solicited
100 * multicast address.
101 */
102int ndp_resolve ( struct net_device *netdev, struct in6_addr *dest,
103                  struct in6_addr *src, void *dest_ll_addr ) {
104        struct ll_protocol *ll_protocol = netdev->ll_protocol;
105        struct ndp_entry *ndp;
106        int rc;
107
108        ndp = ndp_find_entry ( dest );
109        /* Check if the entry is valid */
110        if ( ndp && ndp->state == NDP_STATE_REACHABLE ) {
111                DBG ( "Neighbour cache hit: IP6 %s => %s %s\n",
112                      inet6_ntoa ( *dest ), ll_protocol->name,
113                      ll_protocol->ntoa ( ndp->ll_addr ) );
114                memcpy ( dest_ll_addr, ndp->ll_addr, ll_protocol->ll_addr_len );
115                return 0;
116        }
117
118        /* Check if the entry was already created */
119        if ( ndp ) {
120                DBG ( "Awaiting neighbour advertisement\n" );
121                /* For test */
122//              ndp->state = NDP_STATE_REACHABLE;
123//              memcpy ( ndp->ll_addr, netdev->ll_addr, 6 );
124//              assert ( ndp->ll_protocol->ll_addr_len == 6 );
125//              icmp6_test_nadvert ( netdev, dest, ndp->ll_addr );
126//              assert ( ndp->state == NDP_STATE_REACHABLE );
127                /* Take it out till here */
128                return -ENOENT;
129        }
130        DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest ) );
131
132        /* Add entry in the neighbour cache */
133        add_ndp_entry ( netdev, dest, NULL, NDP_STATE_INCOMPLETE );
134
135        /* Send neighbour solicitation */
136        if ( ( rc = icmp6_send_solicit ( netdev, src, dest ) ) != 0 ) {
137                return rc;
138        }
139        return -ENOENT;
140}
141
142/**
143 * Process neighbour advertisement
144 *
145 * @v iobuf     I/O buffer
146 * @v st_src    Source address
147 * @v st_dest   Destination address
148 */
149int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src __unused,
150                           struct sockaddr_tcpip *st_dest __unused ) {
151        struct neighbour_advert *nadvert = iobuf->data;
152        struct ndp_entry *ndp;
153
154        /* Sanity check */
155        if ( iob_len ( iobuf ) < sizeof ( *nadvert ) ) {
156                DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
157                return -EINVAL;
158        }
159
160        assert ( nadvert->code == 0 );
161        assert ( nadvert->flags & ICMP6_FLAGS_SOLICITED );
162        assert ( nadvert->opt_type == 2 );
163
164        /* Update the neighbour cache, if entry is present */
165        ndp = ndp_find_entry ( &nadvert->target );
166        if ( ndp ) {
167
168        assert ( nadvert->opt_len ==
169                        ( ( 2 + ndp->ll_protocol->ll_addr_len ) / 8 ) );
170
171                if ( IP6_EQUAL ( ndp->in6, nadvert->target ) ) {
172                        memcpy ( ndp->ll_addr, nadvert->opt_ll_addr,
173                                 ndp->ll_protocol->ll_addr_len );
174                        ndp->state = NDP_STATE_REACHABLE;
175                        return 0;
176                }
177        }
178        DBG ( "Unsolicited advertisement (dropping packet)\n" );
179        return 0;
180}
Note: See TracBrowser for help on using the repository browser.