When I implemented RFC9234 support I was a bit to conservative and only
enabled the loop detection if the capability was enabled. This is
how every other capability works but RFC9234 is special.
On top of this with the addition of ASPA support the way BGP roles are
handled changed and the code turned up a bit strange.
Considering all of this and rereading RFC9234 I came up with this diff:

- add role output to bgpctl, also adjust the capability output.
  Note, this changes the JSON output of neighbors a bit.
- adjust the config parser to enable the RFC9234 role capability when
  there is a role set. iBGP and sessions with no role will not announce
  the role capability.
- adjust the role capability announcement to be only on sessions that
  use either AFI IPv4 or IPv6 and SAFI 1 (AID_INET, AID_INET6). If a
  session has neither of the two then do not announce the role (even if
  set)
- if there is an OPEN notification indicating that the role capability
  is bad only disable the capability if it is not enforced. If enforced
  do nothing and let the session fail (again and again).
- Adjust capability negotiation, store remote_role on the peer since
  the neighbors role is no longer needed.
- inject the OTC attribute on ingress only for AID_INET and AID_INET6.
  For other AIDs clear the F_ATTR_OTC_LOOP flag since OTC loop detection
  must be skipped for other address families.
- Adjust the role logic in the RDE and use the peer->role (local role of
  the system) for all checks. Also remove the check if the role capability
  was present (removal of peer_has_open_policy()).
  This change switches all role checks from raw capability codes to
  enum role and at the same time flips the logic since the view of the
  checks is changed from remote system to local system.
  The roles change like this: rs <-> rs-client, customer <-> provider,
  peer <-> peer
- In prefix_eligible() check also if the F_ATTR_OTC_LOOP flag is set.
  The RFC requires that prefixes must be considered ineligible (and not
  treat as withdraw)
- When generating an UPDATE include the OTC attribute unless the AID is
  neither AID_INET or AID_INET6 or the roles do not require the addtion.
  No longer depend on peer_has_open_policy() there.

Please test and check that my logic is actually correct and following the
RFC.
-- 
:wq Claudio

