]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_main.c
*: reindent
[mirror_frr.git] / zebra / irdp_main.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 #ifdef HAVE_IRDP
40
41 #include "if.h"
42 #include "vty.h"
43 #include "sockunion.h"
44 #include "sockopt.h"
45 #include "prefix.h"
46 #include "command.h"
47 #include "memory.h"
48 #include "zebra_memory.h"
49 #include "stream.h"
50 #include "ioctl.h"
51 #include "connected.h"
52 #include "log.h"
53 #include "zclient.h"
54 #include "thread.h"
55 #include "privs.h"
56 #include "zebra/interface.h"
57 #include "zebra/rtadv.h"
58 #include "zebra/rib.h"
59 #include "zebra/zserv.h"
60 #include "zebra/redistribute.h"
61 #include "zebra/irdp.h"
62 #include <netinet/ip_icmp.h>
63
64 #include "checksum.h"
65 #include "if.h"
66 #include "sockunion.h"
67 #include "log.h"
68
69 /* GLOBAL VARS */
70
71 extern struct zebra_privs_t zserv_privs;
72
73 struct thread *t_irdp_raw;
74
75 /* Timer interval of irdp. */
76 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
77
78 int irdp_sock_init(void)
79 {
80 int ret, i;
81 int save_errno;
82 int sock;
83
84 if (zserv_privs.change(ZPRIVS_RAISE))
85 zlog_err("irdp_sock_init: could not raise privs, %s",
86 safe_strerror(errno));
87
88 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
89 save_errno = errno;
90
91 if (zserv_privs.change(ZPRIVS_LOWER))
92 zlog_err("irdp_sock_init: could not lower privs, %s",
93 safe_strerror(errno));
94
95 if (sock < 0) {
96 zlog_warn("IRDP: can't create irdp socket %s",
97 safe_strerror(save_errno));
98 return sock;
99 };
100
101 i = 1;
102 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&i, sizeof(i));
103 if (ret < 0) {
104 zlog_warn("IRDP: can't do irdp sockopt %s",
105 safe_strerror(errno));
106 close(sock);
107 return ret;
108 };
109
110 ret = setsockopt_ifindex(AF_INET, sock, 1);
111 if (ret < 0) {
112 zlog_warn("IRDP: can't do irdp sockopt %s",
113 safe_strerror(errno));
114 close(sock);
115 return ret;
116 };
117
118 t_irdp_raw = thread_add_read(zebrad.master, irdp_read_raw, NULL, sock);
119
120 return sock;
121 }
122
123
124 static int get_pref(struct irdp_interface *irdp, struct prefix *p)
125 {
126 struct listnode *node;
127 struct Adv *adv;
128
129 /* Use default preference or use the override pref */
130
131 if (irdp->AdvPrefList == NULL)
132 return irdp->Preference;
133
134 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
135 if (p->u.prefix4.s_addr == adv->ip.s_addr)
136 return adv->pref;
137
138 return irdp->Preference;
139 }
140
141 /* Make ICMP Router Advertisement Message. */
142 static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
143 struct stream *s)
144 {
145 struct zebra_if *zi = ifp->info;
146 struct irdp_interface *irdp = &zi->irdp;
147 int size;
148 int pref;
149 u_int16_t checksum;
150
151 pref = get_pref(irdp, p);
152
153 stream_putc(s, ICMP_ROUTERADVERT); /* Type. */
154 stream_putc(s, 0); /* Code. */
155 stream_putw(s, 0); /* Checksum. */
156 stream_putc(s, 1); /* Num address. */
157 stream_putc(s, 2); /* Address Entry Size. */
158
159 if (irdp->flags & IF_SHUTDOWN)
160 stream_putw(s, 0);
161 else
162 stream_putw(s, irdp->Lifetime);
163
164 stream_putl(s, htonl(p->u.prefix4.s_addr)); /* Router address. */
165 stream_putl(s, pref);
166
167 /* in_cksum return network byte order value */
168 size = 16;
169 checksum = in_cksum(s->data, size);
170 stream_putw_at(s, 2, htons(checksum));
171
172 return size;
173 }
174
175 static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
176 {
177 struct zebra_if *zi = ifp->info;
178 struct irdp_interface *irdp = &zi->irdp;
179 char buf[PREFIX_STRLEN];
180 u_int32_t dst;
181 u_int32_t ttl = 1;
182
183 if (!(ifp->flags & IFF_UP))
184 return;
185
186 if (irdp->flags & IF_BROADCAST)
187 dst = INADDR_BROADCAST;
188 else
189 dst = htonl(INADDR_ALLHOSTS_GROUP);
190
191 if (irdp->flags & IF_DEBUG_MESSAGES)
192 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
193 ifp->name, prefix2str(p, buf, sizeof buf),
194 irdp->flags & IF_SHUTDOWN ? 0 : irdp->Lifetime,
195 get_pref(irdp, p));
196
197 send_packet(ifp, s, dst, p, ttl);
198 }
199
200 static void irdp_advertisement(struct interface *ifp, struct prefix *p)
201 {
202 struct stream *s;
203 s = stream_new(128);
204 make_advertisement_packet(ifp, p, s);
205 irdp_send(ifp, p, s);
206 stream_free(s);
207 }
208
209 int irdp_send_thread(struct thread *t_advert)
210 {
211 u_int32_t timer, tmp;
212 struct interface *ifp = THREAD_ARG(t_advert);
213 struct zebra_if *zi = ifp->info;
214 struct irdp_interface *irdp = &zi->irdp;
215 struct prefix *p;
216 struct listnode *node, *nnode;
217 struct connected *ifc;
218
219 irdp->flags &= ~IF_SOLICIT;
220
221 if (ifp->connected)
222 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
223 p = ifc->address;
224
225 if (p->family != AF_INET)
226 continue;
227
228 irdp_advertisement(ifp, p);
229 irdp->irdp_sent++;
230 }
231
232 tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
233 timer = random() % (tmp + 1);
234 timer = irdp->MinAdvertInterval + timer;
235
236 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
237 && timer > MAX_INITIAL_ADVERT_INTERVAL)
238 timer = MAX_INITIAL_ADVERT_INTERVAL;
239
240 if (irdp->flags & IF_DEBUG_MISC)
241 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name,
242 timer);
243
244 irdp->t_advertise =
245 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
246 return 0;
247 }
248
249 void irdp_advert_off(struct interface *ifp)
250 {
251 struct zebra_if *zi = ifp->info;
252 struct irdp_interface *irdp = &zi->irdp;
253 struct listnode *node, *nnode;
254 int i;
255 struct connected *ifc;
256 struct prefix *p;
257
258 if (irdp->t_advertise)
259 thread_cancel(irdp->t_advertise);
260 irdp->t_advertise = NULL;
261
262 if (ifp->connected)
263 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
264 p = ifc->address;
265
266 /* Output some packets with Lifetime 0
267 we should add a wait...
268 */
269
270 for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) {
271 irdp->irdp_sent++;
272 irdp_advertisement(ifp, p);
273 }
274 }
275 }
276
277
278 void process_solicit(struct interface *ifp)
279 {
280 struct zebra_if *zi = ifp->info;
281 struct irdp_interface *irdp = &zi->irdp;
282 u_int32_t timer;
283
284 /* When SOLICIT is active we reject further incoming solicits
285 this keeps down the answering rate so we don't have think
286 about DoS attacks here. */
287
288 if (irdp->flags & IF_SOLICIT)
289 return;
290
291 irdp->flags |= IF_SOLICIT;
292 if (irdp->t_advertise)
293 thread_cancel(irdp->t_advertise);
294 irdp->t_advertise = NULL;
295
296 timer = (random() % MAX_RESPONSE_DELAY) + 1;
297
298 irdp->t_advertise =
299 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer);
300 }
301
302 void irdp_finish()
303 {
304 struct vrf *vrf;
305 struct listnode *node, *nnode;
306 struct interface *ifp;
307 struct zebra_if *zi;
308 struct irdp_interface *irdp;
309
310 zlog_info("IRDP: Received shutdown notification.");
311
312 RB_FOREACH(vrf, vrf_id_head, &vrfs_by_id)
313 for (ALL_LIST_ELEMENTS(vrf->iflist, node, nnode, ifp)) {
314 zi = ifp->info;
315
316 if (!zi)
317 continue;
318 irdp = &zi->irdp;
319 if (!irdp)
320 continue;
321
322 if (irdp->flags & IF_ACTIVE) {
323 irdp->flags |= IF_SHUTDOWN;
324 irdp_advert_off(ifp);
325 }
326 }
327 }
328
329 #endif /* HAVE_IRDP */