From 5ba859777b5b1cc80634573caa3437a0887ad5ae Mon Sep 17 00:00:00 2001 From: renato Date: Fri, 1 Jul 2016 23:33:46 +0000 Subject: [PATCH] Be more compliant with RFC 4447. When sending a label withdraw during the pseudowire Control Word negotiation, append a "Wrong C-bit" status TLV after the FEC TLV (in conformance to RFC 4447 section 6.2). Apparently this has no use other than aiding in troubleshooting. Also, extend the recv_labelmessage() function to accept Status TLVs and ignore them instead of shutting down the session. --- usr.sbin/ldpd/l2vpn.c | 10 +++++++--- usr.sbin/ldpd/labelmapping.c | 17 ++++++++++++++--- usr.sbin/ldpd/lde.c | 21 +++++++++++++++------ usr.sbin/ldpd/lde.h | 4 ++-- usr.sbin/ldpd/ldpd.h | 16 +++++++++++----- usr.sbin/ldpd/ldpe.h | 3 ++- usr.sbin/ldpd/notification.c | 6 ++---- 7 files changed, 53 insertions(+), 24 deletions(-) diff --git a/usr.sbin/ldpd/l2vpn.c b/usr.sbin/ldpd/l2vpn.c index 0c973887a74..cdd0985ef5c 100644 --- a/usr.sbin/ldpd/l2vpn.c +++ b/usr.sbin/ldpd/l2vpn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: l2vpn.c,v 1.19 2016/06/27 19:08:39 renato Exp $ */ +/* $OpenBSD: l2vpn.c,v 1.20 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2015 Renato Westphal @@ -258,6 +258,7 @@ int l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) { struct l2vpn_pw *pw; + struct status_tlv status; /* NOTE: thanks martini & friends for all this mess */ @@ -277,8 +278,11 @@ l2vpn_pw_negotiate(struct lde_nbr *ln, struct fec_node *fn, struct map *map) return (1); } else if (!(map->flags & F_MAP_PW_CWORD) && (pw->flags & F_PW_CWORD_CONF)) { - /* TODO append a "Wrong C-bit" status code */ - lde_send_labelwithdraw(ln, fn, NO_LABEL); + /* append a "Wrong C-bit" status code */ + status.status_code = S_WRONG_CBIT; + status.msg_id = map->messageid; + status.msg_type = htons(MSG_TYPE_LABELMAPPING); + lde_send_labelwithdraw(ln, fn, NO_LABEL, &status); pw->flags &= ~F_PW_CWORD; lde_send_labelmapping(ln, fn, 1); diff --git a/usr.sbin/ldpd/labelmapping.c b/usr.sbin/ldpd/labelmapping.c index 43dc7a0c32b..501cec93075 100644 --- a/usr.sbin/ldpd/labelmapping.c +++ b/usr.sbin/ldpd/labelmapping.c @@ -1,4 +1,4 @@ -/* $OpenBSD: labelmapping.c,v 1.53 2016/07/01 23:29:55 renato Exp $ */ +/* $OpenBSD: labelmapping.c,v 1.54 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2014, 2015 Renato Westphal @@ -75,7 +75,6 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) /* calculate size */ msg_size = LDP_MSG_SIZE + TLV_HDR_LEN; - switch (me->map.type) { case MAP_TYPE_WILDCARD: msg_size += FEC_ELM_WCARD_LEN; @@ -95,11 +94,12 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) msg_size += PW_STATUS_TLV_LEN; break; } - if (me->map.label != NO_LABEL) msg_size += LABEL_TLV_LEN; if (me->map.flags & F_MAP_REQ_ID) msg_size += REQID_TLV_LEN; + if (me->map.flags & F_MAP_STATUS) + msg_size += STATUS_SIZE; /* maximum pdu length exceeded, we need a new ldp pdu */ if (size + msg_size > nbr->max_pdu_len) { @@ -119,6 +119,9 @@ send_labelmessage(struct nbr *nbr, uint16_t type, struct mapping_head *mh) err |= gen_reqid_tlv(buf, me->map.requestid); if (me->map.flags & F_MAP_PW_STATUS) err |= gen_pw_status_tlv(buf, me->map.pw_status); + if (me->map.flags & F_MAP_STATUS) + err |= gen_status_tlv(buf, me->map.status.code, + me->map.status.msg_id, me->map.status.msg_type); if (err) { ibuf_free(buf); return; @@ -304,6 +307,14 @@ recv_labelmessage(struct nbr *nbr, char *buf, uint16_t len, uint16_t type) break; } break; + case TLV_TYPE_STATUS: + if (tlv_len != STATUS_TLV_LEN) { + session_shutdown(nbr, S_BAD_TLV_LEN, + lm.msgid, lm.type); + goto err; + } + /* ignore */ + break; case TLV_TYPE_PW_STATUS: switch (type) { case MSG_TYPE_LABELMAPPING: diff --git a/usr.sbin/ldpd/lde.c b/usr.sbin/ldpd/lde.c index cb0553d1eed..81fe48e256b 100644 --- a/usr.sbin/ldpd/lde.c +++ b/usr.sbin/ldpd/lde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.c,v 1.59 2016/06/18 01:25:53 renato Exp $ */ +/* $OpenBSD: lde.c,v 1.60 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal @@ -816,7 +816,8 @@ lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) } void -lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) +lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label, + struct status_tlv *status) { struct lde_wdraw *lw; struct map map; @@ -851,6 +852,13 @@ lde_send_labelwithdraw(struct lde_nbr *ln, struct fec_node *fn, uint32_t label) map.label = label; } + if (status) { + map.status.code = status->status_code; + map.status.msg_id = status->msg_id; + map.status.msg_type = status->msg_type; + map.flags |= F_MAP_STATUS; + } + /* SWd.1: send label withdraw. */ lde_imsg_compose_ldpe(IMSG_WITHDRAW_ADD, ln->peerid, 0, &map, sizeof(map)); @@ -881,7 +889,7 @@ lde_send_labelwithdraw_all(struct fec_node *fn, uint32_t label) struct lde_nbr *ln; RB_FOREACH(ln, nbr_tree, &lde_nbrs) - lde_send_labelwithdraw(ln, fn, label); + lde_send_labelwithdraw(ln, fn, label, NULL); } void @@ -1182,14 +1190,15 @@ lde_change_egress_label(int af, int was_implicit) RB_FOREACH(ln, nbr_tree, &lde_nbrs) { /* explicit withdraw */ if (was_implicit) - lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL); + lde_send_labelwithdraw(ln, NULL, MPLS_LABEL_IMPLNULL, + NULL); else { if (ln->v4_enabled) lde_send_labelwithdraw(ln, NULL, - MPLS_LABEL_IPV4NULL); + MPLS_LABEL_IPV4NULL, NULL); if (ln->v6_enabled) lde_send_labelwithdraw(ln, NULL, - MPLS_LABEL_IPV6NULL); + MPLS_LABEL_IPV6NULL, NULL); } /* advertise new label of connected prefixes */ diff --git a/usr.sbin/ldpd/lde.h b/usr.sbin/ldpd/lde.h index d882d77c0e8..3d2a06c48cb 100644 --- a/usr.sbin/ldpd/lde.h +++ b/usr.sbin/ldpd/lde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: lde.h,v 1.41 2016/06/18 17:13:05 renato Exp $ */ +/* $OpenBSD: lde.h,v 1.42 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal @@ -134,7 +134,7 @@ void lde_map2fec(struct map *, struct in_addr, struct fec *); void lde_send_labelmapping(struct lde_nbr *, struct fec_node *, int); void lde_send_labelwithdraw(struct lde_nbr *, struct fec_node *, - uint32_t); + uint32_t, struct status_tlv *); void lde_send_labelwithdraw_all(struct fec_node *, uint32_t); void lde_send_labelrelease(struct lde_nbr *, struct fec_node *, uint32_t); diff --git a/usr.sbin/ldpd/ldpd.h b/usr.sbin/ldpd/ldpd.h index 03a90a46a12..de7902f381b 100644 --- a/usr.sbin/ldpd/ldpd.h +++ b/usr.sbin/ldpd/ldpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpd.h,v 1.78 2016/07/01 23:14:31 renato Exp $ */ +/* $OpenBSD: ldpd.h,v 1.79 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal @@ -205,16 +205,22 @@ struct map { uint16_t ifmtu; } pwid; } fec; + struct { + uint32_t code; + uint32_t msg_id; + uint16_t msg_type; + } status; uint32_t label; uint32_t requestid; uint32_t pw_status; uint8_t flags; }; #define F_MAP_REQ_ID 0x01 /* optional request message id present */ -#define F_MAP_PW_CWORD 0x02 /* pseudowire control word */ -#define F_MAP_PW_ID 0x04 /* pseudowire connection id */ -#define F_MAP_PW_IFMTU 0x08 /* pseudowire interface parameter */ -#define F_MAP_PW_STATUS 0x10 /* pseudowire status */ +#define F_MAP_STATUS 0x02 /* status */ +#define F_MAP_PW_CWORD 0x04 /* pseudowire control word */ +#define F_MAP_PW_ID 0x08 /* pseudowire connection id */ +#define F_MAP_PW_IFMTU 0x10 /* pseudowire interface parameter */ +#define F_MAP_PW_STATUS 0x20 /* pseudowire status */ struct notify_msg { uint32_t status; diff --git a/usr.sbin/ldpd/ldpe.h b/usr.sbin/ldpd/ldpe.h index 4d9d77dfc57..84f4c2a74ef 100644 --- a/usr.sbin/ldpd/ldpe.h +++ b/usr.sbin/ldpd/ldpe.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ldpe.h,v 1.65 2016/07/01 23:29:55 renato Exp $ */ +/* $OpenBSD: ldpe.h,v 1.66 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2013, 2016 Renato Westphal @@ -163,6 +163,7 @@ void send_notification(uint32_t, struct tcp_conn *, uint32_t, uint16_t); void send_notification_nbr(struct nbr *, uint32_t, uint32_t, uint16_t); int recv_notification(struct nbr *, char *, uint16_t); +int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); /* address.c */ void send_address(struct nbr *, int, struct if_addr *, int); diff --git a/usr.sbin/ldpd/notification.c b/usr.sbin/ldpd/notification.c index 6c290ceaa82..b482c099068 100644 --- a/usr.sbin/ldpd/notification.c +++ b/usr.sbin/ldpd/notification.c @@ -1,4 +1,4 @@ -/* $OpenBSD: notification.c,v 1.37 2016/07/01 23:29:55 renato Exp $ */ +/* $OpenBSD: notification.c,v 1.38 2016/07/01 23:33:46 renato Exp $ */ /* * Copyright (c) 2009 Michele Marchetto @@ -25,8 +25,6 @@ #include "log.h" #include "ldpe.h" -static int gen_status_tlv(struct ibuf *, uint32_t, uint32_t, uint16_t); - void send_notification_full(struct tcp_conn *tcp, struct notify_msg *nm) { @@ -221,7 +219,7 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) return (0); } -static int +int gen_status_tlv(struct ibuf *buf, uint32_t status, uint32_t msgid, uint16_t type) { struct status_tlv st; -- 2.20.1