blob: 67609b31f0fee3f205b4f2ffa609a15351413c51 [file] [log] [blame]
hassoca776982004-06-12 14:33:05 +00001/*
2 *
3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Zebra; see the file COPYING. If not, write to the Free
20 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21 * 02111-1307, USA.
22 */
23
24/*
25 * This work includes work with the following copywrite:
26 *
27 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
28 *
29 */
30
31/*
32 * Thanks to Jens Låås at Swedish University of Agricultural Sciences
33 * for reviewing and tests.
34 */
35
36
37#include <zebra.h>
38
39
40#ifdef HAVE_IRDP
41
42#include "if.h"
43#include "vty.h"
44#include "sockunion.h"
45#include "prefix.h"
46#include "command.h"
47#include "memory.h"
48#include "stream.h"
49#include "ioctl.h"
50#include "connected.h"
51#include "log.h"
52#include "zclient.h"
53#include "thread.h"
54#include "zebra/interface.h"
55#include "zebra/rtadv.h"
56#include "zebra/rib.h"
57#include "zebra/zserv.h"
58#include "zebra/redistribute.h"
59#include "zebra/irdp.h"
60#include <netinet/ip_icmp.h>
61#include "if.h"
62#include "sockunion.h"
63#include "log.h"
paul0de1cde2004-08-19 04:45:33 +000064#include "sockopt.h"
hassoca776982004-06-12 14:33:05 +000065
66
67/* GLOBAL VARS */
68
69int irdp_sock;
70char b1[16], b2[16], b3[16], b4[16]; /* For inet_2a */
71
72extern struct zebra_t zebrad;
73extern struct thread *t_irdp_raw;
74extern struct interface *get_iflist_ifp(int idx);
75int in_cksum (void *ptr, int nbytes);
76void process_solicit (struct interface *ifp);
77
78void parse_irdp_packet(char *p,
79 int len,
80 struct interface *ifp)
81{
82 struct ip *ip = (struct ip *)p ;
83 struct icmphdr *icmp;
84 struct in_addr src;
85 int ip_hlen, ip_len;
86 struct zebra_if *zi;
87 struct irdp_interface *irdp;
88
89 zi = ifp->info;
90 if(!zi) return;
91
92 irdp = &zi->irdp;
93 if(!irdp) return;
94
95 ip_hlen = ip->ip_hl*4;
96 ip_len = ntohs(ip->ip_len);
97 len = len - ip_hlen;
98 src = ip->ip_src;
99
100 if(ip_len < ICMP_MINLEN) {
101 zlog_err ("IRDP: RX ICMP packet too short from %s\n",
102 inet_ntoa (src));
103 return;
104 }
105
106 /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
107 len of IP-header) 14+20 */
108
109 if(ip_len > IRDP_RX_BUF-34) {
110 zlog_err ("IRDP: RX ICMP packet too long from %s\n",
111 inet_ntoa (src));
112 return;
113 }
114
115
116 if (in_cksum (ip, ip_len)) {
117 zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
118 inet_ntoa (src));
119 return;
120 }
121
122 icmp = (struct icmphdr *) (p+ip_hlen);
123
124
125 /* Handle just only IRDP */
126
127 if( icmp->type == ICMP_ROUTERADVERT);
128 else if( icmp->type == ICMP_ROUTERSOLICIT);
129 else return;
130
131
132 if (icmp->code != 0) {
133 zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code, silently ignored",
134 icmp->type,
135 inet_ntoa (src));
136 return;
137 }
138
139 if(ip->ip_dst.s_addr == INADDR_BROADCAST &&
140 irdp->flags & IF_BROADCAST);
141
142 else if ( ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP &&
143 ! (irdp->flags & IF_BROADCAST));
144
145 else { /* ERROR */
146
147 zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
148 inet_ntoa (src),
149 ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP?
150 "multicast" : inet_ntoa(ip->ip_dst),
151 ifp->name,
152 irdp->flags & IF_BROADCAST?
153 "broadcast" : "multicast");
154
155 zlog_warn ("IRDP: Please correct settings\n");
156 return;
157 }
158
159 switch (icmp->type)
160 {
161 case ICMP_ROUTERADVERT:
162 break;
163
164 case ICMP_ROUTERSOLICIT:
165
166 if(irdp->flags & IF_DEBUG_MESSAGES)
167 zlog_warn ("IRDP: RX Solicit on %s from %s\n",
168 ifp->name,
169 inet_ntoa (src));
170
171 process_solicit(ifp);
172 break;
173
174 default:
175 zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
176 icmp->type,
177 inet_ntoa (src));
178 }
179}
180
paul0c0f9112004-09-24 08:24:42 +0000181int irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
hassoca776982004-06-12 14:33:05 +0000182{
183 struct msghdr msg;
184 struct iovec iov;
185 struct cmsghdr *ptr;
paul1470baf2004-07-23 15:25:01 +0000186 char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
hassoca776982004-06-12 14:33:05 +0000187 int ret;
188
189 msg.msg_name = (void *)0;
190 msg.msg_namelen = 0;
191 msg.msg_iov = &iov;
192 msg.msg_iovlen = 1;
193 msg.msg_control = (void *) adata;
194 msg.msg_controllen = sizeof adata;
195
196 iov.iov_base = buf;
197 iov.iov_len = size;
198
199 ret = recvmsg (sock, &msg, 0);
200 if (ret < 0) {
201 zlog_warn("IRDP: recvmsg: read error %s", strerror(errno));
202 return ret;
203 }
204
205 if (msg.msg_flags & MSG_TRUNC) {
206 zlog_warn("IRDP: recvmsg: truncated message");
207 return ret;
208 }
209 if (msg.msg_flags & MSG_CTRUNC) {
210 zlog_warn("IRDP: recvmsg: truncated control message");
211 return ret;
212 }
213
paul0c0f9112004-09-24 08:24:42 +0000214 *ifindex = getsockopt_ifindex (AF_INET, &msg);
paul1470baf2004-07-23 15:25:01 +0000215
hassoca776982004-06-12 14:33:05 +0000216 return ret;
217}
218
219int irdp_read_raw(struct thread *r)
220{
221 struct interface *ifp;
222 struct zebra_if *zi;
223 struct irdp_interface *irdp;
224 char buf[IRDP_RX_BUF];
225 int ret, ifindex;
226
227 int irdp_sock = THREAD_FD (r);
228 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
229
hassoc9e52be2004-09-26 16:09:34 +0000230 ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex);
hassoca776982004-06-12 14:33:05 +0000231
232 if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
233
234 ifp = get_iflist_ifp(ifindex);
235 if(! ifp ) return ret;
236
237 zi= ifp->info;
238 if(! zi ) return ret;
239
240 irdp = &zi->irdp;
241 if(! irdp ) return ret;
242
243 if(! (irdp->flags & IF_ACTIVE)) {
244
245 if(irdp->flags & IF_DEBUG_MISC)
246 zlog_warn("IRDP: RX ICMP for disabled interface %s\n",
247 ifp->name);
248 return 0;
249 }
250
251 if(irdp->flags & IF_DEBUG_PACKET) {
252 int i;
253 zlog_warn("IRDP: RX (idx %d) ", ifindex);
254 for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF);
255 }
256
257 parse_irdp_packet(buf, ret, ifp);
258 return ret;
259}
260
261void send_packet(struct interface *ifp,
262 struct stream *s,
263 u_int32_t dst,
264 struct prefix *p,
265 u_int32_t ttl)
266{
267 static struct sockaddr_in sockdst = {AF_INET};
268 struct ip *ip;
269 struct icmphdr *icmp;
270 struct msghdr *msg;
271 struct cmsghdr *cmsg;
272 struct iovec iovector;
273 char msgbuf[256];
274 char buf[256];
275 struct in_pktinfo *pktinfo;
276 u_long src;
277 int on;
278
279 if (! (ifp->flags & IFF_UP)) return;
280
281 if(!p) src = ntohl(p->u.prefix4.s_addr);
282 else src = 0; /* Is filled in */
283
284 ip = (struct ip *) buf;
285 ip->ip_hl = sizeof(struct ip) >> 2;
286 ip->ip_v = IPVERSION;
287 ip->ip_tos = 0xC0;
288 ip->ip_off = 0L;
289 ip->ip_p = 1; /* IP_ICMP */
290 ip->ip_ttl = ttl;
291 ip->ip_src.s_addr = src;
292 ip->ip_dst.s_addr = dst;
293 icmp = (struct icmphdr *) (buf + 20);
294
295 /* Merge IP header with icmp packet */
296
297 stream_get(icmp, s, s->putp);
298
299 /* icmp->checksum is already calculated */
300 ip->ip_len = sizeof(struct ip) + s->putp;
301 stream_free(s);
302
303 on = 1;
304 if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
305 (char *) &on, sizeof(on)) < 0)
306 zlog_warn("sendto %s", strerror (errno));
307
308
309 if(dst == INADDR_BROADCAST ) {
310 on = 1;
311 if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
312 (char *) &on, sizeof(on)) < 0)
313 zlog_warn("sendto %s", strerror (errno));
314 }
315
316 if(dst != INADDR_BROADCAST) {
317 on = 0;
318 if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
319 (char *)&on,sizeof(on)) < 0)
320 zlog_warn("sendto %s", strerror (errno));
321 }
322
323 bzero(&sockdst,sizeof(sockdst));
324 sockdst.sin_family=AF_INET;
325 sockdst.sin_addr.s_addr = dst;
326
327 cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
328 cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
329 cmsg->cmsg_level = SOL_IP;
330 cmsg->cmsg_type = IP_PKTINFO;
331 pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
332 pktinfo->ipi_ifindex = ifp->ifindex;
333 pktinfo->ipi_spec_dst.s_addr = src;
334 pktinfo->ipi_addr.s_addr = src;
335
336 iovector.iov_base = (void *) buf;
337 iovector.iov_len = ip->ip_len;
338 msg = (struct msghdr *) msgbuf;
339 msg->msg_name = &sockdst;
340 msg->msg_namelen = sizeof(sockdst);
341 msg->msg_iov = &iovector;
342 msg->msg_iovlen = 1;
343 msg->msg_control = cmsg;
344 msg->msg_controllen = cmsg->cmsg_len;
345
346 if (sendmsg(irdp_sock, msg, 0) < 0) {
347 zlog_warn("sendto %s", strerror (errno));
348 }
349 /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
350}
351
352
353#endif /* HAVE_IRDP */
354
355
356