]>
git.ipfire.org Git - thirdparty/bird.git/blob - proto/rip/packets.c
2 * BIRD -- Routing Information Protocol (RIP)
4 * (c) 1998--1999 Pavel Machek <pavel@ucw.cz>
5 * (c) 2004--2013 Ondrej Filip <feela@network.cz>
6 * (c) 2009--2015 Ondrej Zajicek <santiago@crfreenet.org>
7 * (c) 2009--2015 CZ.NIC z.s.p.o.
9 * Can be freely distributed and used under the terms of the GNU GPL.
18 #define RIP_CMD_REQUEST 1 /* want info */
19 #define RIP_CMD_RESPONSE 2 /* responding to request */
21 #define RIP_BLOCK_LENGTH 20
22 #define RIP_PASSWD_LENGTH 16
25 #define RIP_AF_AUTH 0xffff
28 /* RIP packet header */
36 /* RTE block for RIPv2 */
47 /* RTE block for RIPng */
56 /* Authentication block for RIPv2 */
74 /* Authentication tail, RFC 4822 */
82 /* Internal representation of RTE block data */
93 #define DROP(DSC,VAL) do { err_dsc = DSC; err_val = VAL; goto drop; } while(0)
94 #define DROP1(DSC) do { err_dsc = DSC; goto drop; } while(0)
95 #define SKIP(DSC) do { err_dsc = DSC; goto skip; } while(0)
97 #define LOG_PKT(msg, args...) \
98 log_rl(&p->log_pkt_tbf, L_REMOTE "%s: " msg, p->p.name, args)
100 #define LOG_PKT_AUTH(msg, args...) \
101 log_rl(&p->log_pkt_tbf, L_AUTH "%s: " msg, p->p.name, args)
103 #define LOG_RTE(msg, args...) \
104 log_rl(&p->log_rte_tbf, L_REMOTE "%s: " msg, p->p.name, args)
107 static inline void * rip_tx_buffer(struct rip_iface
*ifa
)
108 { return ifa
->sk
->tbuf
; }
110 static inline uint
rip_pkt_hdrlen(struct rip_iface
*ifa
)
111 { return sizeof(struct rip_packet
) + (ifa
->cf
->auth_type
? RIP_BLOCK_LENGTH
: 0); }
114 rip_put_block(struct rip_proto
*p
, byte
*pos
, struct rip_block
*rte
)
118 struct rip_block_v2
*block
= (void *) pos
;
119 block
->family
= rte
->no_af
? 0 : htons(RIP_AF_IPV4
);
120 block
->tag
= htons(rte
->tag
);
121 block
->network
= ip4_hton(net4_prefix(&rte
->net
));
122 block
->netmask
= ip4_hton(ip4_mkmask(net4_pxlen(&rte
->net
)));
123 block
->next_hop
= ip4_hton(ipa_to_ip4(rte
->next_hop
));
124 block
->metric
= htonl(rte
->metric
);
128 struct rip_block_ng
*block
= (void *) pos
;
129 block
->prefix
= ip6_hton(net6_prefix(&rte
->net
));
130 block
->tag
= htons(rte
->tag
);
131 block
->pxlen
= net6_pxlen(&rte
->net
);
132 block
->metric
= rte
->metric
;
137 rip_put_next_hop(struct rip_proto
*p UNUSED
, byte
*pos
, struct rip_block
*rte
)
139 struct rip_block_ng
*block
= (void *) pos
;
140 block
->prefix
= ip6_hton(ipa_to_ip6(rte
->next_hop
));
143 block
->metric
= 0xff;
147 rip_get_block(struct rip_proto
*p
, byte
*pos
, struct rip_block
*rte
)
151 struct rip_block_v2
*block
= (void *) pos
;
153 /* Skip blocks with strange AF, including authentication blocks */
154 if (block
->family
!= (rte
->no_af
? 0 : htons(RIP_AF_IPV4
)))
157 uint pxlen
= ip4_masklen(ip4_ntoh(block
->netmask
));
158 net_fill_ip4(&rte
->net
, ip4_ntoh(block
->network
), pxlen
);
159 rte
->metric
= ntohl(block
->metric
);
160 rte
->tag
= ntohs(block
->tag
);
161 rte
->next_hop
= ipa_from_ip4(ip4_ntoh(block
->next_hop
));
167 struct rip_block_ng
*block
= (void *) pos
;
169 /* Handle and skip next hop blocks */
170 if (block
->metric
== 0xff)
172 rte
->next_hop
= ipa_from_ip6(ip6_ntoh(block
->prefix
));
173 if (!ipa_is_link_local(rte
->next_hop
)) rte
->next_hop
= IPA_NONE
;
177 uint pxlen
= (block
->pxlen
<= IP6_MAX_PREFIX_LENGTH
) ? block
->pxlen
: 255;
178 net_fill_ip6(&rte
->net
, ip6_ntoh(block
->prefix
), pxlen
);
179 rte
->metric
= block
->metric
;
180 rte
->tag
= ntohs(block
->tag
);
181 /* rte->next_hop is deliberately kept unmodified */;
188 rip_update_csn(struct rip_proto
*p UNUSED
, struct rip_iface
*ifa
)
191 * We update crypto sequence numbers at the beginning of update session to
192 * avoid issues with packet reordering, so packets inside one update session
193 * have the same CSN. We are using real time, but enforcing monotonicity.
195 if (ifa
->cf
->auth_type
== RIP_AUTH_CRYPTO
)
197 u32 now_real
= (u32
) (current_real_time() TO_S
);
198 ifa
->csn
= (ifa
->csn
< now_real
) ? now_real
: ifa
->csn
+ 1;
203 rip_fill_authentication(struct rip_proto
*p
, struct rip_iface
*ifa
, struct rip_packet
*pkt
, uint
*plen
)
205 struct rip_block_auth
*auth
= (void *) (pkt
+ 1);
206 struct password_item
*pass
= password_find(ifa
->cf
->passwords
, 0);
210 /* FIXME: This should not happen */
211 log(L_ERR
"%s: No suitable password found for authentication", p
->p
.name
);
212 memset(auth
, 0, sizeof(struct rip_block_auth
));
216 switch (ifa
->cf
->auth_type
)
219 auth
->must_be_ffff
= htons(0xffff);
220 auth
->auth_type
= htons(RIP_AUTH_PLAIN
);
221 strncpy(auth
->password
, pass
->password
, RIP_PASSWD_LENGTH
);
224 case RIP_AUTH_CRYPTO
:
225 auth
->must_be_ffff
= htons(0xffff);
226 auth
->auth_type
= htons(RIP_AUTH_CRYPTO
);
227 auth
->packet_len
= htons(*plen
);
228 auth
->key_id
= pass
->id
;
229 auth
->auth_len
= mac_type_length(pass
->alg
);
230 auth
->seq_num
= ifa
->csn_ready
? htonl(ifa
->csn
) : 0;
235 if (pass
->alg
< ALG_HMAC
)
236 auth
->auth_len
+= sizeof(struct rip_auth_tail
);
239 * Note that RFC 4822 is unclear whether auth_len should cover whole
240 * authentication trailer or just auth_data length.
242 * FIXME: We should use just auth_data length by default. Currently we put
243 * the whole auth trailer length in keyed hash case to keep old behavior,
244 * but we put just auth_data length in the new HMAC case. Note that Quagga
245 * has config option for this.
247 * Crypto sequence numbers are increased by sender in rip_update_csn().
248 * First CSN should be zero, this is handled by csn_ready.
251 struct rip_auth_tail
*tail
= (void *) ((byte
*) pkt
+ *plen
);
252 tail
->must_be_ffff
= htons(0xffff);
253 tail
->must_be_0001
= htons(0x0001);
255 uint auth_len
= mac_type_length(pass
->alg
);
256 *plen
+= sizeof(struct rip_auth_tail
) + auth_len
;
258 /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
259 if (pass
->alg
< ALG_HMAC
)
260 strncpy(tail
->auth_data
, pass
->password
, auth_len
);
262 memset32(tail
->auth_data
, HMAC_MAGIC
, auth_len
/ 4);
264 mac_fill(pass
->alg
, pass
->password
, pass
->length
,
265 (byte
*) pkt
, *plen
, tail
->auth_data
);
269 bug("Unknown authentication type");
274 rip_check_authentication(struct rip_proto
*p
, struct rip_iface
*ifa
, struct rip_packet
*pkt
, uint
*plen
, struct rip_neighbor
*n
)
276 struct rip_block_auth
*auth
= (void *) (pkt
+ 1);
277 struct password_item
*pass
= NULL
;
278 const char *err_dsc
= NULL
;
282 /* Check for authentication entry */
283 if ((*plen
>= (sizeof(struct rip_packet
) + sizeof(struct rip_block_auth
))) &&
284 (auth
->must_be_ffff
== htons(0xffff)))
285 auth_type
= ntohs(auth
->auth_type
);
287 if (auth_type
!= ifa
->cf
->auth_type
)
288 DROP("authentication method mismatch", auth_type
);
296 pass
= password_find_by_value(ifa
->cf
->passwords
, auth
->password
, RIP_PASSWD_LENGTH
);
298 DROP1("wrong password");
302 case RIP_AUTH_CRYPTO
:
303 pass
= password_find_by_id(ifa
->cf
->passwords
, auth
->key_id
);
305 DROP("no suitable password found", auth
->key_id
);
307 uint data_len
= ntohs(auth
->packet_len
);
308 uint auth_len
= mac_type_length(pass
->alg
);
309 uint auth_len2
= sizeof(struct rip_auth_tail
) + auth_len
;
312 * Ideally, first check should be check for internal consistency:
313 * (data_len + sizeof(struct rip_auth_tail) + auth->auth_len) != *plen
315 * Second one should check expected code length:
316 * auth->auth_len != auth_len
318 * But as auth->auth_len has two interpretations, we simplify this
321 if (data_len
+ auth_len2
!= *plen
)
322 DROP("packet length mismatch", *plen
);
324 /* Warning: two interpretations of auth_len field */
325 if ((auth
->auth_len
!= auth_len
) && (auth
->auth_len
!= auth_len2
))
326 DROP("wrong authentication length", auth
->auth_len
);
328 struct rip_auth_tail
*tail
= (void *) ((byte
*) pkt
+ data_len
);
329 if ((tail
->must_be_ffff
!= htons(0xffff)) || (tail
->must_be_0001
!= htons(0x0001)))
330 DROP1("authentication trailer is missing");
332 /* Accept higher sequence number, or zero if connectivity is lost */
333 /* FIXME: sequence number must be password/SA specific */
334 u32 rcv_csn
= ntohl(auth
->seq_num
);
335 if ((rcv_csn
< n
->csn
) && (rcv_csn
|| n
->uc
))
337 /* We want to report both new and old CSN */
338 LOG_PKT_AUTH("Authentication failed for %I on %s - "
339 "lower sequence number (rcv %u, old %u)",
340 n
->nbr
->addr
, ifa
->iface
->name
, rcv_csn
, n
->csn
);
344 byte
*auth_data
= alloca(auth_len
);
345 memcpy(auth_data
, tail
->auth_data
, auth_len
);
347 /* Append key for keyed hash, append padding for HMAC (RFC 4822 2.5) */
348 if (pass
->alg
< ALG_HMAC
)
349 strncpy(tail
->auth_data
, pass
->password
, auth_len
);
351 memset32(tail
->auth_data
, HMAC_MAGIC
, auth_len
/ 4);
353 if (!mac_verify(pass
->alg
, pass
->password
, pass
->length
,
354 (byte
*) pkt
, *plen
, auth_data
))
355 DROP("wrong authentication code", pass
->id
);
364 LOG_PKT_AUTH("Authentication failed for %I on %s - %s (%u)",
365 n
->nbr
->addr
, ifa
->iface
->name
, err_dsc
, err_val
);
371 rip_send_to(struct rip_proto
*p
, struct rip_iface
*ifa
, struct rip_packet
*pkt
, uint plen
, ip_addr dst
)
373 if (ifa
->cf
->auth_type
)
374 rip_fill_authentication(p
, ifa
, pkt
, &plen
);
376 return sk_send_to(ifa
->sk
, plen
, dst
, 0);
381 rip_send_request(struct rip_proto
*p
, struct rip_iface
*ifa
)
383 byte
*pos
= rip_tx_buffer(ifa
);
385 struct rip_packet
*pkt
= (void *) pos
;
386 pkt
->command
= RIP_CMD_REQUEST
;
387 pkt
->version
= ifa
->cf
->version
;
389 pos
+= rip_pkt_hdrlen(ifa
);
391 struct rip_block b
= { .no_af
= 1, .metric
= p
->infinity
};
392 rip_put_block(p
, pos
, &b
);
393 pos
+= RIP_BLOCK_LENGTH
;
395 rip_update_csn(p
, ifa
);
397 TRACE(D_PACKETS
, "Sending request via %s", ifa
->iface
->name
);
398 rip_send_to(p
, ifa
, pkt
, pos
- (byte
*) pkt
, ifa
->addr
);
402 rip_receive_request(struct rip_proto
*p
, struct rip_iface
*ifa
, struct rip_packet
*pkt
, uint plen
, struct rip_neighbor
*from
)
404 TRACE(D_PACKETS
, "Request received from %I on %s", from
->nbr
->addr
, ifa
->iface
->name
);
406 byte
*pos
= (byte
*) pkt
+ rip_pkt_hdrlen(ifa
);
408 /* We expect one regular block */
409 if (plen
!= (rip_pkt_hdrlen(ifa
) + RIP_BLOCK_LENGTH
))
412 struct rip_block b
= { .no_af
= 1 };
414 if (!rip_get_block(p
, pos
, &b
))
417 /* Special case - infinity metric, for RIPng also zero prefix */
418 if ((b
.metric
!= p
->infinity
) ||
419 (rip_is_ng(p
) && !net_zero_ip6((net_addr_ip6
*) &b
.net
)))
422 /* We do nothing if TX is already active */
425 TRACE(D_EVENTS
, "Skipping request from %I on %s, TX is busy", from
->nbr
->addr
, ifa
->iface
->name
);
429 if (!ifa
->cf
->passive
)
430 rip_send_table(p
, ifa
, from
->nbr
->addr
, 0);
435 rip_send_response(struct rip_proto
*p
, struct rip_iface
*ifa
)
437 if (! ifa
->tx_active
)
440 byte
*pos
= rip_tx_buffer(ifa
);
441 byte
*max
= rip_tx_buffer(ifa
) + ifa
->tx_plen
-
442 (rip_is_v2(p
) ? RIP_BLOCK_LENGTH
: 2*RIP_BLOCK_LENGTH
);
443 ip_addr last_next_hop
= IPA_NONE
;
444 btime now_
= current_time();
447 struct rip_packet
*pkt
= (void *) pos
;
448 pkt
->command
= RIP_CMD_RESPONSE
;
449 pkt
->version
= ifa
->cf
->version
;
451 pos
+= rip_pkt_hdrlen(ifa
);
453 FIB_ITERATE_START(&p
->rtable
, &ifa
->tx_fit
, struct rip_entry
, en
)
459 /* Stale entries that should be removed */
460 if ((en
->valid
== RIP_ENTRY_STALE
) &&
461 ((en
->changed
+ ifa
->cf
->garbage_time
) <= now_
))
464 /* Triggered updates */
465 if (en
->changed
< ifa
->tx_changed
)
468 /* Not enough space for current entry */
471 FIB_ITERATE_PUT(&ifa
->tx_fit
);
475 struct rip_block rte
= {
476 .metric
= en
->metric
,
480 net_copy(&rte
.net
, en
->n
.addr
);
482 if (en
->iface
== ifa
->iface
)
483 rte
.next_hop
= en
->next_hop
;
485 if (rip_is_v2(p
) && (ifa
->cf
->version
== RIP_V1
))
487 /* Skipping subnets (i.e. not hosts, classful networks or default route) */
488 if (ip4_masklen(ip4_class_mask(net4_prefix(&rte
.net
))) != rte
.net
.pxlen
)
493 rte
.next_hop
= IPA_NONE
;
497 if (en
->from
== ifa
->iface
&& ifa
->cf
->split_horizon
)
499 if (ifa
->cf
->poison_reverse
)
501 rte
.metric
= p
->infinity
;
502 rte
.next_hop
= IPA_NONE
;
508 // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net, rte.next_hop, rte.metric);
510 /* RIPng next hop entry */
511 if (rip_is_ng(p
) && !ipa_equal(rte
.next_hop
, last_next_hop
))
513 last_next_hop
= rte
.next_hop
;
514 rip_put_next_hop(p
, pos
, &rte
);
515 pos
+= RIP_BLOCK_LENGTH
;
518 rip_put_block(p
, pos
, &rte
);
519 pos
+= RIP_BLOCK_LENGTH
;
527 /* Do not send empty packet */
532 TRACE(D_PACKETS
, "Sending response via %s", ifa
->iface
->name
);
533 return rip_send_to(p
, ifa
, pkt
, pos
- (byte
*) pkt
, ifa
->tx_addr
);
537 * rip_send_table - RIP interface timer hook
539 * @ifa: RIP interface
540 * @addr: destination IP address
541 * @changed: time limit for triggered updates
543 * The function activates an update session and starts sending routing update
544 * packets (using rip_send_response()). The session may be finished during the
545 * call or may continue in rip_tx_hook() until all appropriate routes are
546 * transmitted. Note that there may be at most one active update session per
547 * interface, the function will terminate the old active session before
548 * activating the new one.
551 rip_send_table(struct rip_proto
*p
, struct rip_iface
*ifa
, ip_addr addr
, btime changed
)
553 DBG("RIP: Opening TX session to %I on %s\n", addr
, ifa
->iface
->name
);
555 rip_reset_tx_session(p
, ifa
);
559 ifa
->tx_changed
= changed
;
560 FIB_ITERATE_INIT(&ifa
->tx_fit
, &p
->rtable
);
562 rip_update_csn(p
, ifa
);
564 while (rip_send_response(p
, ifa
) > 0)
569 rip_tx_hook(sock
*sk
)
571 struct rip_iface
*ifa
= sk
->data
;
572 struct rip_proto
*p
= ifa
->rip
;
574 DBG("RIP: TX hook called (iface %s, src %I, dst %I)\n",
575 sk
->iface
->name
, sk
->saddr
, sk
->daddr
);
577 while (rip_send_response(p
, ifa
) > 0)
582 rip_err_hook(sock
*sk
, int err
)
584 struct rip_iface
*ifa
= sk
->data
;
585 struct rip_proto
*p
= ifa
->rip
;
587 log(L_ERR
"%s: Socket error on %s: %M", p
->p
.name
, ifa
->iface
->name
, err
);
589 rip_reset_tx_session(p
, ifa
);
593 rip_receive_response(struct rip_proto
*p
, struct rip_iface
*ifa
, struct rip_packet
*pkt
, uint plen
, struct rip_neighbor
*from
)
595 struct rip_block rte
= {};
596 const char *err_dsc
= NULL
;
598 TRACE(D_PACKETS
, "Response received from %I on %s", from
->nbr
->addr
, ifa
->iface
->name
);
600 byte
*pos
= (byte
*) pkt
+ sizeof(struct rip_packet
);
601 byte
*end
= (byte
*) pkt
+ plen
;
602 btime now_
= current_time();
604 for (; pos
< end
; pos
+= RIP_BLOCK_LENGTH
)
606 /* Find next regular RTE */
607 if (!rip_get_block(p
, pos
, &rte
))
610 if (rip_is_v2(p
) && (pkt
->version
== RIP_V1
))
612 if (ifa
->cf
->check_zero
&& (rte
.tag
|| rte
.net
.pxlen
|| ipa_nonzero(rte
.next_hop
)))
613 SKIP("RIPv1 reserved field is nonzero");
616 rte
.net
.pxlen
= ip4_masklen(ip4_class_mask(net4_prefix(&rte
.net
)));
617 rte
.next_hop
= IPA_NONE
;
620 if (rte
.net
.pxlen
== 255)
621 SKIP("invalid prefix length");
623 net_normalize(&rte
.net
);
625 int c
= net_classify(&rte
.net
);
626 if ((c
< 0) || !(c
& IADDR_HOST
) || ((c
& IADDR_SCOPE_MASK
) <= SCOPE_LINK
))
627 SKIP("invalid prefix");
629 if (rte
.metric
> p
->infinity
)
630 SKIP("invalid metric");
632 if (ipa_nonzero(rte
.next_hop
))
634 neighbor
*nbr
= neigh_find(&p
->p
, rte
.next_hop
, ifa
->iface
, 0);
635 if (!nbr
|| (nbr
->scope
<= 0))
636 rte
.next_hop
= IPA_NONE
;
639 // TRACE(D_PACKETS, " %N -> %I metric %d", &rte.net.n, rte.next_hop, rte.metric);
641 rte
.metric
+= ifa
->cf
->metric
;
643 if (rte
.metric
< p
->infinity
)
645 struct rip_rte
new = {
647 .next_hop
= ipa_nonzero(rte
.next_hop
) ? rte
.next_hop
: from
->nbr
->addr
,
648 .metric
= rte
.metric
,
650 .expires
= now_
+ ifa
->cf
->timeout_time
653 rip_update_rte(p
, &rte
.net
, &new);
656 rip_withdraw_rte(p
, &rte
.net
, from
);
661 LOG_RTE("Ignoring route %N received from %I - %s",
662 &rte
.net
, from
->nbr
->addr
, err_dsc
);
667 rip_rx_hook(sock
*sk
, uint len
)
669 struct rip_iface
*ifa
= sk
->data
;
670 struct rip_proto
*p
= ifa
->rip
;
671 const char *err_dsc
= NULL
;
674 if (sk
->lifindex
!= sk
->iface
->index
)
677 DBG("RIP: RX hook called (iface %s, src %I, dst %I)\n",
678 sk
->iface
->name
, sk
->faddr
, sk
->laddr
);
680 /* Silently ignore my own packets */
681 if (ipa_equal(sk
->faddr
, sk
->saddr
))
684 if (rip_is_ng(p
) && !ipa_is_link_local(sk
->faddr
))
685 DROP1("wrong src address");
687 struct rip_neighbor
*n
= rip_get_neighbor(p
, &sk
->faddr
, ifa
);
690 DROP1("not from neighbor");
692 if ((ifa
->cf
->ttl_security
== 1) && (sk
->rcv_ttl
< 255))
693 DROP("wrong TTL", sk
->rcv_ttl
);
695 if (sk
->fport
!= sk
->dport
)
696 DROP("wrong src port", sk
->fport
);
698 if (len
< sizeof(struct rip_packet
))
699 DROP("too short", len
);
701 if (sk
->flags
& SKF_TRUNCATED
)
702 DROP("truncated", len
);
704 struct rip_packet
*pkt
= (struct rip_packet
*) sk
->rbuf
;
707 if (!pkt
->version
|| (ifa
->cf
->version_only
&& (pkt
->version
!= ifa
->cf
->version
)))
708 DROP("wrong version", pkt
->version
);
710 /* rip_check_authentication() has its own error logging */
711 if (rip_is_v2(p
) && !rip_check_authentication(p
, ifa
, pkt
, &plen
, n
))
714 if ((plen
- sizeof(struct rip_packet
)) % RIP_BLOCK_LENGTH
)
715 DROP("invalid length", plen
);
717 n
->last_seen
= current_time();
718 rip_update_bfd(p
, n
);
720 switch (pkt
->command
)
722 case RIP_CMD_REQUEST
:
723 rip_receive_request(p
, ifa
, pkt
, plen
, n
);
726 case RIP_CMD_RESPONSE
:
727 rip_receive_response(p
, ifa
, pkt
, plen
, n
);
731 DROP("unknown command", pkt
->command
);
736 LOG_PKT("Bad packet from %I via %s - %s (%u)",
737 sk
->faddr
, sk
->iface
->name
, err_dsc
, err_val
);
743 rip_open_socket(struct rip_iface
*ifa
)
745 struct rip_proto
*p
= ifa
->rip
;
747 sock
*sk
= sk_new(p
->p
.pool
);
749 sk
->subtype
= rip_is_v2(p
) ? SK_IPV4
: SK_IPV6
;
750 sk
->sport
= ifa
->cf
->port
;
751 sk
->dport
= ifa
->cf
->port
;
752 sk
->iface
= ifa
->iface
;
753 sk
->saddr
= rip_is_v2(p
) ? ifa
->iface
->addr4
->ip
: ifa
->iface
->llv6
->ip
;
756 sk
->rx_hook
= rip_rx_hook
;
757 sk
->tx_hook
= rip_tx_hook
;
758 sk
->err_hook
= rip_err_hook
;
761 sk
->tos
= ifa
->cf
->tx_tos
;
762 sk
->priority
= ifa
->cf
->tx_priority
;
763 sk
->ttl
= ifa
->cf
->ttl_security
? 255 : 1;
764 sk
->flags
= SKF_LADDR_RX
| ((ifa
->cf
->ttl_security
== 1) ? SKF_TTL_RX
: 0);
766 /* sk->rbsize and sk->tbsize are handled in rip_iface_update_buffers() */
771 if (ifa
->cf
->mode
== RIP_IM_MULTICAST
)
773 if (sk_setup_multicast(sk
) < 0)
776 if (sk_join_group(sk
, ifa
->addr
) < 0)
781 if (sk_setup_broadcast(sk
) < 0)
784 if (ipa_zero(ifa
->addr
))
786 sk
->err
= "Missing broadcast address";
795 sk_log_error(sk
, p
->p
.name
);