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