Index: usr.sbin/bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.36
diff -u -p -r1.36 output.c
--- usr.sbin/bgpctl/output.c    31 Jan 2023 14:32:43 -0000      1.36
+++ usr.sbin/bgpctl/output.c    28 Feb 2023 05:46:41 -0000
@@ -281,6 +281,8 @@ show_neighbor_full(struct peer *p, struc
        printf("\n");
        if (p->conf.descr[0])
                printf(" Description: %s\n", p->conf.descr);
+       if (p->conf.ebgp && p->conf.role != ROLE_NONE)
+               printf(" Role: %s\n", log_policy(p->conf.role));
        if (p->conf.max_prefix) {
                printf(" Max-prefix: %u", p->conf.max_prefix);
                if (p->conf.max_prefix_restart)
@@ -330,7 +332,7 @@ show_neighbor_full(struct peer *p, struc
        }
        if (hascapamp || hascapaap || p->capa.peer.grestart.restart ||
            p->capa.peer.refresh || p->capa.peer.enhanced_rr ||
-           p->capa.peer.as4byte || p->capa.peer.role_ena) {
+           p->capa.peer.as4byte || p->capa.peer.policy) {
                printf("  Neighbor capabilities:\n");
                if (hascapamp)
                        show_neighbor_capa_mp(&p->capa.peer);
@@ -344,10 +346,10 @@ show_neighbor_full(struct peer *p, struc
                        show_neighbor_capa_restart(&p->capa.peer);
                if (hascapaap)
                        show_neighbor_capa_add_path(&p->capa.peer);
-               if (p->capa.peer.role_ena)
+               if (p->capa.peer.policy)
                        printf("    Open Policy role %s (local %s)\n",
-                           log_policy(p->capa.peer.role),
-                           log_policy(p->capa.ann.role));
+                           log_policy(p->remote_role),
+                           log_policy(p->conf.role));
        }
 
        hascapamp = 0;
@@ -360,7 +362,7 @@ show_neighbor_full(struct peer *p, struc
        }
        if (hascapamp || hascapaap || p->capa.neg.grestart.restart ||
            p->capa.neg.refresh || p->capa.neg.enhanced_rr ||
-           p->capa.neg.as4byte || p->capa.neg.role_ena) {
+           p->capa.neg.as4byte || p->capa.neg.policy) {
                printf("  Negotiated capabilities:\n");
                if (hascapamp)
                        show_neighbor_capa_mp(&p->capa.neg);
@@ -374,10 +376,10 @@ show_neighbor_full(struct peer *p, struc
                        show_neighbor_capa_restart(&p->capa.neg);
                if (hascapaap)
                        show_neighbor_capa_add_path(&p->capa.neg);
-               if (p->capa.neg.role_ena)
+               if (p->capa.neg.policy)
                        printf("    Open Policy role %s (local %s)\n",
-                           log_policy(p->capa.neg.role),
-                           log_policy(p->capa.ann.role));
+                           log_policy(p->remote_role),
+                           log_policy(p->conf.role));
        }
        printf("\n");
 
Index: usr.sbin/bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.29
diff -u -p -r1.29 output_json.c
--- usr.sbin/bgpctl/output_json.c       24 Jan 2023 11:29:34 -0000      1.29
+++ usr.sbin/bgpctl/output_json.c       28 Feb 2023 05:41:27 -0000
@@ -125,10 +125,9 @@ json_neighbor_capabilities(struct capabi
                json_do_end();
        }
 
-       if (capa->role_ena) {
-               json_do_printf("open_policy_role", "%s%s",
-                   log_policy(capa->role),
-                   capa->role_ena == 2 ? " enforce" : "");
+       if (capa->policy) {
+               json_do_printf("open_policy", "%s",
+                   capa->policy == 2 ? "enforce" : "present");
        }
 
        json_do_end();
@@ -248,6 +247,9 @@ json_neighbor_full(struct peer *p)
        json_do_bool("ttl_security", p->conf.ttlsec);
        json_do_uint("holdtime", p->conf.holdtime);
        json_do_uint("min_holdtime", p->conf.min_holdtime);
+       if (p->conf.ebgp && p->conf.role != ROLE_NONE)
+               json_do_printf("role", "%s",
+                   log_policy(p->conf.role));
 
        /* capabilities */
        json_do_bool("announce_capabilities", p->conf.announce_capa);
@@ -296,6 +298,12 @@ json_neighbor_full(struct peer *p)
                /* capabilities */
                json_neighbor_capabilities(&p->capa.neg);
 
+               if (p->conf.ebgp && p->conf.role != ROLE_NONE) {
+                       json_do_printf("remote_role", "%s",
+                           log_policy(p->remote_role));
+                       json_do_printf("local_role", "%s",
+                           log_policy(p->conf.role));
+               }
                json_do_end();
        }
 }
Index: usr.sbin/bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.461
diff -u -p -r1.461 bgpd.h
--- usr.sbin/bgpd/bgpd.h        9 Feb 2023 13:43:23 -0000       1.461
+++ usr.sbin/bgpd/bgpd.h        28 Feb 2023 04:23:31 -0000
@@ -398,13 +398,12 @@ struct capabilities {
                int8_t  flags[AID_MAX]; /* graceful restart per AID flags */
                int8_t  restart;        /* graceful restart, RFC 4724 */
        }       grestart;
-       enum role role;                 /* Open Policy, RFC 9234 */
        int8_t  mp[AID_MAX];            /* multiprotocol extensions, RFC 4760 */
        int8_t  add_path[AID_MAX];      /* ADD_PATH, RFC 7911 */
        int8_t  refresh;                /* route refresh, RFC 2918 */
        int8_t  as4byte;                /* 4-byte ASnum, RFC 4893 */
        int8_t  enhanced_rr;            /* enhanced route refresh, RFC 7313 */
-       int8_t  role_ena;               /* 1 for enable, 2 for enforce */
+       int8_t  policy;                 /* Open Policy, RFC 9234, 2 = enforce */
 };
 
 /* flags for RFC 4724 - graceful restart */
