diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2009-09-04 11:06:51 +0200 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2009-09-04 11:06:51 +0200 |
commit | f9c799a00e705b1420b214628c2bb2a30bf491d9 (patch) | |
tree | 23386935f0128d31acab5f86da41774cac0a4de5 | |
parent | d2ceaf4ec82837239a35ace00399ce3aa845849e (diff) | |
download | bird-f9c799a00e705b1420b214628c2bb2a30bf491d9.tar bird-f9c799a00e705b1420b214628c2bb2a30bf491d9.zip |
Temporary OSPFv3 development commit (changing multicast support).
-rw-r--r-- | lib/socket.h | 12 | ||||
-rw-r--r-- | proto/ospf/dbdes.c | 10 | ||||
-rw-r--r-- | proto/ospf/hello.c | 28 | ||||
-rw-r--r-- | proto/ospf/iface.c | 113 | ||||
-rw-r--r-- | proto/ospf/lsack.c | 34 | ||||
-rw-r--r-- | proto/ospf/lsalib.c | 16 | ||||
-rw-r--r-- | proto/ospf/lsreq.c | 12 | ||||
-rw-r--r-- | proto/ospf/lsupd.c | 38 | ||||
-rw-r--r-- | proto/ospf/neighbor.c | 4 | ||||
-rw-r--r-- | proto/ospf/ospf.h | 6 | ||||
-rw-r--r-- | proto/ospf/packet.c | 13 | ||||
-rw-r--r-- | proto/ospf/packet.h | 6 | ||||
-rw-r--r-- | proto/ospf/rt.c | 11 | ||||
-rw-r--r-- | proto/ospf/topology.c | 20 | ||||
-rw-r--r-- | proto/rip/rip.c | 36 | ||||
-rw-r--r-- | sysdep/bsd/sysio.h | 51 | ||||
-rw-r--r-- | sysdep/linux/sysio.h | 136 | ||||
-rw-r--r-- | sysdep/unix/io.c | 190 |
18 files changed, 406 insertions, 330 deletions
diff --git a/lib/socket.h b/lib/socket.h index f192260..0ab7d95 100644 --- a/lib/socket.h +++ b/lib/socket.h @@ -50,7 +50,15 @@ int sk_send_to(sock *, unsigned len, ip_addr to, unsigned port); /* sk_send to g void sk_reallocate(sock *); /* Free and allocate tbuf & rbuf */ void sk_dump_all(void); int sk_set_ttl(sock *s, int ttl); /* Set TTL for given socket */ -int sk_set_md5_auth(sock *s, ip_addr a, char *passwd); /* Add or remove security associations for given passive socket */ + +/* Add or remove security associations for given passive socket */ +int sk_set_md5_auth(sock *s, ip_addr a, char *passwd); + +/* Prepare UDP or IP socket to multicasting. s->iface and s->ttl must be set */ +int sk_setup_multicast(sock *s); +int sk_join_group(sock *s, ip_addr maddr); +int sk_leave_group(sock *s, ip_addr maddr); + static inline int sk_send_buffer_empty(sock *sk) @@ -72,9 +80,7 @@ sk_send_buffer_empty(sock *sk) #define SK_TCP_ACTIVE 1 /* ? ? * * - ? - */ #define SK_TCP 2 #define SK_UDP 3 /* ? ? - - - ? ? */ -#define SK_UDP_MC 4 /* ? ? * * * * - */ #define SK_IP 5 /* ? - - * - ? ? */ -#define SK_IP_MC 6 /* ? - * * * * - */ #define SK_MAGIC 7 /* Internal use by sysdep code */ #define SK_UNIX_PASSIVE 8 #define SK_UNIX 9 diff --git a/proto/ospf/dbdes.c b/proto/ospf/dbdes.c index 9be8e61..c9d318c 100644 --- a/proto/ospf/dbdes.c +++ b/proto/ospf/dbdes.c @@ -93,7 +93,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) { case NEIGHBOR_EXSTART: /* Send empty packets */ n->myimms.bit.i = 1; - pkt = (struct ospf_dbdes_packet *) (ifa->ip_sk->tbuf); + pkt = (struct ospf_dbdes_packet *) (ifa->sk->tbuf); op = (struct ospf_packet *) pkt; ospf_pkt_fill_hdr(ifa, pkt, DBDES_P); pkt->iface_mtu = htons(ifa->iface->mtu); @@ -104,7 +104,7 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) op->length = htons(length); OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); - ospf_send_to(ifa->ip_sk, n->ip, ifa); + ospf_send_to(ifa, n->ip); break; case NEIGHBOR_EXCHANGE: @@ -185,11 +185,11 @@ ospf_dbdes_send(struct ospf_neighbor *n, int next) } /* Copy last sent packet again */ - memcpy(ifa->ip_sk->tbuf, n->ldbdes, length); + memcpy(ifa->sk->tbuf, n->ldbdes, length); - OSPF_PACKET(ospf_dump_dbdes, (struct ospf_dbdes_packet *) ifa->ip_sk->tbuf, + OSPF_PACKET(ospf_dump_dbdes, (struct ospf_dbdes_packet *) ifa->sk->tbuf, "DBDES packet sent to %I via %s", n->ip, ifa->iface->name); - ospf_send_to(ifa->ip_sk, n->ip, n->ifa); + ospf_send_to(ifa, n->ip); if(n->myimms.bit.ms) tm_start(n->rxmt_timer, n->ifa->rxmtint); /* Restart timer */ diff --git a/proto/ospf/hello.c b/proto/ospf/hello.c index cce256f..783761f 100644 --- a/proto/ospf/hello.c +++ b/proto/ospf/hello.c @@ -56,7 +56,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, (ifa->type == OSPF_IT_VLINK ? "vlink-" : ""), ifa->iface->name); #ifdef OSPFv2 - mask = ps->netmask; + ip_addr mask = ps->netmask; ipa_ntoh(mask); if (ifa->type != OSPF_IT_VLINK) { @@ -198,7 +198,7 @@ ospf_hello_receive(struct ospf_packet *ps_i, struct ospf_iface *ifa, if (n->state >= NEIGHBOR_2WAY) { #ifdef OSPFv2 - u32 rid = n->ip; + u32 rid = ipa_to_u32(n->ip); #else /* OSPFv3 */ u32 rid = p->cf->global->router_id; #endif @@ -266,20 +266,12 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn) p = (struct proto *) (ifa->oa->po); DBG("%s: Hello/Poll timer fired on interface %s.\n", p->name, ifa->iface->name); - /* Now we should send a hello packet */ - /* First a common packet header */ - if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_VLINK)) - { - pkt = (struct ospf_hello_packet *) (ifa->ip_sk->tbuf); - } - else - { - pkt = (struct ospf_hello_packet *) (ifa->hello_sk->tbuf); - } - /* Now fill ospf_hello header */ + /* Now we should send a hello packet */ + pkt = (struct ospf_hello_packet *) (ifa->sk->tbuf); op = (struct ospf_packet *) pkt; + /* Now fill ospf_hello header */ ospf_pkt_fill_hdr(ifa, pkt, HELLO_P); #ifdef OSPFv2 @@ -332,7 +324,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn) case OSPF_IT_NBMA: if (timer == NULL) /* Response to received hello */ { - ospf_send_to(ifa->ip_sk, dirn->ip, ifa); + ospf_send_to(ifa, dirn->ip); } else { @@ -357,7 +349,7 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn) if ((poll == 1) && (send)) { if (toall || (meeli && nb->eligible)) - ospf_send_to(ifa->ip_sk, nb->ip, ifa); + ospf_send_to(ifa, nb->ip); } } if (poll == 0) @@ -366,16 +358,16 @@ ospf_hello_send(timer *timer, int poll, struct ospf_neighbor *dirn) { if (toall || (n1->rid == ifa->drid) || (n1->rid == ifa->bdrid) || (meeli && (n1->priority > 0))) - ospf_send_to(ifa->ip_sk, n1->ip, ifa); + ospf_send_to(ifa, n1->ip); } } } break; case OSPF_IT_VLINK: - ospf_send_to(ifa->ip_sk, ifa->vip, ifa); + ospf_send_to(ifa, ifa->vip); break; default: - ospf_send_to(ifa->hello_sk, IPA_NONE, ifa); + ospf_send_to(ifa, AllSPFRouters); } OSPF_TRACE(D_PACKETS, "HELLO packet sent via %s%s", diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c index 439a29c..fc1cf2a 100644 --- a/proto/ospf/iface.c +++ b/proto/ospf/iface.c @@ -59,7 +59,7 @@ rxbufsize(struct ospf_iface *ifa) } static sock * -ospf_open_ip_socket(struct ospf_iface *ifa) +ospf_open_socket(struct ospf_iface *ifa, int mc) { sock *ipsk; struct proto *p = &ifa->oa->po->proto; @@ -69,7 +69,8 @@ ospf_open_ip_socket(struct ospf_iface *ifa) ipsk->dport = OSPF_PROTO; #ifdef OSPFv2 - ipsk->saddr = ifa->iface->addr->ip; + // ipsk->saddr = ifa->iface->addr->ip; + ipsk->saddr = IPA_NONE; #else /* OSPFv3 */ ipsk->saddr = ifa->lladdr; #endif @@ -86,12 +87,22 @@ ospf_open_ip_socket(struct ospf_iface *ifa) ipsk->tbsize = ifa->iface->mtu; ipsk->data = (void *) ifa; if (sk_open(ipsk) != 0) + goto err; + + if (mc) { - DBG("%s: SK_OPEN: ip open failed.\n", p->name); - return (NULL); + if (sk_setup_multicast(ipsk) < 0) + goto err; + + if (sk_join_group(ipsk, AllSPFRouters) < 0) + goto err; } - DBG("%s: SK_OPEN: ip opened.\n", p->name); - return (ipsk); + + return ipsk; + + err: + rfree(ipsk); + return NULL; } @@ -122,7 +133,7 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) ifa->vid, ospf_is[oldstate], ospf_is[state]); if (state == OSPF_IS_PTP) { - ifa->ip_sk = ospf_open_ip_socket(ifa); + ifa->sk = ospf_open_socket(ifa, 0); } } else @@ -132,43 +143,17 @@ ospf_iface_chstate(struct ospf_iface *ifa, u8 state) ifa->iface->name, ospf_is[oldstate], ospf_is[state]); if (ifa->iface->flags & IF_MULTICAST) { - if ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR)) + if ((ifa->type != OSPF_IT_NBMA) && (ifa->ioprob == OSPF_I_OK) && + ((state == OSPF_IS_BACKUP) || (state == OSPF_IS_DR))) { - if ((ifa->dr_sk == NULL) && (ifa->type != OSPF_IT_NBMA)) - { - DBG("%s: Adding new multicast socket for (B)DR\n", p->name); - ifa->dr_sk = sk_new(p->pool); - ifa->dr_sk->type = SK_IP_MC; - ifa->dr_sk->sport = 0; - ifa->dr_sk->dport = OSPF_PROTO; - -#ifdef OSPFv2 - ifa->dr_sk->saddr = AllDRouters; -#else /* OSPFv3 */ - // ifa->dr_sk->saddr = AllDRouters; - ifa->dr_sk->saddr = ifa->lladdr; -#endif - - ifa->dr_sk->daddr = AllDRouters; - ifa->dr_sk->tos = IP_PREC_INTERNET_CONTROL; - ifa->dr_sk->ttl = 1; - ifa->dr_sk->rx_hook = ospf_rx_hook; - ifa->dr_sk->tx_hook = ospf_tx_hook; - ifa->dr_sk->err_hook = ospf_err_hook; - ifa->dr_sk->iface = ifa->iface; - ifa->dr_sk->rbsize = rxbufsize(ifa); - ifa->dr_sk->tbsize = ifa->iface->mtu; - ifa->dr_sk->data = (void *) ifa; - if (sk_open(ifa->dr_sk) != 0) - { - DBG("%s: SK_OPEN: new? mc open failed.\n", p->name); - } - } + /* FIXME some error handing ? */ + sk_join_group(ifa->sk, AllDRouters); + ifa->dr_up = 1; } - else + else if (ifa->dr_up) { - rfree(ifa->dr_sk); - ifa->dr_sk = NULL; + sk_leave_group(ifa->sk, AllDRouters); + ifa->dr_up = 0; } if ((oldstate == OSPF_IS_DR) && (ifa->net_lsa != NULL)) { @@ -209,13 +194,12 @@ ospf_iface_down(struct ospf_iface *ifa) OSPF_TRACE(D_EVENTS, "Removing neighbor %I", n->ip); ospf_neigh_remove(n); } - rfree(ifa->hello_sk); - rfree(ifa->dr_sk); - rfree(ifa->ip_sk); + + rfree(ifa->sk); + ifa->sk = NULL; if (ifa->type == OSPF_IT_VLINK) { - ifa->ip_sk = NULL; ifa->iface = NULL; return; } @@ -311,6 +295,7 @@ ospf_iface_sm(struct ospf_iface *ifa, int event) } +#if 0 static sock * ospf_open_mc_socket(struct ospf_iface *ifa) { @@ -347,6 +332,7 @@ ospf_open_mc_socket(struct ospf_iface *ifa) DBG("%s: SK_OPEN: mc opened.\n", p->name); return (mcsk); } +#endif u8 ospf_iface_clasify(struct iface * ifa) @@ -383,20 +369,8 @@ ospf_iface_add(struct object_lock *lock) ifa->ioprob = OSPF_I_OK; - if (ifa->type != OSPF_IT_NBMA) - { - if ((ifa->hello_sk = ospf_open_mc_socket(ifa)) == NULL) - { - log("%s: Huh? could not open mc socket on interface %s?", p->name, - iface->name); - log("%s: Declaring as stub.", p->name); - ifa->stub = 1; - ifa->ioprob += OSPF_I_MC; - } - ifa->dr_sk = NULL; - } - - if ((ifa->ip_sk = ospf_open_ip_socket(ifa)) == NULL) + ifa->sk = ospf_open_socket(ifa, ifa->type != OSPF_IT_NBMA); + if (ifa->sk == NULL) { log("%s: Huh? could not open ip socket on interface %s?", p->name, iface->name); @@ -546,23 +520,12 @@ ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa) struct ospf_packet *op; struct ospf_neighbor *n; OSPF_TRACE(D_EVENTS, "Changing MTU on interface %s.", ifa->iface->name); - if (ifa->hello_sk) - { - ifa->hello_sk->rbsize = rxbufsize(ifa); - ifa->hello_sk->tbsize = ifa->iface->mtu; - sk_reallocate(ifa->hello_sk); - } - if (ifa->dr_sk) - { - ifa->dr_sk->rbsize = rxbufsize(ifa); - ifa->dr_sk->tbsize = ifa->iface->mtu; - sk_reallocate(ifa->dr_sk); - } - if (ifa->ip_sk) + + if (ifa->sk) { - ifa->ip_sk->rbsize = rxbufsize(ifa); - ifa->ip_sk->tbsize = ifa->iface->mtu; - sk_reallocate(ifa->ip_sk); + ifa->sk->rbsize = rxbufsize(ifa); + ifa->sk->tbsize = ifa->iface->mtu; + sk_reallocate(ifa->sk); } WALK_LIST(n, ifa->neigh_list) diff --git a/proto/ospf/lsack.c b/proto/ospf/lsack.c index dc94219..2aafd9d 100644 --- a/proto/ospf/lsack.c +++ b/proto/ospf/lsack.c @@ -57,7 +57,6 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) { struct ospf_packet *op; struct ospf_lsack_packet *pk; - sock *sk; u16 len, i = 0; struct ospf_lsa_header *h; struct lsah_n *no; @@ -67,13 +66,8 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) if (EMPTY_LIST(n->ackl[queue])) return; - if (ifa->type == OSPF_IT_BCAST) - sk = ifa->hello_sk; - else - sk = ifa->ip_sk; - - pk = (struct ospf_lsack_packet *) sk->tbuf; - op = (struct ospf_packet *) sk->tbuf; + pk = (struct ospf_lsack_packet *) ifa->sk->tbuf; + op = (struct ospf_packet *) ifa->sk->tbuf; ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); h = pk->lsh; @@ -98,22 +92,22 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) op->length = htons(len); DBG("Sending and continuing! Len=%u\n", len); - OSPF_PACKET(ospf_dump_lsack, (struct ospf_lsack_packet *) sk->tbuf, + OSPF_PACKET(ospf_dump_lsack, (struct ospf_lsack_packet *) ifa->sk->tbuf, "LSACK packet sent via %s", ifa->iface->name); if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to(sk, AllSPFRouters, ifa); + ospf_send_to(ifa, AllSPFRouters); else - ospf_send_to(sk, AllDRouters, ifa); + ospf_send_to(ifa, AllDRouters); } else { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); else - ospf_send_to_bdr(sk, ifa); + ospf_send_to_bdr(ifa); } ospf_pkt_fill_hdr(n->ifa, pk, LSACK_P); @@ -126,24 +120,18 @@ ospf_lsack_send(struct ospf_neighbor *n, int queue) op->length = htons(len); DBG("Sending! Len=%u\n", len); - OSPF_PACKET(ospf_dump_lsack, (struct ospf_lsack_packet *) sk->tbuf, + OSPF_PACKET(ospf_dump_lsack, (struct ospf_lsack_packet *) ifa->sk->tbuf, "LSACK packet sent via %s", ifa->iface->name); if (ifa->type == OSPF_IT_BCAST) { if ((ifa->state == OSPF_IS_DR) || (ifa->state == OSPF_IS_BACKUP)) - { - ospf_send_to(sk, AllSPFRouters, ifa); - } + ospf_send_to(ifa, AllSPFRouters); else - { - ospf_send_to(sk, AllDRouters, ifa); - } + ospf_send_to(ifa, AllDRouters); } else - { - ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); - } + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); } void diff --git a/proto/ospf/lsalib.c b/proto/ospf/lsalib.c index 3bc5986..8442882 100644 --- a/proto/ospf/lsalib.c +++ b/proto/ospf/lsalib.c @@ -126,6 +126,7 @@ void htonlsab(void *h, void *n, u16 type, u16 len) { unsigned int i; + switch (type) { case LSA_T_RT: @@ -138,10 +139,9 @@ htonlsab(void *h, void *n, u16 type, u16 len) hrt = h; #ifdef OSPFv2 - nrt->veb.byte = hrt->veb.byte; - nrt->padding = 0; - nrt->links = htons(hrt->links); links = hrt->links; + nrt->options = htons(hrt->options); + nrt->links = htons(hrt->links); #else /* OSPFv3 */ nrt->options = htonl(hrt->options); links = (len - sizeof(struct ospf_lsa_rt)) / @@ -211,8 +211,7 @@ ntohlsab(void *n, void *h, u16 type, u16 len) hrt = h; #ifdef OSPFv2 - hrt->veb.byte = nrt->veb.byte; - hrt->padding = 0; + hrt->options = ntohs(nrt->options); links = hrt->links = ntohs(nrt->links); #else /* OSPFv3 */ hrt->options = ntohl(nrt->options); @@ -308,19 +307,20 @@ lsasum_calculate(struct ospf_lsa_header *h, void *body) u16 length = h->length; u16 type = h->type; - log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); + // log(L_WARN "Checksum %R %R %d start (len %d)", h->id, h->rt, h->type, length); htonlsah(h, h); - htonlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); + /* char buf[1024]; memcpy(buf, h, sizeof(struct ospf_lsa_header)); memcpy(buf + sizeof(struct ospf_lsa_header), body, length - sizeof(struct ospf_lsa_header)); buf_dump("CALC", buf, length); + */ (void) lsasum_check(h, body); - log(L_WARN "Checksum result %4x", h->checksum); + // log(L_WARN "Checksum result %4x", h->checksum); ntohlsah(h, h); ntohlsab(body, body, type, length - sizeof(struct ospf_lsa_header)); diff --git a/proto/ospf/lsreq.c b/proto/ospf/lsreq.c index aafc190..1b5da27 100644 --- a/proto/ospf/lsreq.c +++ b/proto/ospf/lsreq.c @@ -28,8 +28,8 @@ static void ospf_dump_lsreq(struct proto *p, struct ospf_lsreq_packet *pkt) sizeof(struct ospf_lsreq_header); for (i = 0; i < j; i++) - log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: %u", p->name, - htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), pkt->lsh[i].type); + log(L_TRACE "%s: LSR Id: %R, Rt: %R, Type: 0x%x", p->name, + htonl(pkt->lsh[i].id), htonl(pkt->lsh[i].rt), htonl(pkt->lsh[i].type)); } void @@ -44,8 +44,8 @@ ospf_lsreq_send(struct ospf_neighbor *n) int i, j; struct proto *p = &n->ifa->oa->po->proto; - pk = (struct ospf_lsreq_packet *) n->ifa->ip_sk->tbuf; - op = (struct ospf_packet *) n->ifa->ip_sk->tbuf; + pk = (struct ospf_lsreq_packet *) n->ifa->sk->tbuf; + op = (struct ospf_packet *) n->ifa->sk->tbuf; ospf_pkt_fill_hdr(n->ifa, pk, LSREQ_P); @@ -82,9 +82,9 @@ ospf_lsreq_send(struct ospf_neighbor *n) i) * sizeof(struct ospf_lsreq_header); op->length = htons(length); - OSPF_PACKET(ospf_dump_lsreq, (struct ospf_lsreq_packet *) n->ifa->ip_sk->tbuf, + OSPF_PACKET(ospf_dump_lsreq, (struct ospf_lsreq_packet *) n->ifa->sk->tbuf, "LSREQ packet sent to %I via %s", n->ip, n->ifa->iface->name); - ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); + ospf_send_to(n->ifa, n->ip); } void diff --git a/proto/ospf/lsupd.c b/proto/ospf/lsupd.c index 72861bd..bccdba8 100644 --- a/proto/ospf/lsupd.c +++ b/proto/ospf/lsupd.c @@ -21,7 +21,7 @@ void ospf_dump_lsahdr(struct proto *p, struct ospf_lsa_header *lsa_n) struct ospf_lsa_header lsa; ntohlsah(lsa_n, &lsa); - log(L_TRACE "%s: LSA Id: %R, Rt: %R, Type: %u, Age: %u, Seqno: 0x%08x, Sum: %u", + log(L_TRACE "%s: LSA Id: %R, Rt: %R, Type: 0x%04x, Age: %u, Seqno: 0x%08x, Sum: 0x%04x", p->name, lsa.id, lsa.rt, lsa.type, lsa.age, lsa.sn, lsa.checksum); } @@ -70,7 +70,7 @@ ospf_lsa_flooding_allowed(struct ospf_lsa_header *lsa, u32 domain, struct ospf_i return 0; if (ifa->oa->stub) return 0; - return 1 + return 1; } else return ifa->oa->areaid == domain; @@ -262,19 +262,13 @@ ospf_lsupd_flood(struct proto_ospf *po, } { - sock *sk; u16 len, age; struct ospf_lsupd_packet *pk; struct ospf_packet *op; struct ospf_lsa_header *lh; - if ((ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_VLINK)) - sk = ifa->ip_sk; - else - sk = ifa->hello_sk; - - pk = (struct ospf_lsupd_packet *) sk->tbuf; - op = (struct ospf_packet *) sk->tbuf; + pk = (struct ospf_lsupd_packet *) ifa->sk->tbuf; + op = (struct ospf_packet *) ifa->sk->tbuf; ospf_pkt_fill_hdr(ifa, pk, LSUPD_P); pk->lsano = htonl(1); @@ -308,28 +302,28 @@ ospf_lsupd_flood(struct proto_ospf *po, op->length = htons(len); - OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) sk->tbuf, + OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) ifa->sk->tbuf, "LSUPD packet flooded via %s", ifa->iface->name); switch (ifa->type) { case OSPF_IT_NBMA: if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR)) - ospf_send_to_agt(sk, ifa, NEIGHBOR_EXCHANGE); + ospf_send_to_agt(ifa, NEIGHBOR_EXCHANGE); else - ospf_send_to_bdr(sk, ifa); + ospf_send_to_bdr(ifa); break; case OSPF_IT_VLINK: - ospf_send_to(sk, ifa->vip, ifa); + ospf_send_to(ifa, ifa->vip); break; default: if ((ifa->state == OSPF_IS_BACKUP) || (ifa->state == OSPF_IS_DR) || (ifa->type == OSPF_IT_PTP)) - ospf_send_to(sk, AllSPFRouters, ifa); + ospf_send_to(ifa, AllSPFRouters); else - ospf_send_to(sk, AllDRouters, ifa); + ospf_send_to(ifa, AllDRouters); } } } @@ -353,8 +347,8 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) if (EMPTY_LIST(*l)) return; - pk = (struct ospf_lsupd_packet *) n->ifa->ip_sk->tbuf; - op = (struct ospf_packet *) n->ifa->ip_sk->tbuf; + pk = (struct ospf_lsupd_packet *) n->ifa->sk->tbuf; + op = (struct ospf_packet *) n->ifa->sk->tbuf; DBG("LSupd: 1st packet\n"); @@ -378,9 +372,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) pk->lsano = htonl(lsano); op->length = htons(len); - OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) n->ifa->ip_sk->tbuf, + OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) n->ifa->sk->tbuf, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name); - ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); + ospf_send_to(n->ifa, n->ip); DBG("LSupd: next packet\n"); ospf_pkt_fill_hdr(n->ifa, pk, LSUPD_P); @@ -401,9 +395,9 @@ ospf_lsupd_send_list(struct ospf_neighbor *n, list * l) pk->lsano = htonl(lsano); op->length = htons(len); - OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) n->ifa->ip_sk->tbuf, + OSPF_PACKET(ospf_dump_lsupd, (struct ospf_lsupd_packet *) n->ifa->sk->tbuf, "LSUPD packet sent to %I via %s", n->ip, n->ifa->iface->name); - ospf_send_to(n->ifa->ip_sk, n->ip, n->ifa); + ospf_send_to(n->ifa, n->ip); } } diff --git a/proto/ospf/neighbor.c b/proto/ospf/neighbor.c index 7847654..aa7bc2f 100644 --- a/proto/ospf/neighbor.c +++ b/proto/ospf/neighbor.c @@ -478,8 +478,8 @@ bdr_election(struct ospf_iface *ifa) || ((ifa->bdrid != myid) && (nbdr == &me))) { #ifdef OSPFv2 - me.dr = ndr ? ipa_to_u32(ndr->ip) : IPA_NONE; - me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : IPA_NONE; + me.dr = ndr ? ipa_to_u32(ndr->ip) : 0; + me.bdr = nbdr ? ipa_to_u32(nbdr->ip) : 0; #else /* OSPFv3 */ me.dr = ndr ? ndr->rid : 0; me.bdr = nbdr ? nbdr->rid : 0; diff --git a/proto/ospf/ospf.h b/proto/ospf/ospf.h index c1d5de7..ae073dd 100644 --- a/proto/ospf/ospf.h +++ b/proto/ospf/ospf.h @@ -18,6 +18,7 @@ * normally allocate 2*mtu - (I found one cisco * sending packets mtu+16) */ +#define LOCAL_DEBUG 1 #ifdef LOCAL_DEBUG #define OSPF_FORCE_DEBUG 1 #else @@ -161,9 +162,7 @@ struct ospf_iface struct iface *iface; /* Nest's iface */ struct ospf_area *oa; struct object_lock *lock; - sock *hello_sk; /* Hello socket */ - sock *dr_sk; /* For states DR or BACKUP */ - sock *ip_sk; /* IP socket (for DD ...) */ + sock *sk; /* IP socket (for DD ...) */ list neigh_list; /* List of neigbours */ u32 cost; /* Cost of iface */ u32 waitint; /* number of sec before changing state from wait */ @@ -241,6 +240,7 @@ struct ospf_iface list nbma_list; u8 priority; /* A router priority for DR election */ u8 ioprob; + u8 dr_up; /* Socket is a member of DRouters group */ u32 rxbuf; }; diff --git a/proto/ospf/packet.c b/proto/ospf/packet.c index 200ef95..0bb1f51 100644 --- a/proto/ospf/packet.c +++ b/proto/ospf/packet.c @@ -437,26 +437,27 @@ ospf_err_hook(sock * sk, int err) } void -ospf_send_to_agt(sock * sk, struct ospf_iface *ifa, u8 state) +ospf_send_to_agt(struct ospf_iface *ifa, u8 state) { struct ospf_neighbor *n; WALK_LIST(n, ifa->neigh_list) if (n->state >= state) - ospf_send_to(sk, n->ip, ifa); + ospf_send_to(ifa, n->ip); } void -ospf_send_to_bdr(sock * sk, struct ospf_iface *ifa) +ospf_send_to_bdr(struct ospf_iface *ifa) { if (!ipa_equal(ifa->drip, IPA_NONE)) - ospf_send_to(sk, ifa->drip, ifa); + ospf_send_to(ifa, ifa->drip); if (!ipa_equal(ifa->bdrip, IPA_NONE)) - ospf_send_to(sk, ifa->bdrip, ifa); + ospf_send_to(ifa, ifa->bdrip); } void -ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa) +ospf_send_to(struct ospf_iface *ifa, ip_addr ip) { + sock *sk = ifa->sk; struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf; int len = ntohs(pkt->length); diff --git a/proto/ospf/packet.h b/proto/ospf/packet.h index b85b608..4d5612f 100644 --- a/proto/ospf/packet.h +++ b/proto/ospf/packet.h @@ -15,9 +15,9 @@ unsigned ospf_pkt_maxsize(struct ospf_iface *ifa); int ospf_rx_hook(sock * sk, int size); void ospf_tx_hook(sock * sk); void ospf_err_hook(sock * sk, int err); -void ospf_send_to_agt(sock * sk, struct ospf_iface *ifa, u8 state); -void ospf_send_to_bdr(sock * sk, struct ospf_iface *ifa); -void ospf_send_to(sock *sk, ip_addr ip, struct ospf_iface *ifa); +void ospf_send_to_agt(struct ospf_iface *ifa, u8 state); +void ospf_send_to_bdr(struct ospf_iface *ifa); +void ospf_send_to(struct ospf_iface *ifa, ip_addr ip); #endif /* _BIRD_OSPF_PACKET_H_ */ diff --git a/proto/ospf/rt.c b/proto/ospf/rt.c index 27bd226..0f6efd7 100644 --- a/proto/ospf/rt.c +++ b/proto/ospf/rt.c @@ -26,6 +26,8 @@ static void rt_sync(struct proto_ospf *po); #endif +#ifdef OSPFv3 + static inline u32 * get_ipv6_prefix(u32 *buf, ip_addr *addr, int *pxlen, u8 *pxopts, u16 *rest) { @@ -56,6 +58,9 @@ get_ipv6_addr(u32 *buf, ip_addr *addr) return buf + 4; } +#endif + + static void fill_ri(orta * orta) { @@ -839,8 +844,8 @@ ospf_ext_spf(struct proto_ospf *po) if (en->lsa.rt == p->cf->global->router_id) continue; - DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u, Mask %I\n", - p->name, en->lsa.id, en->lsa.rt, en->lsa.type, le->netmask); + DBG("%s: Working on LSA. ID: %R, RT: %R, Type: %u\n", + p->name, en->lsa.id, en->lsa.rt, en->lsa.type); le = en->lsa_body; @@ -1056,7 +1061,7 @@ static inline int match_dr(struct ospf_iface *ifa, struct top_hash_entry *en) { #ifdef OSPFv2 - return (ifa->drid == en->lsa.rt) && (ifa->drip == ipa_from_u32(en->lsa.id)); + return (ifa->drid == en->lsa.rt) && (ipa_to_u32(ifa->drip) == en->lsa.id); #else /* OSPFv3 */ return (ifa->drid == en->lsa.rt) && (ifa->dr_iface_id == en->lsa.id); #endif diff --git a/proto/ospf/topology.c b/proto/ospf/topology.c index 8263010..8f64c4c 100644 --- a/proto/ospf/topology.c +++ b/proto/ospf/topology.c @@ -174,7 +174,7 @@ originate_rt_lsa_body(struct ospf_area *oa, u16 *length) ASSERT(po->lsab_used == 0); rt = lsab_allocz(po, sizeof(struct ospf_lsa_rt)); - rt->options = 0 + rt->options = 0; if (po->areano > 1) rt->options |= OPT_RT_B; @@ -445,7 +445,9 @@ update_rt_lsa(struct ospf_area *oa) */ originate_rt_lsa(oa); +#ifdef OSPFv3 originate_prefix_rt_lsa(oa); +#endif schedule_rtcalc(po); oa->origrt = 0; @@ -577,12 +579,16 @@ update_net_lsa(struct ospf_iface *ifa) if ((ifa->state != OSPF_IS_DR) || (ifa->fadj == 0)) { flush_net_lsa(ifa); +#ifdef OSPFv3 flush_prefix_net_lsa(ifa); +#endif } else { originate_net_lsa(ifa); +#ifdef OSPFv3 originate_prefix_net_lsa(ifa); +#endif } schedule_rtcalc(po); @@ -1353,6 +1359,16 @@ ospf_top_rehash(struct top_graph *f, int step) ospf_top_ht_free(oldt); } +#ifdef OSPFv2 + +u32 +ospf_lsa_domain(u32 type, struct ospf_iface *ifa) +{ + return (type == LSA_T_EXT) ? 0 : ifa->oa->areaid; +} + +#else /* OSPFv3 */ + u32 ospf_lsa_domain(u32 type, struct ospf_iface *ifa) { @@ -1370,6 +1386,8 @@ ospf_lsa_domain(u32 type, struct ospf_iface *ifa) } } +#endif + struct top_hash_entry * ospf_hash_find_header(struct top_graph *f, u32 domain, struct ospf_lsa_header *h) { diff --git a/proto/rip/rip.c b/proto/rip/rip.c index c655cc3..f9a160e 100644 --- a/proto/rip/rip.c +++ b/proto/rip/rip.c @@ -684,7 +684,7 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ DBG( "Doing multicasts!\n" ); rif->sock = sk_new( p->pool ); - rif->sock->type = rif->multicast?SK_UDP_MC:SK_UDP; + rif->sock->type = SK_UDP; rif->sock->sport = P_CF->port; rif->sock->rx_hook = rip_rx; rif->sock->data = rif; @@ -721,19 +721,37 @@ new_iface(struct proto *p, struct iface *new, unsigned long flags, struct iface_ if (!ipa_nonzero(rif->sock->daddr)) { if (rif->iface) log( L_WARN "%s: interface %s is too strange for me", p->name, rif->iface->name ); - } else if (sk_open(rif->sock)<0) { - log( L_ERR "%s: could not create socket for %s", p->name, rif->iface ? rif->iface->name : "(dummy)" ); - if (rif->iface) { - rfree(rif->sock); - mb_free(rif); - return NULL; - } - /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */ + } else { + + if (sk_open(rif->sock)<0) + goto err; + + if (rif->multicast) + { + if (sk_setup_multicast(rif->sock) < 0) + goto err; + if (sk_join_group(rif->sock, rif->sock->daddr) < 0) + goto err; + } + else + { + if (sk_set_broadcast(rif->sock, 1) < 0) + goto err; + } } TRACE(D_EVENTS, "Listening on %s, port %d, mode %s (%I)", rif->iface ? rif->iface->name : "(dummy)", P_CF->port, rif->multicast ? "multicast" : "broadcast", rif->sock->daddr ); return rif; + + err: + log( L_ERR "%s: could not create socket for %s", p->name, rif->iface ? rif->iface->name : "(dummy)" ); + if (rif->iface) { + rfree(rif->sock); + mb_free(rif); + return NULL; + } + /* On dummy, we just return non-working socket, so that user gets error every time anyone requests table */ } static void diff --git a/sysdep/bsd/sysio.h b/sysdep/bsd/sysio.h index b0ec456..80f8f94 100644 --- a/sysdep/bsd/sysio.h +++ b/sysdep/bsd/sysio.h @@ -27,48 +27,55 @@ set_inaddr(struct in_addr * ia, ip_addr a) } static inline char * -sysio_mcast_setup(sock * s) +sysio_setup_multicast(sock *s) { - u8 zero = 0; - u8 one = 1; + struct in_addr m; + u8 zero = 0; + u8 ttl = s->ttl; - if (ipa_nonzero(s->daddr)) { + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) + return "IP_MULTICAST_LOOP"; - if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - return "IP_MULTICAST_LOOP"; + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) + return "IP_MULTICAST_TTL"; + + /* This defines where should we send _outgoing_ multicasts */ + set_inaddr(&m, s->iface->addr->ip); + if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) + return "IP_MULTICAST_IF"; - if (setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_TTL, &one, sizeof(one)) < 0) - return "IP_MULTICAST_TTL"; - } return NULL; } static inline char * -sysio_mcast_join(sock * s) +sysio_join_group(sock *s, ip_addr maddr) { - struct in_addr m; struct ip_mreq mreq; - char *err; - - set_inaddr(&m, s->iface->addr->ip ); bzero(&mreq, sizeof(mreq)); set_inaddr(&mreq.imr_interface, s->iface->addr->ip); - set_inaddr(&mreq.imr_multiaddr, s->daddr); + set_inaddr(&mreq.imr_multiaddr, maddr); /* And this one sets interface for _receiving_ multicasts from */ - if (ipa_nonzero(s->daddr) && - setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + if (setsockopt(s->fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) return "IP_ADD_MEMBERSHIP"; + return NULL; +} - /* This defines where should we send _outgoing_ multicasts */ - if (ipa_nonzero(s->daddr) && setsockopt(s->fd, IPPROTO_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) - return "IP_MULTICAST_IF"; +static inline char * +sysio_leave_group(sock *s, ip_addr maddr) +{ + struct ip_mreq mreq; - if (err = sysio_mcast_setup(s)) - return err; + bzero(&mreq, sizeof(mreq)); + set_inaddr(&mreq.imr_interface, s->iface->addr->ip); + set_inaddr(&mreq.imr_multiaddr, maddr); + + /* And this one sets interface for _receiving_ multicasts from */ + if (setsockopt(s->fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + return "IP_DROP_MEMBERSHIP"; return NULL; } diff --git a/sysdep/linux/sysio.h b/sysdep/linux/sysio.h index 2fa5f0a..70d35cc 100644 --- a/sysdep/linux/sysio.h +++ b/sysdep/linux/sysio.h @@ -38,27 +38,33 @@ set_inaddr(struct in_addr *ia, ip_addr a) * ways. Horrible. */ -static inline char *sysio_mcast_setup(sock *s) + +#if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND) +/* + * Older kernels support only struct mreq which matches interfaces by their + * addresses and thus fails on unnumbered devices. On newer 2.0 kernels + * we can use SO_BINDTODEVICE to circumvent this problem. + */ + +#define MREQ_IFA struct in_addr +#define MREQ_GRP struct ip_mreq +static inline void fill_mreq_ifa(struct in_addr *m, struct iface *ifa, UNUSED ip_addr maddr) { - int zero = 0; + set_inaddr(m, ifa->addr->ip); +} - if (ipa_nonzero(s->daddr)) - { - if ( -#ifdef IP_DEFAULT_MULTICAST_TTL - s->ttl != IP_DEFAULT_MULTICAST_TTL && -#endif - setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0) - return "IP_MULTICAST_TTL"; - if ( -#ifdef IP_DEFAULT_MULTICAST_LOOP - IP_DEFAULT_MULTICAST_LOOP && +static inline void fill_mreq_grp(struct ip_mreq *m, struct iface *ifa, ip_addr maddr) +{ + bzero(m, sizeof(*m)); +#ifdef CONFIG_LINUX_MC_MREQ_BIND + m->imr_interface.s_addr = INADDR_ANY; +#else + set_inaddr(&m->imr_interface, ifa->addr->ip); #endif - setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - return "IP_MULTICAST_LOOP"; - } - return NULL; + set_inaddr(&m->imr_multiaddr, maddr); } +#endif + #ifdef CONFIG_LINUX_MC_MREQN /* @@ -76,70 +82,78 @@ struct ip_mreqn }; #endif -static inline char *sysio_mcast_join(sock *s) +#define MREQ_IFA struct ip_mreqn +#define MREQ_GRP struct ip_mreqn +#define fill_mreq_ifa fill_mreq +#define fill_mreq_grp fill_mreq + +static inline fill_mreq(struct ip_mreqn *m, struct iface *ifa, ip_addr maddr) { - struct ip_mreqn mreq; - char *err; - struct ifreq ifr; - - if (err = sysio_mcast_setup(s)) - return err; - strcpy(ifr.ifr_name, s->iface->name); - if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) - return "SO_BINDTODEVICE"; - mreq.imr_ifindex = s->iface->index; - set_inaddr(&mreq.imr_address, s->iface->addr->ip); - set_inaddr(&mreq.imr_multiaddr, s->daddr); - /* This defines where should we send _outgoing_ multicasts */ - if (ipa_nonzero(s->daddr) && setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) - return "IP_MULTICAST_IF"; - /* And this one sets interface for _receiving_ multicasts from */ - if (ipa_nonzero(s->saddr) && setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - return "IP_ADD_MEMBERSHIP"; - return NULL; + bzero(m, sizeof(*m)); + m->imr_ifindex = ifa->index; + set_inaddr(&m->imr_address, ifa->addr->ip); + set_inaddr(&m->imr_multiaddr, maddr); } #endif -#if defined(CONFIG_LINUX_MC_MREQ) || defined(CONFIG_LINUX_MC_MREQ_BIND) -/* - * Older kernels support only struct mreq which matches interfaces by their - * addresses and thus fails on unnumbered devices. On newer 2.0 kernels - * we can use SO_BINDTODEVICE to circumvent this problem. - */ - -static inline char *sysio_mcast_join(sock *s) +static inline char * +sysio_setup_multicast(sock *s) { - struct in_addr mreq; - struct ip_mreq mreq_add; - char *err; + MREQ_IFA m; + int zero = 0; - if (err = sysio_mcast_setup(s)) - return err; - set_inaddr(&mreq, s->iface->addr->ip); -#ifdef CONFIG_LINUX_MC_MREQ_BIND + if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) + return "IP_MULTICAST_LOOP"; + + if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_TTL, &s->ttl, sizeof(s->ttl)) < 0) + return "IP_MULTICAST_TTL"; + + /* This defines where should we send _outgoing_ multicasts */ + fill_mreq_ifa(&m, s->iface, IPA_NONE); + if (setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &m, sizeof(m)) < 0) + return "IP_MULTICAST_IF"; + +#if defined(CONFIG_LINUX_MC_MREQ_BIND) || defined(CONFIG_LINUX_MC_MREQN) { struct ifreq ifr; strcpy(ifr.ifr_name, s->iface->name); if (setsockopt(s->fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) return "SO_BINDTODEVICE"; - mreq_add.imr_interface.s_addr = INADDR_ANY; } -#else - mreq_add.imr_interface = mreq; #endif - set_inaddr(&mreq_add.imr_multiaddr, s->daddr); - /* This defines where should we send _outgoing_ multicasts */ - if (ipa_nonzero(s->daddr) && setsockopt(s->fd, SOL_IP, IP_MULTICAST_IF, &mreq, sizeof(mreq)) < 0) - return "IP_MULTICAST_IF"; + + return NULL; +} + +static inline char * +sysio_join_group(sock *s, ip_addr maddr) +{ + MREQ_GRP m; + /* And this one sets interface for _receiving_ multicasts from */ - if (ipa_nonzero(s->saddr) && setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq_add, sizeof(mreq_add)) < 0) + fill_mreq_grp(&m, s->iface, maddr); + if (setsockopt(s->fd, SOL_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m)) < 0) return "IP_ADD_MEMBERSHIP"; + + return NULL; +} + +static inline char * +sysio_leave_group(sock *s, ip_addr maddr) +{ + MREQ_GRP m; + + /* And this one sets interface for _receiving_ multicasts from */ + fill_mreq_grp(&m, s->iface, maddr); + if (setsockopt(s->fd, SOL_IP, IP_DROP_MEMBERSHIP, &m, sizeof(m)) < 0) + return "IP_DROP_MEMBERSHIP"; + return NULL; } -#endif #endif + #include <linux/socket.h> #include <linux/tcp.h> diff --git a/sysdep/unix/io.c b/sysdep/unix/io.c index d954716..5cc80dc 100644 --- a/sysdep/unix/io.c +++ b/sysdep/unix/io.c @@ -690,8 +690,7 @@ sk_set_ttl_int(sock *s) { int one = 1; #ifdef IPV6 - if (s->type != SK_UDP_MC && s->type != SK_IP_MC && - setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) + if (setsockopt(s->fd, SOL_IPV6, IPV6_UNICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) return "IPV6_UNICAST_HOPS"; #else if (setsockopt(s->fd, SOL_IP, IP_TTL, &s->ttl, sizeof(s->ttl)) < 0) @@ -788,6 +787,134 @@ sk_set_md5_auth(sock *s, ip_addr a, char *passwd) return sk_set_md5_auth_int(s, &sa, passwd); } +int +sk_set_broadcast(sock *s, int enable) +{ + if (setsockopt(s->fd, SOL_SOCKET, SO_BROADCAST, &enable, sizeof(enable)) < 0) + log(L_ERR "sk_set_broadcast: SO_BROADCAST: %m"); +} + + +#ifdef IPV6 + +int +sk_setup_multicast(sock *s) +{ + char *err; + int zero = 0; + int index; + + ASSERT(s->iface && s->iface->addr); + + index = s->iface->index; + if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) + ERR("IPV6_MULTICAST_HOPS"); + if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) + ERR("IPV6_MULTICAST_LOOP"); + if (setsockopt(s->fd, SOL_IPV6, IPV6_MULTICAST_IF, &index, sizeof(index)) < 0) + ERR("IPV6_MULTICAST_IF"); + + return 0; + +bad: + log(L_ERR "sk_setup_multicast: %s: %m", err); + return -1; +} + +int +sk_join_group(sock *s, ip_addr maddr) +{ + struct ipv6_mreq mreq; + + set_inaddr(&mreq.ipv6mr_multiaddr, maddr); + +#ifdef CONFIG_IPV6_GLIBC_20 + mreq.ipv6mr_ifindex = s->iface->index; +#else + mreq.ipv6mr_interface = s->iface->index; +#endif + + /* RFC 2553 says IPV6_JOIN_GROUP */ + if (setsockopt(s->fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + log(L_ERR "sk_join_group: IPV6_ADD_MEMBERSHIP: %m"); + return -1; + } + + return 0; +} + +int +sk_leave_group(sock *s, ip_addr maddr) +{ + struct ipv6_mreq mreq; + + set_inaddr(&mreq.ipv6mr_multiaddr, maddr); + +#ifdef CONFIG_IPV6_GLIBC_20 + mreq.ipv6mr_ifindex = s->iface->index; +#else + mreq.ipv6mr_interface = s->iface->index; +#endif + + /* RFC 2553 says IPV6_LEAVE_GROUP */ + if (setsockopt(s->fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) + { + log(L_ERR "sk_leave_group: IPV6_DROP_MEMBERSHIP: %m"); + return -1; + } + + return 0; +} + +#else /* IPV4 */ + +int +sk_setup_multicast(sock *s) +{ + char *err; + + ASSERT(s->iface && s->iface->addr); + + if (err = sysio_setup_multicast(s)) + { + log(L_ERR "sk_setup_multicast: %s: %m", err); + return -1; + } + + return 0; +} + +int +sk_join_group(sock *s, ip_addr maddr) +{ + char *err; + + if (err = sysio_join_group(s, maddr)) + { + log(L_ERR "sk_join_group: %s: %m", err); + return -1; + } + + return 0; +} + +int +sk_leave_group(sock *s, ip_addr maddr) +{ + char *err; + + if (err = sysio_leave_group(s, maddr)) + { + log(L_ERR "sk_leave_group: %s: %m", err); + return -1; + } + + return 0; +} + +#endif + static void sk_tcp_connected(sock *s) @@ -861,11 +988,9 @@ sk_open(sock *s) fd = socket(BIRD_PF, SOCK_STREAM, IPPROTO_TCP); break; case SK_UDP: - case SK_UDP_MC: fd = socket(BIRD_PF, SOCK_DGRAM, IPPROTO_UDP); break; case SK_IP: - case SK_IP_MC: fd = socket(BIRD_PF, SOCK_RAW, s->dport); break; case SK_MAGIC: @@ -881,59 +1006,11 @@ sk_open(sock *s) if (err = sk_setup(s)) goto bad; - switch (type) - { - case SK_UDP: - case SK_IP: -#ifndef IPV6 - if (s->iface) /* It's a broadcast socket */ - if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0) - ERR("SO_BROADCAST"); -#endif - break; - case SK_UDP_MC: - case SK_IP_MC: - { -#ifdef IPV6 - /* Fortunately, IPv6 socket interface is recent enough and therefore standardized */ - ASSERT(s->iface && s->iface->addr); - if (ipa_nonzero(s->daddr)) - { - int t = s->iface->index; - int zero = 0; - if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &s->ttl, sizeof(s->ttl)) < 0) - ERR("IPV6_MULTICAST_HOPS"); - if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &zero, sizeof(zero)) < 0) - ERR("IPV6_MULTICAST_LOOP"); - if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_IF, &t, sizeof(t)) < 0) - ERR("IPV6_MULTICAST_IF"); - } - if (has_src) - { - struct ipv6_mreq mreq; - set_inaddr(&mreq.ipv6mr_multiaddr, s->daddr); -#ifdef CONFIG_IPV6_GLIBC_20 - mreq.ipv6mr_ifindex = s->iface->index; -#else - mreq.ipv6mr_interface = s->iface->index; -#endif /* CONFIG_IPV6_GLIBC_20 */ - if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) - ERR("IPV6_ADD_MEMBERSHIP"); - } -#else /* IPv4 */ - /* With IPv4 there are zillions of different socket interface variants. Ugh. */ - ASSERT(s->iface && s->iface->addr); - if (err = sysio_mcast_join(s)) - goto bad; -#endif /* IPV6 */ - break; - } - } if (has_src) { int port; - if (type == SK_IP || type == SK_IP_MC) + if (type == SK_IP) port = 0; else { @@ -943,12 +1020,7 @@ sk_open(sock *s) } fill_in_sockaddr(&sa, s->saddr, port); fill_in_sockifa(&sa, s->iface); -#ifdef CONFIG_SKIP_MC_BIND - if ((type != SK_UDP_MC) && (type != SK_IP_MC) && - bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) -#else if (bind(fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) -#endif ERR("bind"); } fill_in_sockaddr(&sa, s->daddr, s->dport); @@ -1069,9 +1141,7 @@ sk_maybe_write(sock *s) s->ttx = s->tpos = s->tbuf; return 1; case SK_UDP: - case SK_UDP_MC: case SK_IP: - case SK_IP_MC: { sockaddr sa; |