5 #include <gpxe/if_ether.h>
6 #include <gpxe/iobuf.h>
8 #include <gpxe/icmp6.h>
10 #include <gpxe/netdevice.h>
14 * Neighbour Discovery Protocol
16 * This file implements address resolution as specified by the neighbour
17 * discovery protocol in RFC2461. This protocol is part of the IPv6 protocol
21 /* A neighbour entry */
23 /** Target IP6 address */
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 */
33 /** Number of entries in the neighbour cache table */
34 #define NUM_NDP_ENTRIES 4
36 /** The neighbour cache table */
37 static struct ndp_entry ndp_table
[NUM_NDP_ENTRIES
];
38 #define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
40 static unsigned int next_new_ndp_entry
= 0;
43 * Find entry in the neighbour cache
47 static struct ndp_entry
*
48 ndp_find_entry ( struct in6_addr
*in6
) {
49 struct ndp_entry
*ndp
;
51 for ( ndp
= ndp_table
; ndp
< ndp_table_end
; ndp
++ ) {
52 if ( IP6_EQUAL ( ( *in6
), ndp
->in6
) &&
53 ( ndp
->state
!= NDP_STATE_INVALID
) ) {
63 * @v netdev Network device
65 * @v ll_addr Link-layer address
66 * @v state State of the entry - one of the NDP_STATE_XXX values
69 add_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
];
75 ndp
->ll_protocol
= netdev
->ll_protocol
;
76 memcpy ( &ndp
->in6
, &( *in6
), sizeof ( *in6
) );
78 memcpy ( ndp
->ll_addr
, ll_addr
, netdev
->ll_protocol
->ll_addr_len
);
80 memset ( ndp
->ll_addr
, 0, netdev
->ll_protocol
->ll_addr_len
);
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
) );
89 * Resolve the link-layer address
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
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
102 int 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
;
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
);
118 /* Check if the entry was already created */
120 DBG ( "Awaiting neighbour advertisement\n" );
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 */
130 DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest
) );
132 /* Add entry in the neighbour cache */
133 add_ndp_entry ( netdev
, dest
, NULL
, NDP_STATE_INCOMPLETE
);
135 /* Send neighbour solicitation */
136 if ( ( rc
= icmp6_send_solicit ( netdev
, src
, dest
) ) != 0 ) {
143 * Process neighbour advertisement
145 * @v iobuf I/O buffer
146 * @v st_src Source address
147 * @v st_dest Destination address
149 int 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
;
155 if ( iob_len ( iobuf
) < sizeof ( *nadvert
) ) {
156 DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf
) );
160 assert ( nadvert
->code
== 0 );
161 assert ( nadvert
->flags
& ICMP6_FLAGS_SOLICITED
);
162 assert ( nadvert
->opt_type
== 2 );
164 /* Update the neighbour cache, if entry is present */
165 ndp
= ndp_find_entry ( &nadvert
->target
);
168 assert ( nadvert
->opt_len
==
169 ( ( 2 + ndp
->ll_protocol
->ll_addr_len
) / 8 ) );
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
;
178 DBG ( "Unsolicited advertisement (dropping packet)\n" );