Index: usr.sbin/bgpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.441
diff -u -p -r1.441 parse.y
--- usr.sbin/bgpd/parse.y       30 Jan 2023 16:51:34 -0000      1.441
+++ usr.sbin/bgpd/parse.y       28 Feb 2023 11:35:51 -0000
@@ -1642,7 +1642,7 @@ peeropts  : REMOTEAS as4number    {
                        curpeer->conf.eval.maxpaths = $6;
                }
                | ANNOUNCE POLICY enforce {
-                       curpeer->conf.capabilities.role_ena = $3;
+                       curpeer->conf.capabilities.policy = $3;
                }
                | ROLE STRING {
                        if (strcmp($2, "provider") == 0) {
@@ -4284,6 +4284,7 @@ alloc_peer(void)
        p->conf.capabilities.refresh = 1;
        p->conf.capabilities.grestart.restart = 1;
        p->conf.capabilities.as4byte = 1;
+       p->conf.capabilities.policy = 1;
        p->conf.local_as = conf->as;
        p->conf.local_short_as = conf->short_as;
        p->conf.remote_port = BGP_PORT;
@@ -4736,12 +4737,13 @@ neighbor_consistent(struct peer *p)
        }
 
        /* BGP role and RFC 9234 role are only valid for EBGP neighbors */
-       if (p->conf.ebgp) {
-               if (p->conf.role == ROLE_NONE)
-                       p->conf.capabilities.role_ena = 0;
-               p->conf.capabilities.role = p->conf.role;
-       } else
+       if (!p->conf.ebgp) {
                p->conf.role = ROLE_NONE;
+               p->conf.capabilities.policy = 0;
+       } else if (p->conf.role == ROLE_NONE) {
+               /* no role, no policy capability */
+               p->conf.capabilities.policy = 0;
+       }
 
        /* check for duplicate peer definitions */
        RB_FOREACH(xp, peer_head, new_peers)
Index: usr.sbin/bgpd/printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.163
diff -u -p -r1.163 printconf.c
--- usr.sbin/bgpd/printconf.c   24 Jan 2023 14:13:12 -0000      1.163
+++ usr.sbin/bgpd/printconf.c   28 Feb 2023 04:24:06 -0000
@@ -847,9 +847,9 @@ print_announce(struct peer_config *p, co
                        printf(" max %d", p->eval.maxpaths);
                printf("\n");
        }
-       if (p->capabilities.role_ena) {
+       if (p->capabilities.policy) {
                printf("%s\tannounce policy %s\n", c,
-                   p->capabilities.role_ena == 2 ? "enforce" : "yes");
+                   p->capabilities.policy == 2 ? "enforce" : "yes");
        }
 }
 
Index: usr.sbin/bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.593
diff -u -p -r1.593 rde.c
--- usr.sbin/bgpd/rde.c 13 Feb 2023 18:07:53 -0000      1.593
+++ usr.sbin/bgpd/rde.c 28 Feb 2023 05:52:08 -0000
@@ -1242,7 +1242,7 @@ rde_update_dispatch(struct rde_peer *pee
        uint16_t                 withdrawn_len;
        uint16_t                 attrpath_len;
        uint16_t                 nlri_len;
-       uint8_t                  aid, prefixlen, safi, subtype, role;
+       uint8_t                  aid, prefixlen, safi, subtype;
        uint32_t                 fas, pathid;
 
        p = imsg->data;
@@ -1324,26 +1324,6 @@ rde_update_dispatch(struct rde_peer *pee
                        }
                }
 
