ndp.c
Go to the documentation of this file.00001 #include <stdint.h>
00002 #include <string.h>
00003 #include <byteswap.h>
00004 #include <errno.h>
00005 #include <gpxe/if_ether.h>
00006 #include <gpxe/iobuf.h>
00007 #include <gpxe/ndp.h>
00008 #include <gpxe/icmp6.h>
00009 #include <gpxe/ip6.h>
00010 #include <gpxe/netdevice.h>
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 struct ndp_entry {
00023
00024 struct in6_addr in6;
00025
00026 struct ll_protocol *ll_protocol;
00027
00028 uint8_t ll_addr[MAX_LL_ADDR_LEN];
00029
00030 int state;
00031 };
00032
00033
00034 #define NUM_NDP_ENTRIES 4
00035
00036
00037 static struct ndp_entry ndp_table[NUM_NDP_ENTRIES];
00038 #define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
00039
00040 static unsigned int next_new_ndp_entry = 0;
00041
00042
00043
00044
00045
00046
00047 static struct ndp_entry *
00048 ndp_find_entry ( struct in6_addr *in6 ) {
00049 struct ndp_entry *ndp;
00050
00051 for ( ndp = ndp_table ; ndp < ndp_table_end ; ndp++ ) {
00052 if ( IP6_EQUAL ( ( *in6 ), ndp->in6 ) &&
00053 ( ndp->state != NDP_STATE_INVALID ) ) {
00054 return ndp;
00055 }
00056 }
00057 return NULL;
00058 }
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 static void
00069 add_ndp_entry ( struct net_device *netdev, struct in6_addr *in6,
00070 void *ll_addr, int state ) {
00071 struct ndp_entry *ndp;
00072 ndp = &ndp_table[next_new_ndp_entry++ % NUM_NDP_ENTRIES];
00073
00074
00075 ndp->ll_protocol = netdev->ll_protocol;
00076 memcpy ( &ndp->in6, &( *in6 ), sizeof ( *in6 ) );
00077 if ( ll_addr ) {
00078 memcpy ( ndp->ll_addr, ll_addr, netdev->ll_protocol->ll_addr_len );
00079 } else {
00080 memset ( ndp->ll_addr, 0, netdev->ll_protocol->ll_addr_len );
00081 }
00082 ndp->state = state;
00083 DBG ( "New neighbour cache entry: IP6 %s => %s %s\n",
00084 inet6_ntoa ( ndp->in6 ), netdev->ll_protocol->name,
00085 netdev->ll_protocol->ntoa ( ndp->ll_addr ) );
00086 }
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 int ndp_resolve ( struct net_device *netdev, struct in6_addr *dest,
00103 struct in6_addr *src, void *dest_ll_addr ) {
00104 struct ll_protocol *ll_protocol = netdev->ll_protocol;
00105 struct ndp_entry *ndp;
00106 int rc;
00107
00108 ndp = ndp_find_entry ( dest );
00109
00110 if ( ndp && ndp->state == NDP_STATE_REACHABLE ) {
00111 DBG ( "Neighbour cache hit: IP6 %s => %s %s\n",
00112 inet6_ntoa ( *dest ), ll_protocol->name,
00113 ll_protocol->ntoa ( ndp->ll_addr ) );
00114 memcpy ( dest_ll_addr, ndp->ll_addr, ll_protocol->ll_addr_len );
00115 return 0;
00116 }
00117
00118
00119 if ( ndp ) {
00120 DBG ( "Awaiting neighbour advertisement\n" );
00121
00122
00123
00124
00125
00126
00127
00128 return -ENOENT;
00129 }
00130 DBG ( "Neighbour cache miss: IP6 %s\n", inet6_ntoa ( *dest ) );
00131
00132
00133 add_ndp_entry ( netdev, dest, NULL, NDP_STATE_INCOMPLETE );
00134
00135
00136 if ( ( rc = icmp6_send_solicit ( netdev, src, dest ) ) != 0 ) {
00137 return rc;
00138 }
00139 return -ENOENT;
00140 }
00141
00142
00143
00144
00145
00146
00147
00148
00149 int ndp_process_advert ( struct io_buffer *iobuf, struct sockaddr_tcpip *st_src __unused,
00150 struct sockaddr_tcpip *st_dest __unused ) {
00151 struct neighbour_advert *nadvert = iobuf->data;
00152 struct ndp_entry *ndp;
00153
00154
00155 if ( iob_len ( iobuf ) < sizeof ( *nadvert ) ) {
00156 DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf ) );
00157 return -EINVAL;
00158 }
00159
00160 assert ( nadvert->code == 0 );
00161 assert ( nadvert->flags & ICMP6_FLAGS_SOLICITED );
00162 assert ( nadvert->opt_type == 2 );
00163
00164
00165 ndp = ndp_find_entry ( &nadvert->target );
00166 if ( ndp ) {
00167
00168 assert ( nadvert->opt_len ==
00169 ( ( 2 + ndp->ll_protocol->ll_addr_len ) / 8 ) );
00170
00171 if ( IP6_EQUAL ( ndp->in6, nadvert->target ) ) {
00172 memcpy ( ndp->ll_addr, nadvert->opt_ll_addr,
00173 ndp->ll_protocol->ll_addr_len );
00174 ndp->state = NDP_STATE_REACHABLE;
00175 return 0;
00176 }
00177 }
00178 DBG ( "Unsolicited advertisement (dropping packet)\n" );
00179 return 0;
00180 }