Fixed ICMPv6 & NDP sources - invalid ndp structure
[ZeXOS.git] / kernel / core / net / icmp6.c
blobe21241c5b4bb21f076b25f9a15a1c2a09c10091a
1 /*
2 * ZeX/OS
3 * Copyright (C) 2008 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
4 * Copyright (C) 2009 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
5 * Copyright (C) 2010 Tomas 'ZeXx86' Jedrzejek (zexx86@zexos.org)
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <system.h>
23 #include <string.h>
24 #include <dev.h>
25 #include <net/eth.h>
26 #include <net/net.h>
27 #include <net/if.h>
28 #include <net/packet.h>
29 #include <net/ip.h>
30 #include <net/icmp.h>
31 #include <net/ndp.h>
32 #include <net/tun.h>
33 #include <net/checksum.h>
35 extern unsigned long timer_ticks;
37 static unsigned net_icmp6_ping = 0;
39 static proto_ipv6_t proto_ipv6_prealloc;
40 static char proto_icmp_prealloc[sizeof (proto_icmp_t)+65];
41 static packet_t packet_prealloc;
42 static char buf_icmp_prealloc[NET_PACKET_MTU + sizeof (proto_icmp_t) + 1];
44 /* prototype */
45 unsigned net_proto_icmp6_reply (netif_t *netif, packet_t *packet, proto_ipv6_t *ip, proto_icmp_t *icmp, char *buf, unsigned len);
46 unsigned net_proto_icmp6_request (netif_t *netif, net_ipv6 dest);
48 unsigned net_proto_icmp6_ping (netif_t *netif, net_ipv6 ip)
50 if (!netif)
51 return 2;
53 unsigned ret = net_proto_icmp6_request (netif, ip);
55 if (!ret)
56 return 0;
58 unsigned long time = timer_ticks;
60 while (!net_icmp6_ping) {
61 /* timeout 1s - 1000ms */
62 if ((timer_ticks-time) > 1000)
63 return 0;
65 schedule ();
68 net_icmp6_ping = 0;
70 return 1;
73 unsigned net_proto_icmp6_handler (packet_t *packet, proto_ipv6_t *ip, char *buf, unsigned len)
75 proto_icmp_t *icmp = (proto_icmp_t *) buf;
77 if (icmp->type == NET_ICMP6_TYPE_PING_REQUEST) {
78 //kprintf ("ICMP->Request !\n");
80 /* TODO: melo by to projit vsechny rozhrani */
81 netif_t *netif = netif_findbyname ("eth0");
83 if (net_proto_ipv6_cmp (ip->ip_dest, netif->ipv6))
84 return net_proto_icmp6_reply (netif, packet, ip, icmp, buf+8, len-8);
86 return 0;
89 if (icmp->type == NET_ICMP6_TYPE_PING_REPLY) {
90 /* TODO: make it better :) */
91 net_icmp6_ping = 1;
92 return 1;
95 /* ICMPv6 - NDP protocol handler */
96 if (icmp->type == NET_NDP_TYPE_NBADVERT) {
97 netif_t *netif = netif_findbyname ("eth0");
99 proto_ndp_t *ndp = (proto_ndp_t *) buf;
101 if (net_proto_ipv6_cmp (ip->ip_dest, netif->ipv6))
102 return ndp_cache_add (ndp->ll_mac, ndp->target);
104 return 0;
107 if (icmp->type == NET_NDP_TYPE_NBSOL) {
108 netif_t *netif = netif_findbyname ("eth0");
110 proto_ndp_t *ndp = (proto_ndp_t *) buf;
112 /* send NDP reply */
113 if (net_proto_ipv6_cmp (ndp->target, netif->ipv6)) {
114 ndp_cache_add (ndp->ll_mac, ip->ip_source);
115 return ndp_send_nbreply (netif, ndp->ll_mac, ip->ip_source);
119 if (icmp->type == NET_NDP_TYPE_RADVERT) {
120 netif_t *netif = netif_findbyname ("eth0");
122 proto_icmp_ndp2_t *ndp = (proto_icmp_ndp2_t *) buf;
124 /* send NDP reply */
125 return ndp_send_rreply (netif, ndp, ip->ip_source, ip->ip_dest);
129 return 0;
132 unsigned net_proto_icmp6_request (netif_t *netif, net_ipv6 dest)
134 mac_addr_t mac_dest;
136 if (!tun6_addr_get ()) {
137 unsigned get = ndp_cache_get (dest, &mac_dest);
139 if (!get) {
140 ndp_send_nbrequest (netif, dest);
142 unsigned i = 0;
143 /* 200ms for waiting on NDP reply */
144 while (i < 200) {
145 get = ndp_cache_get (dest, &mac_dest);
147 if (get)
148 break;
150 /* TODO: make better waiting for ARP reply */
151 timer_wait (1);
153 schedule ();
155 i ++;
158 if (!get)
159 return 0;
161 } else {
162 /* IPv6 tunnel stuff */
163 net_ipv4 tunnel = tun6_addr_get ();
164 unsigned get = arp_cache_get (tunnel, &mac_dest);
166 if (!get) {
167 arp_send_request (netif, tunnel);
169 unsigned i = 0;
170 /* 100ms for waiting on ARP reply */
171 while (i < 100) {
172 get = arp_cache_get (tunnel, &mac_dest);
174 if (get)
175 break;
177 /* TODO: make better waiting for ARP reply */
178 timer_wait (1);
180 schedule ();
182 i ++;
185 if (!get)
186 return 0;
190 /* packet header */
191 packet_t *packet = (packet_t *) &packet_prealloc;
193 if (!packet)
194 return 0;
196 memcpy (&packet->mac_source, netif->dev->dev_addr, 6);
197 memcpy (&packet->mac_dest, mac_dest, 6);
198 packet->type = NET_PACKET_TYPE_IPV6;
200 /* ip layer */
201 proto_ipv6_t *ip = (proto_ipv6_t *) &proto_ipv6_prealloc;
203 if (!ip)
204 return 0;
206 /* there are some fixed values - yeah it is horrible */
207 ip->ver = 0x60;
208 ip->tclass = 0x0;
209 ip->flabel = 0x0;
210 ip->pl_len = swap16 (64);
211 ip->nhead = NET_PROTO_IP_TYPE_ICMP6;
212 ip->hop = 0xff;
213 memcpy (ip->ip_source, (void *) netif->ipv6, sizeof (net_ipv6));
214 memcpy (ip->ip_dest, (void *) dest, sizeof (net_ipv6));
216 /* icmp layer */
217 proto_icmp_t *icmp = (proto_icmp_t *) &proto_icmp_prealloc;
219 if (!icmp)
220 return 0;
222 memset ((char *) icmp, 0, 64);
224 icmp->type = NET_ICMP6_TYPE_PING_REQUEST;
225 icmp->code = 0;
226 icmp->seq = 0x3ff3;
228 unsigned ret = 0;
230 icmp->checksum = checksum16_ipv6 (ip->ip_source, ip->ip_dest, icmp, sizeof (proto_icmp_t)+56, NET_PROTO_IP_TYPE_ICMP6);
232 if (!tun6_addr_get ())
233 ret = net_proto_ipv6_send (netif, packet, ip, (char *) icmp, sizeof (proto_icmp_t)+56);
234 else /* tunnel mode */
235 ret = net_proto_tun6_send (netif, packet, ip, (char *) icmp, sizeof (proto_icmp_t)+56);
237 return ret;
240 unsigned net_proto_icmp6_reply (netif_t *netif, packet_t *packet, proto_ipv6_t *ip, proto_icmp_t *icmp, char *buf, unsigned len)
242 mac_addr_t mac_dest;
243 mac_addr_t mac_source;
245 /* cross mac and ip address, because this packet have to go back */
246 memcpy (&mac_dest, packet->mac_source, 6);
247 memcpy (&mac_source, packet->mac_dest, 6);
249 /* assign new values to old structures */
250 memcpy (&packet->mac_source, mac_source, 6);
251 memcpy (&packet->mac_dest, mac_dest, 6);
253 /* TODO: identification, flags, etc */
255 /* ip layer */
256 net_ipv6 tmp;
257 memcpy (tmp, (void *) ip->ip_dest, sizeof (net_ipv6));
259 memcpy (ip->ip_dest, (void *) ip->ip_source, sizeof (net_ipv6));
260 memcpy (ip->ip_source, (void *) tmp, sizeof (net_ipv6));
262 icmp->type = NET_ICMP6_TYPE_PING_REPLY;
263 icmp->checksum = 0;
265 char *buf_icmp = (char *) &buf_icmp_prealloc;
267 if (!buf_icmp)
268 return 0;
270 unsigned l = sizeof (proto_icmp_t);
272 memcpy (buf_icmp, (char *) icmp, l);
273 memcpy (buf_icmp+l, buf, len);
275 buf_icmp[l+len] = '\0';
277 unsigned ret = 0;
279 /* calculate checksum and put it to icmp header */
280 proto_icmp_t *icmp_ = (proto_icmp_t *) buf_icmp;
282 icmp_->checksum = checksum16_ipv6 (ip->ip_source, ip->ip_dest, buf_icmp, len+l, NET_PROTO_IP_TYPE_ICMP6);
284 if (!tun6_addr_get ())
285 ret = net_proto_ipv6_send (netif, packet, ip, buf_icmp, len+l);
286 else
287 ret = net_proto_tun6_send (netif, packet, ip, buf_icmp, len+l);
289 return ret;