|
|
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.