]> git.proxmox.com Git - mirror_frr.git/blame - zebra/irdp_packet.c
isisd: implement the 'lsp-too-large' notification
[mirror_frr.git] / zebra / irdp_packet.c
CommitLineData
ca776988 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 *
896014f4
DL
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
ca776988 21 */
22
d62a17ae 23/*
ca776988 24 * This work includes work with the following copywrite:
25 *
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
27 *
28 */
29
d62a17ae 30/*
43e52561 31 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
ca776988 32 * for reviewing and tests.
33 */
34
35
36#include <zebra.h>
43e52561 37#include <netinet/ip_icmp.h>
ca776988 38
43e52561 39#include "checksum.h"
ca776988 40#include "command.h"
ca776988 41#include "connected.h"
43e52561
QY
42#include "if.h"
43#include "ioctl.h"
ca776988 44#include "log.h"
43e52561
QY
45#include "log.h"
46#include "memory.h"
47#include "prefix.h"
48#include "sockopt.h"
49#include "sockunion.h"
50#include "sockunion.h"
51#include "stream.h"
ca776988 52#include "thread.h"
43e52561
QY
53#include "vty.h"
54#include "zclient.h"
9df414fe 55#include "lib_errors.h"
43e52561
QY
56
57#include "zebra_memory.h"
ca776988 58#include "zebra/interface.h"
59#include "zebra/rtadv.h"
60#include "zebra/rib.h"
61#include "zebra/zserv.h"
62#include "zebra/redistribute.h"
63#include "zebra/irdp.h"
43e52561 64#include "zebra/zebra_errors.h"
ca776988 65
66
67/* GLOBAL VARS */
68
2da40f49 69int irdp_sock = -1;
ca776988 70
ca776988 71extern struct thread *t_irdp_raw;
ca776988 72
d62a17ae 73static void parse_irdp_packet(char *p, int len, struct interface *ifp)
ca776988 74{
d62a17ae 75 struct ip *ip = (struct ip *)p;
76 struct icmphdr *icmp;
77 struct in_addr src;
78 int ip_hlen, iplen, datalen;
79 struct zebra_if *zi;
80 struct irdp_interface *irdp;
81
82 zi = ifp->info;
83 if (!zi)
84 return;
85
ead4ee99 86 irdp = zi->irdp;
d62a17ae 87 if (!irdp)
88 return;
89
90 ip_hlen = ip->ip_hl << 2;
91
92 sockopt_iphdrincl_swab_systoh(ip);
93
94 iplen = ip->ip_len;
95 datalen = len - ip_hlen;
96 src = ip->ip_src;
97
98 if (len != iplen) {
e914ccbe 99 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
0437e105 100 "IRDP: RX length doesn't match IP length");
d62a17ae 101 return;
102 }
103
104 if (iplen < ICMP_MINLEN) {
e914ccbe 105 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
1c50c1c0
QY
106 "IRDP: RX ICMP packet too short from %s\n",
107 inet_ntoa(src));
d62a17ae 108 return;
109 }
110
0437e105 111 /* XXX: RAW doesn't receive link-layer, surely? ??? */
d62a17ae 112 /* Check so we don't checksum packets longer than oure RX_BUF - (ethlen
113 +
114 len of IP-header) 14+20 */
115 if (iplen > IRDP_RX_BUF - 34) {
e914ccbe 116 flog_err(EC_ZEBRA_IRDP_LEN_MISMATCH,
1c50c1c0
QY
117 "IRDP: RX ICMP packet too long from %s\n",
118 inet_ntoa(src));
d62a17ae 119 return;
120 }
121
122 icmp = (struct icmphdr *)(p + ip_hlen);
123
124 /* check icmp checksum */
125 if (in_cksum(icmp, datalen) != icmp->checksum) {
9df414fe 126 flog_warn(
e914ccbe 127 EC_ZEBRA_IRDP_BAD_CHECKSUM,
d62a17ae 128 "IRDP: RX ICMP packet from %s. Bad checksum, silently ignored",
129 inet_ntoa(src));
130 return;
131 }
132
133 /* Handle just only IRDP */
134 if (!(icmp->type == ICMP_ROUTERADVERT
135 || icmp->type == ICMP_ROUTERSOLICIT))
136 return;
137
138 if (icmp->code != 0) {
e914ccbe 139 flog_warn(EC_ZEBRA_IRDP_BAD_TYPE_CODE,
9df414fe
QY
140 "IRDP: RX packet type %d from %s. Bad ICMP type code,"
141 " silently ignored",
142 icmp->type, inet_ntoa(src));
d62a17ae 143 return;
144 }
145
146 if (!((ntohl(ip->ip_dst.s_addr) == INADDR_BROADCAST)
147 && (irdp->flags & IF_BROADCAST))
148 || (ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
149 && !(irdp->flags & IF_BROADCAST))) {
9df414fe 150 flog_warn(
e914ccbe 151 EC_ZEBRA_IRDP_BAD_RX_FLAGS,
9df414fe 152 "IRDP: RX illegal from %s to %s while %s operates in %s; Please correct settings\n",
d62a17ae 153 inet_ntoa(src),
154 ntohl(ip->ip_dst.s_addr) == INADDR_ALLRTRS_GROUP
155 ? "multicast"
156 : inet_ntoa(ip->ip_dst),
157 ifp->name,
158 irdp->flags & IF_BROADCAST ? "broadcast" : "multicast");
d62a17ae 159 return;
160 }
161
162 switch (icmp->type) {
163 case ICMP_ROUTERADVERT:
164 break;
165
166 case ICMP_ROUTERSOLICIT:
167
168 if (irdp->flags & IF_DEBUG_MESSAGES)
169 zlog_debug("IRDP: RX Solicit on %s from %s\n",
170 ifp->name, inet_ntoa(src));
171
172 process_solicit(ifp);
173 break;
174
175 default:
9df414fe 176 flog_warn(
e914ccbe 177 EC_ZEBRA_IRDP_BAD_TYPE,
d62a17ae 178 "IRDP: RX type %d from %s. Bad ICMP type, silently ignored",
179 icmp->type, inet_ntoa(src));
180 }
ca776988 181}
6b0655a2 182
d7c0a89a 183static int irdp_recvmsg(int sock, uint8_t *buf, int size, int *ifindex)
ca776988 184{
d62a17ae 185 struct msghdr msg;
186 struct iovec iov;
187 char adata[CMSG_SPACE(SOPT_SIZE_CMSG_PKTINFO_IPV4())];
188 int ret;
189
0af35d90 190 memset(&msg, 0, sizeof(msg));
d62a17ae 191 msg.msg_name = (void *)0;
192 msg.msg_namelen = 0;
193 msg.msg_iov = &iov;
194 msg.msg_iovlen = 1;
195 msg.msg_control = (void *)adata;
196 msg.msg_controllen = sizeof adata;
197
198 iov.iov_base = buf;
199 iov.iov_len = size;
200
201 ret = recvmsg(sock, &msg, 0);
202 if (ret < 0) {
450971aa 203 flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: read error %s",
9df414fe 204 safe_strerror(errno));
d62a17ae 205 return ret;
206 }
207
208 if (msg.msg_flags & MSG_TRUNC) {
450971aa 209 flog_warn(EC_LIB_SOCKET, "IRDP: recvmsg: truncated message");
d62a17ae 210 return ret;
211 }
212 if (msg.msg_flags & MSG_CTRUNC) {
450971aa 213 flog_warn(EC_LIB_SOCKET,
9df414fe 214 "IRDP: recvmsg: truncated control message");
d62a17ae 215 return ret;
216 }
217
218 *ifindex = getsockopt_ifindex(AF_INET, &msg);
219
220 return ret;
ca776988 221}
6b0655a2 222
ca776988 223int irdp_read_raw(struct thread *r)
224{
d62a17ae 225 struct interface *ifp;
226 struct zebra_if *zi;
227 struct irdp_interface *irdp;
228 char buf[IRDP_RX_BUF];
229 int ret, ifindex = 0;
230
231 int irdp_sock = THREAD_FD(r);
232 t_irdp_raw = NULL;
233 thread_add_read(zebrad.master, irdp_read_raw, NULL, irdp_sock,
234 &t_irdp_raw);
235
d7c0a89a 236 ret = irdp_recvmsg(irdp_sock, (uint8_t *)buf, IRDP_RX_BUF, &ifindex);
d62a17ae 237
238 if (ret < 0)
450971aa 239 flog_warn(EC_LIB_SOCKET, "IRDP: RX Error length = %d", ret);
d62a17ae 240
241 ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
242 if (!ifp)
243 return ret;
244
245 zi = ifp->info;
246 if (!zi)
247 return ret;
248
ead4ee99 249 irdp = zi->irdp;
d62a17ae 250 if (!irdp)
251 return ret;
252
253 if (!(irdp->flags & IF_ACTIVE)) {
254
255 if (irdp->flags & IF_DEBUG_MISC)
256 zlog_debug("IRDP: RX ICMP for disabled interface %s\n",
257 ifp->name);
258 return 0;
259 }
260
261 if (irdp->flags & IF_DEBUG_PACKET) {
262 int i;
263 zlog_debug("IRDP: RX (idx %d) ", ifindex);
264 for (i = 0; i < ret; i++)
265 zlog_debug("IRDP: RX %x ", buf[i] & 0xFF);
266 }
267
268 parse_irdp_packet(buf, ret, ifp);
269
270 return ret;
ca776988 271}
6b0655a2 272
d7c0a89a
QY
273void send_packet(struct interface *ifp, struct stream *s, uint32_t dst,
274 struct prefix *p, uint32_t ttl)
ca776988 275{
d62a17ae 276 static struct sockaddr_in sockdst = {AF_INET};
277 struct ip *ip;
278 struct icmphdr *icmp;
279 struct msghdr *msg;
280 struct cmsghdr *cmsg;
281 struct iovec iovector;
282 char msgbuf[256];
283 char buf[256];
284 struct in_pktinfo *pktinfo;
d7c0a89a
QY
285 unsigned long src;
286 uint8_t on;
d62a17ae 287
288 if (!(ifp->flags & IFF_UP))
289 return;
290
291 if (p)
292 src = ntohl(p->u.prefix4.s_addr);
293 else
294 src = 0; /* Is filled in */
295
296 ip = (struct ip *)buf;
297 ip->ip_hl = sizeof(struct ip) >> 2;
298 ip->ip_v = IPVERSION;
299 ip->ip_tos = 0xC0;
300 ip->ip_off = 0L;
301 ip->ip_p = 1; /* IP_ICMP */
302 ip->ip_ttl = ttl;
303 ip->ip_src.s_addr = src;
304 ip->ip_dst.s_addr = dst;
305 icmp = (struct icmphdr *)(buf + sizeof(struct ip));
306
307 /* Merge IP header with icmp packet */
308 assert(stream_get_endp(s) < (sizeof(buf) - sizeof(struct ip)));
309 stream_get(icmp, s, stream_get_endp(s));
310
311 /* icmp->checksum is already calculated */
312 ip->ip_len = sizeof(struct ip) + stream_get_endp(s);
313
314 on = 1;
315 if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on,
316 sizeof(on))
317 < 0)
9df414fe 318 zlog_debug("sendto %s", safe_strerror(errno));
d62a17ae 319
320
321 if (dst == INADDR_BROADCAST) {
322 on = 1;
323 if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, (char *)&on,
324 sizeof(on))
325 < 0)
9df414fe 326 zlog_debug("sendto %s", safe_strerror(errno));
d62a17ae 327 }
328
329 if (dst != INADDR_BROADCAST)
330 setsockopt_ipv4_multicast_loop(irdp_sock, 0);
331
332 memset(&sockdst, 0, sizeof(sockdst));
333 sockdst.sin_family = AF_INET;
334 sockdst.sin_addr.s_addr = dst;
335
336 cmsg = (struct cmsghdr *)(msgbuf + sizeof(struct msghdr));
337 cmsg->cmsg_len = sizeof(struct cmsghdr) + sizeof(struct in_pktinfo);
338 cmsg->cmsg_level = SOL_IP;
339 cmsg->cmsg_type = IP_PKTINFO;
340 pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
341 pktinfo->ipi_ifindex = ifp->ifindex;
342 pktinfo->ipi_spec_dst.s_addr = src;
343 pktinfo->ipi_addr.s_addr = src;
344
345 iovector.iov_base = (void *)buf;
346 iovector.iov_len = ip->ip_len;
347 msg = (struct msghdr *)msgbuf;
348 msg->msg_name = &sockdst;
349 msg->msg_namelen = sizeof(sockdst);
350 msg->msg_iov = &iovector;
351 msg->msg_iovlen = 1;
352 msg->msg_control = cmsg;
353 msg->msg_controllen = cmsg->cmsg_len;
354
355 sockopt_iphdrincl_swab_htosys(ip);
356
357 if (sendmsg(irdp_sock, msg, 0) < 0) {
9df414fe 358 zlog_debug("sendto %s", safe_strerror(errno));
d62a17ae 359 }
360 /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */
ca776988 361}