7 #include <gpxe/if_ether.h>
8 #include <gpxe/iobuf.h>
10 #include <gpxe/icmp6.h>
11 #include <gpxe/tcpip.h>
12 #include <gpxe/netdevice.h>
14 struct tcpip_protocol icmp6_protocol
;
17 * Send neighbour solicitation packet
19 * @v netdev Network device
20 * @v src Source address
21 * @v dest Destination address
23 * This function prepares a neighbour solicitation packet and sends it to the
26 int icmp6_send_solicit ( struct net_device
*netdev
, struct in6_addr
*src __unused
,
27 struct in6_addr
*dest
) {
29 struct sockaddr_in6 sin6
;
30 struct sockaddr_tcpip st
;
32 struct ll_protocol
*ll_protocol
= netdev
->ll_protocol
;
33 struct neighbour_solicit
*nsolicit
;
34 struct io_buffer
*iobuf
= alloc_iob ( sizeof ( *nsolicit
) + MIN_IOB_LEN
);
35 iob_reserve ( iobuf
, MAX_HDR_LEN
);
36 nsolicit
= iob_put ( iobuf
, sizeof ( *nsolicit
) );
38 /* Fill up the headers */
39 memset ( nsolicit
, 0, sizeof ( *nsolicit
) );
40 nsolicit
->type
= ICMP6_NSOLICIT
;
42 nsolicit
->target
= *dest
;
43 nsolicit
->opt_type
= 1;
44 nsolicit
->opt_len
= ( 2 + ll_protocol
->ll_addr_len
) / 8;
45 memcpy ( nsolicit
->opt_ll_addr
, netdev
->ll_addr
,
46 netdev
->ll_protocol
->ll_addr_len
);
47 /* Partial checksum */
49 nsolicit
->csum
= tcpip_chksum ( nsolicit
, sizeof ( *nsolicit
) );
51 /* Solicited multicast address */
52 st_dest
.sin6
.sin_family
= AF_INET6
;
53 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr8
[0] = 0xff;
54 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr8
[2] = 0x02;
55 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr16
[1] = 0x0000;
56 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr32
[1] = 0x00000000;
57 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr16
[4] = 0x0000;
58 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr16
[5] = 0x0001;
59 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr32
[3] = dest
->in6_u
.u6_addr32
[3];
60 st_dest
.sin6
.sin6_addr
.in6_u
.u6_addr8
[13] = 0xff;
62 /* Send packet over IP6 */
63 return tcpip_tx ( iobuf
, &icmp6_protocol
, NULL
, &st_dest
.st
,
64 NULL
, &nsolicit
->csum
);
68 * Process ICMP6 headers
71 * @v st_src Source address
72 * @v st_dest Destination address
74 static int icmp6_rx ( struct io_buffer
*iobuf
, struct sockaddr_tcpip
*st_src
,
75 struct sockaddr_tcpip
*st_dest
, __unused
uint16_t pshdr_csum
) {
76 struct icmp6_header
*icmp6hdr
= iobuf
->data
;
79 if ( iob_len ( iobuf
) < sizeof ( *icmp6hdr
) ) {
80 DBG ( "Packet too short (%zd bytes)\n", iob_len ( iobuf
) );
85 /* TODO: Verify checksum */
87 /* Process the ICMP header */
88 switch ( icmp6hdr
->type
) {
90 return ndp_process_advert ( iobuf
, st_src
, st_dest
);
96 void icmp6_test_nadvert (struct net_device
*netdev
, struct sockaddr_in6
*server_p
, char *ll_addr
) {
98 struct sockaddr_in6 server
;
99 memcpy ( &server
, server_p
, sizeof ( server
) );
100 struct io_buffer
*rxiobuf
= alloc_iob ( 500 );
101 iob_reserve ( rxiobuf
, MAX_HDR_LEN
);
102 struct neighbour_advert
*nadvert
= iob_put ( rxiobuf
, sizeof ( *nadvert
) );
105 nadvert
->flags
= ICMP6_FLAGS_SOLICITED
;
106 nadvert
->csum
= 0xffff;
107 nadvert
->target
= server
.sin6_addr
;
108 nadvert
->opt_type
= 2;
109 nadvert
->opt_len
= 1;
110 memcpy ( nadvert
->opt_ll_addr
, ll_addr
, 6 );
111 struct ip6_header
*ip6hdr
= iob_push ( rxiobuf
, sizeof ( *ip6hdr
) );
112 ip6hdr
->ver_traffic_class_flow_label
= htonl ( 0x60000000 );
113 ip6hdr
->hop_limit
= 255;
114 ip6hdr
->nxt_hdr
= 58;
115 ip6hdr
->payload_len
= htons ( sizeof ( *nadvert
) );
116 ip6hdr
->src
= server
.sin6_addr
;
117 ip6hdr
->dest
= server
.sin6_addr
;
118 hex_dump ( rxiobuf
->data
, iob_len ( rxiobuf
) );
119 net_rx ( rxiobuf
, netdev
, htons ( ETH_P_IPV6
), ll_addr
);
123 /** ICMP6 protocol */
124 struct tcpip_protocol icmp6_protocol __tcpip_protocol
= {
127 .tcpip_proto
= IP_ICMP6
, // 58