|
|
1.1 root 1: #include <stdint.h>
2: #include <string.h>
3: #include <byteswap.h>
4: #include <errno.h>
5: #include <ipxe/if_ether.h>
6: #include <ipxe/iobuf.h>
7: #include <ipxe/ndp.h>
8: #include <ipxe/icmp6.h>
9: #include <ipxe/ip6.h>
10: #include <ipxe/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 */
22: struct 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 */
37: static struct ndp_entry ndp_table[NUM_NDP_ENTRIES];
38: #define ndp_table_end &ndp_table[NUM_NDP_ENTRIES]
39:
40: static unsigned int next_new_ndp_entry = 0;
41:
42: /**
43: * Find entry in the neighbour cache
44: *
45: * @v in6 IP6 address
46: */
47: static struct ndp_entry *
48: ndp_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: */
68: static void
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];
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: */
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;
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: */
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;
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.