]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_register.c
pimd: Fix some static analysis
[mirror_frr.git] / pimd / pim_register.c
1 /*
2 * PIM for Quagga
3 * Copyright (C) 2015 Cumulus Networks, Inc.
4 * Donald Sharp
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; see the file COPYING; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 * MA 02110-1301 USA
20 */
21
22 #include <zebra.h>
23
24 #include "log.h"
25 #include "if.h"
26 #include "thread.h"
27
28 #include "pimd.h"
29 #include "pim_mroute.h"
30 #include "pim_iface.h"
31 #include "pim_msg.h"
32 #include "pim_pim.h"
33 #include "pim_str.h"
34 #include "pim_rp.h"
35 #include "pim_register.h"
36 #include "pim_upstream.h"
37 #include "pim_br.h"
38
39 struct thread *send_test_packet_timer = NULL;
40
41 /*
42 * This seems stupidly expensive. A list lookup. Why is this
43 * not a hash?
44 */
45 static int
46 pim_check_is_my_ip_address (struct in_addr dest_addr)
47 {
48 /*
49 * See if we can short-cut some?
50 * This might not make sense if we ever leave a static RP
51 * type of configuration.
52 * Note - Premature optimization might bite our patooeys' here.
53 */
54 if (I_am_RP(dest_addr) && (dest_addr.s_addr == qpim_rp.rpf_addr.s_addr))
55 return 1;
56
57 if (if_lookup_exact_address (&dest_addr, AF_INET))
58 return 1;
59
60 return 0;
61 }
62
63 static void
64 pim_register_stop_send (struct in_addr src)
65 {
66 return;
67 }
68
69 void
70 pim_register_send (const struct ip *ip_hdr, struct pim_rpf *rpg)
71 {
72 unsigned char buffer[3000];
73 unsigned char *b1;
74 struct pim_interface *pinfo;
75 struct interface *ifp;
76 uint32_t plen;
77
78 ifp = rpg->source_nexthop.interface;
79 pinfo = (struct pim_interface *)ifp->info;
80 if (!pinfo) {
81 zlog_debug("%s: No pinfo!\n", __PRETTY_FUNCTION__);
82 return;
83 }
84
85 memset(buffer, 0, 3000);
86 b1 = buffer + PIM_MSG_REGISTER_LEN;
87
88 plen = ntohs(ip_hdr->ip_len);
89 memcpy(b1, (const unsigned char *)ip_hdr, plen);
90
91 pim_msg_build_header(buffer, plen + PIM_MSG_HEADER_LEN, PIM_MSG_TYPE_REGISTER);
92
93 if (pim_msg_send(pinfo->pim_sock_fd,
94 rpg->rpf_addr,
95 buffer,
96 plen + PIM_MSG_REGISTER_LEN,
97 ifp->name)) {
98 if (PIM_DEBUG_PIM_TRACE) {
99 zlog_debug("%s: could not send PIM register message on interface %s",
100 __PRETTY_FUNCTION__, ifp->name);
101 }
102 return;
103 }
104 }
105
106 /*
107 * 4.4.2 Receiving Register Messages at the RP
108 *
109 * When an RP receives a Register message, the course of action is
110 * decided according to the following pseudocode:
111 *
112 * packet_arrives_on_rp_tunnel( pkt ) {
113 * if( outer.dst is not one of my addresses ) {
114 * drop the packet silently.
115 * # Note: this may be a spoofing attempt
116 * }
117 * if( I_am_RP(G) AND outer.dst == RP(G) ) {
118 * sentRegisterStop = FALSE;
119 * if ( register.borderbit == TRUE ) {
120 * if ( PMBR(S,G) == unknown ) {
121 * PMBR(S,G) = outer.src
122 * } else if ( outer.src != PMBR(S,G) ) {
123 * send Register-Stop(S,G) to outer.src
124 * drop the packet silently.
125 * }
126 * }
127 * if ( SPTbit(S,G) OR
128 * ( SwitchToSptDesired(S,G) AND
129 * ( inherited_olist(S,G) == NULL ))) {
130 * send Register-Stop(S,G) to outer.src
131 * sentRegisterStop = TRUE;
132 * }
133 * if ( SPTbit(S,G) OR SwitchToSptDesired(S,G) ) {
134 * if ( sentRegisterStop == TRUE ) {
135 * set KeepaliveTimer(S,G) to RP_Keepalive_Period;
136 * } else {
137 * set KeepaliveTimer(S,G) to Keepalive_Period;
138 * }
139 * }
140 * if( !SPTbit(S,G) AND ! pkt.NullRegisterBit ) {
141 * decapsulate and forward the inner packet to
142 * inherited_olist(S,G,rpt) # Note (+)
143 * }
144 * } else {
145 * send Register-Stop(S,G) to outer.src
146 * # Note (*)
147 * }
148 * }
149 */
150 int
151 pim_register_recv (struct interface *ifp,
152 struct in_addr dest_addr,
153 struct in_addr src_addr,
154 uint8_t *tlv_buf, int tlv_buf_size)
155 {
156 int sentRegisterStop = 0;
157 struct ip *ip_hdr;
158 //size_t hlen;
159 struct in_addr group = { .s_addr = 0 };
160 struct in_addr source = { .s_addr = 0 };
161 //uint8_t *msg;
162 uint32_t *bits;
163
164 if (!pim_check_is_my_ip_address (dest_addr)) {
165 if (PIM_DEBUG_PIM_PACKETS) {
166 char dest[100];
167
168 pim_inet4_dump ("<dst?>", dest_addr, dest, sizeof(dest));
169 zlog_debug ("%s: Received Register message for %s that I do not own", __func__,
170 dest);
171 }
172 return 0;
173 }
174
175 #define inherited_olist(S,G) NULL
176 /*
177 * Please note this is not drawn to get the correct bit/data size
178 *
179 * The entirety of the REGISTER packet looks like this:
180 * -------------------------------------------------------------
181 * | Ver | Type | Reserved | Checksum |
182 * |-----------------------------------------------------------|
183 * |B|N| Reserved 2 |
184 * |-----------------------------------------------------------|
185 * | Encap | IP HDR |
186 * | Mcast | |
187 * | Packet |--------------------------------------------------|
188 * | | Mcast Data |
189 * | | |
190 * ...
191 *
192 * tlv_buf when received from the caller points at the B bit
193 * We need to know the inner source and dest
194 */
195 bits = (uint32_t *)tlv_buf;
196 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_LEN);
197 //hlen = (ip_hdr->ip_hl << 2) | PIM_MSG_REGISTER_LEN;
198 //msg = (uint8_t *)tlv_buf + hlen;
199 source = ip_hdr->ip_src;
200 group = ip_hdr->ip_dst;
201
202 if (I_am_RP (group) && (dest_addr.s_addr == ((RP (group))->rpf_addr.s_addr))) {
203 sentRegisterStop = 0;
204
205 if (*bits & PIM_REGISTER_BORDER_BIT) {
206 struct in_addr pimbr = pim_br_get_pmbr (source, group);
207 if (PIM_DEBUG_PIM_PACKETS)
208 zlog_debug("%s: Received Register message with Border bit set", __func__);
209
210 if (pimbr.s_addr == pim_br_unknown.s_addr)
211 pim_br_set_pmbr(source, group, src_addr);
212 else if (src_addr.s_addr != pimbr.s_addr) {
213 pim_register_stop_send(src_addr);
214 if (PIM_DEBUG_PIM_PACKETS)
215 zlog_debug("%s: Sending register-Stop to %s and dropping mr. packet",
216 __func__, "Sender");
217 /* Drop Packet Silently */
218 return 1;
219 }
220 }
221
222 struct pim_upstream *upstream = pim_upstream_find (source, group);
223 /*
224 * If we don't have a place to send ignore the packet
225 */
226 if (!upstream)
227 return 1;
228
229 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
230 ((SwitchToSptDesired(source, group)) &&
231 (inherited_olist(source, group) == NULL))) {
232 pim_register_stop_send(src_addr);
233 sentRegisterStop = 1;
234 }
235
236 if ((upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) ||
237 (SwitchToSptDesired(source, group))) {
238 if (sentRegisterStop) {
239 pim_upstream_keep_alive_timer_start (upstream, PIM_RP_KEEPALIVE_PERIOD);
240 } else {
241 pim_upstream_keep_alive_timer_start (upstream, PIM_KEEPALIVE_PERIOD);
242 }
243 }
244
245 if (!(upstream->sptbit == PIM_UPSTREAM_SPTBIT_TRUE) &&
246 !(*bits & PIM_REGISTER_NR_BIT)) {
247 //decapsulate and forward the iner packet to
248 //inherited_olist(S,G,rpt)
249 }
250 } else {
251 pim_register_stop_send(src_addr);
252 }
253
254 return 1;
255 }
256
257
258 static int
259 pim_register_send_test_packet (struct thread *t)
260 {
261 uint8_t *packet;
262
263 packet = THREAD_ARG(t);
264
265 *packet = 4;
266
267 return 1;
268 }
269
270 /*
271 * pim_register_send_test_packet
272 *
273 * Send a test packet to the RP from source, in group and pps packets per second
274 */
275 void
276 pim_register_send_test_packet_start (struct in_addr source,
277 struct in_addr group,
278 uint32_t pps)
279 {
280 uint8_t *packet = NULL;
281
282 THREAD_TIMER_MSEC_ON(master, send_test_packet_timer,
283 pim_register_send_test_packet, packet, 1000/pps);
284
285 return;
286 }