]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_packet.c
2004-11-19 Andrew J. Schorr <ajschorr@alumni.princeton.edu>
[mirror_frr.git] / zebra / irdp_packet.c
1 /*
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"
64 #include "sockopt.h"
65
66
67 /* GLOBAL VARS */
68
69 int irdp_sock;
70 char b1[16], b2[16], b3[16], b4[16]; /* For inet_2a */
71
72 extern struct zebra_t zebrad;
73 extern struct thread *t_irdp_raw;
74 extern struct interface *get_iflist_ifp(int idx);
75 int in_cksum (void *ptr, int nbytes);
76 void process_solicit (struct interface *ifp);
77
78 void 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, iplen, datalen;
86 struct zebra_if *zi;
87 struct irdp_interface *irdp;
88
89 zi = ifp->info;
90 if (!zi)
91 return;
92
93 irdp = &zi->irdp;
94 if (!irdp)
95 return;
96
97 ip_hlen = ip->ip_hl << 2;
98
99 sockopt_iphdrincl_swab_systoh (ip);
100
101 iplen = ip->ip_len;
102 datalen = len - ip_hlen;
103 src = ip->ip_src;
104
105 if (len != iplen)
106 {
107 zlog_err ("IRDP: RX length doesnt match IP length");
108 return;
109 }
110
111 if (iplen < ICMP_MINLEN)
112 {
113 zlog_err ("IRDP: RX ICMP packet too short from %s\n",
114 inet_ntoa (src));
115 return;
116 }
117
118 /* XXX: RAW doesnt receive link-layer, surely? ??? */
119 /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen +
120 len of IP-header) 14+20 */
121 if (iplen > IRDP_RX_BUF-34)
122 {
123 zlog_err ("IRDP: RX ICMP packet too long from %s\n",
124 inet_ntoa (src));
125 return;
126 }
127
128 icmp = (struct icmphdr *) (p+ip_hlen);
129
130 /* check icmp checksum */
131 if (in_cksum (icmp, datalen) != icmp->checksum)
132 {
133 zlog_warn ("IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
134 inet_ntoa (src));
135 return;
136 }
137
138 /* Handle just only IRDP */
139 if (!(icmp->type == ICMP_ROUTERADVERT
140 || icmp->type == ICMP_ROUTERSOLICIT))
141 return;
142
143 if (icmp->code != 0)
144 {
145 zlog_warn ("IRDP: RX packet type %d from %s. Bad ICMP type code,"
146 " silently ignored",
147 icmp->type, inet_ntoa (src));
148 return;
149 }
150
151 if (! ((ntohl (ip->ip_dst.s_addr) == INADDR_BROADCAST)
152 && (irdp->flags & IF_BROADCAST))
153 ||
154 (ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
155 && !(irdp->flags & IF_BROADCAST)))
156 {
157 zlog_warn ("IRDP: RX illegal from %s to %s while %s operates in %s\n",
158 inet_ntoa (src),
159 ntohl (ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP ?
160 "multicast" : inet_ntoa (ip->ip_dst),
161 ifp->name,
162 irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
163
164 zlog_warn ("IRDP: Please correct settings\n");
165 return;
166 }
167
168 switch (icmp->type)
169 {
170 case ICMP_ROUTERADVERT:
171 break;
172
173 case ICMP_ROUTERSOLICIT:
174
175 if(irdp->flags & IF_DEBUG_MESSAGES)
176 zlog_warn ("IRDP: RX Solicit on %s from %s\n",
177 ifp->name,
178 inet_ntoa (src));
179
180 process_solicit(ifp);
181 break;
182
183 default:
184 zlog_warn ("IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
185 icmp->type,
186 inet_ntoa (src));
187 }
188 }
189 \f
190 int irdp_recvmsg (int sock, u_char *buf, int size, int *ifindex)
191 {
192 struct msghdr msg;
193 struct iovec iov;
194 char adata[CMSG_SPACE( SOPT_SIZE_CMSG_PKTINFO_IPV4() )];
195 int ret;
196
197 msg.msg_name = (void *)0;
198 msg.msg_namelen = 0;
199 msg.msg_iov = &iov;
200 msg.msg_iovlen = 1;
201 msg.msg_control = (void *) adata;
202 msg.msg_controllen = sizeof adata;
203
204 iov.iov_base = buf;
205 iov.iov_len = size;
206
207 ret = recvmsg (sock, &msg, 0);
208 if (ret < 0) {
209 zlog_warn("IRDP: recvmsg: read error %s", safe_strerror(errno));
210 return ret;
211 }
212
213 if (msg.msg_flags & MSG_TRUNC) {
214 zlog_warn("IRDP: recvmsg: truncated message");
215 return ret;
216 }
217 if (msg.msg_flags & MSG_CTRUNC) {
218 zlog_warn("IRDP: recvmsg: truncated control message");
219 return ret;
220 }
221
222 *ifindex = getsockopt_ifindex (AF_INET, &msg);
223
224 return ret;
225 }
226 \f
227 int irdp_read_raw(struct thread *r)
228 {
229 struct interface *ifp;
230 struct zebra_if *zi;
231 struct irdp_interface *irdp;
232 char buf[IRDP_RX_BUF];
233 int ret, ifindex;
234
235 int irdp_sock = THREAD_FD (r);
236 t_irdp_raw = thread_add_read (zebrad.master, irdp_read_raw, NULL, irdp_sock);
237
238 ret = irdp_recvmsg (irdp_sock, (u_char *) buf, IRDP_RX_BUF, &ifindex);
239
240 if (ret < 0) zlog_warn ("IRDP: RX Error length = %d", ret);
241
242 ifp = get_iflist_ifp(ifindex);
243 if(! ifp ) return ret;
244
245 zi= ifp->info;
246 if(! zi ) return ret;
247
248 irdp = &zi->irdp;
249 if(! irdp ) return ret;
250
251 if(! (irdp->flags & IF_ACTIVE)) {
252
253 if(irdp->flags & IF_DEBUG_MISC)
254 zlog_warn("IRDP: RX ICMP for disabled interface %s\n",
255 ifp->name);
256 return 0;
257 }
258
259 if(irdp->flags & IF_DEBUG_PACKET) {
260 int i;
261 zlog_warn("IRDP: RX (idx %d) ", ifindex);
262 for(i=0; i < ret; i++) zlog_warn( "IRDP: RX %x ", buf[i]&0xFF);
263 }
264
265 parse_irdp_packet(buf, ret, ifp);
266
267 return ret;
268 }
269 \f
270 void
271 send_packet(struct interface *ifp,
272 struct stream *s,
273 u_int32_t dst,
274 struct prefix *p,
275 u_int32_t ttl)
276 {
277 static struct sockaddr_in sockdst = {AF_INET};
278 struct ip *ip;
279 struct icmphdr *icmp;
280 struct msghdr *msg;
281 struct cmsghdr *cmsg;
282 struct iovec iovector;
283 char msgbuf[256];
284 char buf[256];
285 struct in_pktinfo *pktinfo;
286 u_long src;
287 int on;
288
289 if (!(ifp->flags & IFF_UP))
290 return;
291
292 if (!p)
293 src = ntohl(p->u.prefix4.s_addr);
294 else
295 src = 0; /* Is filled in */
296
297 ip = (struct ip *) buf;
298 ip->ip_hl = sizeof(struct ip) >> 2;
299 ip->ip_v = IPVERSION;
300 ip->ip_tos = 0xC0;
301 ip->ip_off = 0L;
302 ip->ip_p = 1; /* IP_ICMP */
303 ip->ip_ttl = ttl;
304 ip->ip_src.s_addr = src;
305 ip->ip_dst.s_addr = dst;
306 icmp = (struct icmphdr *) (buf + sizeof (struct ip));
307
308 /* Merge IP header with icmp packet */
309
310 stream_get(icmp, s, s->putp);
311
312 /* icmp->checksum is already calculated */
313 ip->ip_len = sizeof(struct ip) + s->putp;
314 stream_free(s);
315
316 on = 1;
317 if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL,
318 (char *) &on, sizeof(on)) < 0)
319 zlog_warn("sendto %s", safe_strerror (errno));
320
321
322 if(dst == INADDR_BROADCAST ) {
323 on = 1;
324 if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST,
325 (char *) &on, sizeof(on)) < 0)
326 zlog_warn("sendto %s", safe_strerror (errno));
327 }
328
329 if(dst != INADDR_BROADCAST) {
330 on = 0;
331 if( setsockopt(irdp_sock,IPPROTO_IP, IP_MULTICAST_LOOP,
332 (char *)&on,sizeof(on)) < 0)
333 zlog_warn("sendto %s", safe_strerror (errno));
334 }
335
336 bzero(&sockdst,sizeof(sockdst));
337 sockdst.sin_family=AF_INET;
338 sockdst.sin_addr.s_addr = dst;
339
340 cmsg = (struct cmsghdr *) (msgbuf + sizeof(struct msghdr));
341 cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
342 cmsg->cmsg_level = SOL_IP;
343 cmsg->cmsg_type = IP_PKTINFO;
344 pktinfo = (struct in_pktinfo *) CMSG_DATA(cmsg);
345 pktinfo->ipi_ifindex = ifp->ifindex;
346 pktinfo->ipi_spec_dst.s_addr = src;
347 pktinfo->ipi_addr.s_addr = src;
348
349 iovector.iov_base = (void *) buf;
350 iovector.iov_len = ip->ip_len;
351 msg = (struct msghdr *) msgbuf;
352 msg->msg_name = &sockdst;
353 msg->msg_namelen = sizeof(sockdst);
354 msg->msg_iov = &iovector;
355 msg->msg_iovlen = 1;
356 msg->msg_control = cmsg;
357 msg->msg_controllen = cmsg->cmsg_len;
358
359 sockopt_iphdrincl_swab_htosys (ip);
360
361 if (sendmsg(irdp_sock, msg, 0) < 0) {
362 zlog_warn("sendto %s", safe_strerror (errno));
363 }
364 /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
365 }
366
367
368 #endif /* HAVE_IRDP */
369
370
371