-               /* inject open policy OTC attribute if needed */
-               if (peer_has_open_policy(peer, &role) &&
-                   (state.aspath.flags & F_ATTR_OTC) == 0) {
-                       uint32_t tmp;
-                       switch (role) {
-                       case CAPA_ROLE_PROVIDER:
-                       case CAPA_ROLE_RS:
-                       case CAPA_ROLE_PEER:
-                               tmp = htonl(peer->conf.remote_as);
-                               if (attr_optadd(&state.aspath,
-                                   ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_OTC,
-                                   &tmp, sizeof(tmp)) == -1) {
-                                       rde_update_err(peer, ERR_UPDATE,
-                                           ERR_UPD_ATTRLIST, NULL, 0);
-                                       goto done;
-                               }
-                               state.aspath.flags |= F_ATTR_OTC;
-                       }
-               }
-
                /* aspath needs to be loop free. This is not a hard error. */
                if (state.aspath.flags & F_ATTR_ASPATH &&
                    peer->conf.ebgp &&
@@ -1520,6 +1500,28 @@ rde_update_dispatch(struct rde_peer *pee
                            NULL, 0);
                        goto done;
                }
+
+               /* inject open policy OTC attribute if needed */
+               if ((state.aspath.flags & F_ATTR_OTC) == 0) {
+                       uint32_t tmp;
+                       switch (peer->role) {
+                       case ROLE_CUSTOMER:
+                       case ROLE_RS_CLIENT:
+                       case ROLE_PEER:
+                               tmp = htonl(peer->conf.remote_as);
+                               if (attr_optadd(&state.aspath,
+                                   ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_OTC,
+                                   &tmp, sizeof(tmp)) == -1) {
+                                       rde_update_err(peer, ERR_UPDATE,
+                                           ERR_UPD_ATTRLIST, NULL, 0);
+                                       goto done;
+                               }
+                               state.aspath.flags |= F_ATTR_OTC;
+                               break;
+                       default:
+                               break;
+                       }
+               }
        }
        while (nlri_len > 0) {
                if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
@@ -1580,6 +1582,34 @@ rde_update_dispatch(struct rde_peer *pee
                        goto done;
                }
 
+               if (aid == AID_INET6) {
+                       /* inject open policy OTC attribute if needed */
+                       if ((state.aspath.flags & F_ATTR_OTC) == 0) {
+                               uint32_t tmp;
+                               switch (peer->role) {
+                               case ROLE_CUSTOMER:
+                               case ROLE_RS_CLIENT:
+                               case ROLE_PEER:
+                                       tmp = htonl(peer->conf.remote_as);
+                                       if (attr_optadd(&state.aspath,
+                                           ATTR_OPTIONAL|ATTR_TRANSITIVE,
+                                           ATTR_OTC, &tmp,
+                                           sizeof(tmp)) == -1) {
+                                               rde_update_err(peer, ERR_UPDATE,
+                                                   ERR_UPD_ATTRLIST, NULL, 0);
+                                               goto done;
+                                       }
+                                       state.aspath.flags |= F_ATTR_OTC;
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+               } else {
+                       /* Only IPv4 and IPv6 unicast do OTC handling */
+                       state.aspath.flags &= ~F_ATTR_OTC_LOOP;
+               }
+
                /* unlock the previously locked nexthop, it is no longer used */
                nexthop_unref(state.nexthop);
                state.nexthop = NULL;
@@ -1824,7 +1854,7 @@ rde_attr_parse(u_char *p, uint16_t len, 
        int              error;
        uint16_t         attr_len, nlen;
        uint16_t         plen = 0;
-       uint8_t          flags, type, role, tmp8;
+       uint8_t          flags, type, tmp8;
 
        if (len < 3) {
 bad_len:
@@ -2160,20 +2190,19 @@ bad_flags:
                if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
                    ATTR_PARTIAL))
                        goto bad_flags;
-               if (peer_has_open_policy(peer, &role)) {
-                       switch (role) {
-                       case CAPA_ROLE_CUSTOMER:
-                       case CAPA_ROLE_RS_CLIENT:
-                               a->flags |= F_ATTR_OTC_LOOP | F_ATTR_PARSE_ERR;
-                               break;
-                       case CAPA_ROLE_PEER:
-                               memcpy(&tmp32, p, sizeof(tmp32));
-                               tmp32 = ntohl(tmp32);
-                               if (tmp32 != peer->conf.remote_as)
-                                       a->flags |= F_ATTR_OTC_LOOP |
-                                           F_ATTR_PARSE_ERR;
-                               break;
-                       }
+               switch (peer->role) {
+               case ROLE_PROVIDER:
+               case ROLE_RS:
+                       a->flags |= F_ATTR_OTC_LOOP;
+                       break;
+               case ROLE_PEER:
+                       memcpy(&tmp32, p, sizeof(tmp32));
+                       tmp32 = ntohl(tmp32);
+                       if (tmp32 != peer->conf.remote_as)
+                               a->flags |= F_ATTR_OTC_LOOP;
+                       break;
+               default:
+                       break;
                }
                a->flags |= F_ATTR_OTC;
                goto optattr;
Index: usr.sbin/bgpd/rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.283
diff -u -p -r1.283 rde.h
--- usr.sbin/bgpd/rde.h 13 Feb 2023 18:07:53 -0000      1.283
+++ usr.sbin/bgpd/rde.h 28 Feb 2023 05:30:22 -0000
@@ -400,7 +400,6 @@ int         rde_match_peer(struct rde_peer *, s
 /* rde_peer.c */
 int             peer_has_as4byte(struct rde_peer *);
 int             peer_has_add_path(struct rde_peer *, uint8_t, int);
-int             peer_has_open_policy(struct rde_peer *, uint8_t *);
 int             peer_accept_no_as_set(struct rde_peer *);
 void            peer_init(void);
 void            peer_shutdown(void);
Index: usr.sbin/bgpd/rde_decide.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_decide.c,v
retrieving revision 1.99
diff -u -p -r1.99 rde_decide.c
--- usr.sbin/bgpd/rde_decide.c  13 Feb 2023 18:07:53 -0000      1.99
+++ usr.sbin/bgpd/rde_decide.c  28 Feb 2023 05:31:32 -0000
@@ -487,7 +487,8 @@ prefix_eligible(struct prefix *p)
        struct rde_aspath *asp = prefix_aspath(p);
 
        /* The aspath needs to be loop and error free */
-       if (asp == NULL || asp->flags & (F_ATTR_LOOP|F_ATTR_PARSE_ERR))
+       if (asp == NULL ||
+           asp->flags & (F_ATTR_LOOP|F_ATTR_OTC_LOOP|F_ATTR_PARSE_ERR))
                return 0;
 
        /* The nexthop must be valid. */
Index: usr.sbin/bgpd/rde_peer.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
retrieving revision 1.29
diff -u -p -r1.29 rde_peer.c
--- usr.sbin/bgpd/rde_peer.c    13 Feb 2023 18:07:53 -0000      1.29
+++ usr.sbin/bgpd/rde_peer.c    28 Feb 2023 05:30:09 -0000
@@ -62,13 +62,6 @@ peer_has_add_path(struct rde_peer *peer,
 }
 
 int
-peer_has_open_policy(struct rde_peer *peer, uint8_t *role)
-{
-       *role = peer->capa.role;
-       return (peer->capa.role_ena != 0);
-}
-
-int
 peer_accept_no_as_set(struct rde_peer *peer)
 {
        return (peer->flags & PEERFLAG_NO_AS_SET);
Index: usr.sbin/bgpd/rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.156
diff -u -p -r1.156 rde_update.c
--- usr.sbin/bgpd/rde_update.c  13 Feb 2023 18:07:53 -0000      1.156
+++ usr.sbin/bgpd/rde_update.c  28 Feb 2023 05:51:50 -0000
@@ -66,7 +66,7 @@ up_test_update(struct rde_peer *peer, st
 
        if (asp == NULL || asp->flags & F_ATTR_PARSE_ERR)
                fatalx("try to send out a botched path");
-       if (asp->flags & F_ATTR_LOOP)
+       if (asp->flags & (F_ATTR_LOOP | F_ATTR_OTC_LOOP))
                fatalx("try to send out a looped path");
 
        if (peer == frompeer)
@@ -104,27 +104,28 @@ up_test_update(struct rde_peer *peer, st
 
 /* RFC9234 open policy handling */
 static int
-up_enforce_open_policy(struct rde_peer *peer, struct filterstate *state)
+up_enforce_open_policy(struct rde_peer *peer, struct filterstate *state,
+    uint8_t aid)
 {
-       uint8_t role;
-
-       if (!peer_has_open_policy(peer, &role))
+       /* only for IPv4 and IPv6 unicast */
+       if (aid != AID_INET && aid != AID_INET6)
                return 0;
 
        /*
         * do not propagate (consider it filtered) if OTC is present and
-        * neighbor role is peer, provider or rs.
+        * local role is peer, customer or rs-client.
         */
-       if (role == CAPA_ROLE_PEER || role == CAPA_ROLE_PROVIDER ||
-           role == CAPA_ROLE_RS)
+       if (peer->role == ROLE_PEER || peer->role == ROLE_CUSTOMER ||
+           peer->role == ROLE_RS_CLIENT)
                if (state->aspath.flags & F_ATTR_OTC)
-                       return (1);
+                       return 1;
 
        /*
-        * add OTC attribute if not present for peers, customers and rs-clients.
+        * add OTC attribute if not present towards peers, customers and
+        * rs-clients (local roles peer, provider, rs).
         */
-       if (role == CAPA_ROLE_PEER || role == CAPA_ROLE_CUSTOMER ||
-           role == CAPA_ROLE_RS_CLIENT)
+       if (peer->role == ROLE_PEER || peer->role == ROLE_PROVIDER ||
+           peer->role == ROLE_RS)
                if ((state->aspath.flags & F_ATTR_OTC) == 0) {
                        uint32_t tmp;
 
@@ -172,7 +173,7 @@ up_process_prefix(struct filter_head *ru
        }
 
        /* Open Policy Check: acts like an output filter */
-       if (up_enforce_open_policy(peer, &state)) {
+       if (up_enforce_open_policy(peer, &state, addr->aid)) {
                rde_filterstate_clean(&state);
                return UP_FILTERED;
        }
Index: usr.sbin/bgpd/session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.441
diff -u -p -r1.441 session.c
--- usr.sbin/bgpd/session.c     14 Feb 2023 15:37:45 -0000      1.441
+++ usr.sbin/bgpd/session.c     28 Feb 2023 10:39:27 -0000
@@ -1475,10 +1475,12 @@ session_open(struct peer *p)
                errs += session_capa_add(opb, CAPA_REFRESH, 0);
 
        /* BGP open policy, RFC 9234, only for ebgp sessions */
-       if (p->conf.ebgp && p->capa.ann.role_ena &&
-           p->capa.ann.role != ROLE_NONE) {
+       if (p->conf.ebgp && p->capa.ann.policy &&
+           p->conf.role != ROLE_NONE &&
+           (p->capa.ann.mp[AID_INET] || p->capa.ann.mp[AID_INET6] ||
+           mpcapa == 0)) {
                uint8_t val;
-               val = role2capa(p->capa.ann.role);
+               val = role2capa(p->conf.role);
                errs += session_capa_add(opb, CAPA_ROLE, 1);
                errs += ibuf_add(opb, &val, 1);
        }
@@ -2515,9 +2517,15 @@ parse_notification(struct peer *peer)
                                    "disabling route refresh capability");
                                break;
                        case CAPA_ROLE:
-                               peer->capa.ann.role_ena = 0;
-                               log_peer_warnx(&peer->conf,
-                                   "disabling role capability");
+                               if (peer->capa.ann.policy == 1) {
+                                       peer->capa.ann.policy = 0;
+                                       log_peer_warnx(&peer->conf,
+                                           "disabling role capability");
+                               } else {
+                                       log_peer_warnx(&peer->conf,
+                                           "role capability enforced, "
+                                           "not disabling");
+                               }
                                break;
                        case CAPA_RESTART:
                                peer->capa.ann.grestart.restart = 0;
@@ -2660,11 +2668,13 @@ parse_capabilities(struct peer *peer, u_
                                    "Bad role capability length: %u", capa_len);
                                break;
                        }
-                       if (!peer->conf.ebgp)
+                       if (!peer->conf.ebgp) {
                                log_peer_warnx(&peer->conf,
                                    "Received role capability on iBGP session");
-                       peer->capa.peer.role_ena = 1;
-                       peer->capa.peer.role = capa2role(*capa_val);
+                               break;
+                       }
+                       peer->capa.peer.policy = 1;
+                       peer->remote_role = capa2role(*capa_val);
                        break;
                case CAPA_RESTART:
                        if (capa_len == 2) {
@@ -2880,40 +2890,40 @@ capa_neg_calc(struct peer *p, uint8_t *s
         * See RFC 9234, section 4.2.
         * These checks should only happen on ebgp sessions.
         */
-       if (p->capa.ann.role_ena != 0 && p->capa.peer.role_ena != 0 &&
+       if (p->capa.ann.policy != 0 && p->capa.peer.policy != 0 &&
            p->conf.ebgp) {
-               switch (p->capa.ann.role) {
+               switch (p->conf.role) {
                case ROLE_PROVIDER:
-                       if (p->capa.peer.role != ROLE_CUSTOMER)
+                       if (p->remote_role != ROLE_CUSTOMER)
                                goto fail;
                        break;
                case ROLE_RS:
-                       if (p->capa.peer.role != ROLE_RS_CLIENT)
+                       if (p->remote_role != ROLE_RS_CLIENT)
                                goto fail;
                        break;
                case ROLE_RS_CLIENT:
-                       if (p->capa.peer.role != ROLE_RS)
+                       if (p->remote_role != ROLE_RS)
                                goto fail;
                        break;
                case ROLE_CUSTOMER:
-                       if (p->capa.peer.role != ROLE_PROVIDER)
+                       if (p->remote_role != ROLE_PROVIDER)
                                goto fail;
                        break;
                case ROLE_PEER:
-                       if (p->capa.peer.role != ROLE_PEER)
+                       if (p->remote_role != ROLE_PEER)
                                goto fail;
                        break;
                default:
  fail:
                        log_peer_warnx(&p->conf, "open policy role mismatch: "
-                           "%s vs %s", log_policy(p->capa.ann.role),
-                           log_policy(p->capa.peer.role));
+                           "our role %s, their role %s",
+                           log_policy(p->conf.role),
+                           log_policy(p->remote_role));
                        *suberr = ERR_OPEN_ROLE;
                        return (-1);
                }
-               p->capa.neg.role_ena = 1;
-               p->capa.neg.role = p->capa.peer.role;
-       } else if (p->capa.ann.role_ena == 2 && p->conf.ebgp) {
+               p->capa.neg.policy = 1;
+       } else if (p->capa.ann.policy == 2 && p->conf.ebgp) {
                /* enforce presence of open policy role capability */
                log_peer_warnx(&p->conf, "open policy role enforced but "
                    "not present");
Index: usr.sbin/bgpd/session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.159
diff -u -p -r1.159 session.h
--- usr.sbin/bgpd/session.h     9 Feb 2023 13:43:23 -0000       1.159
+++ usr.sbin/bgpd/session.h     28 Feb 2023 04:46:25 -0000
@@ -243,6 +243,7 @@ struct peer {
        enum session_state       state;
        enum session_state       prev_state;
        enum reconf_action       reconf_action;
+       enum role                remote_role;
        uint16_t                 short_as;
        uint16_t                 holdtime;
        uint16_t                 local_port;

Reply via email to