From 2cc1d4d7dfc8fb9837fc62992ccb92c1f8613706 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 31 Jan 2021 18:33:31 +0100 Subject: frame_relay: Add status call-backs for link + DLC status changes Change-Id: Iec19db4e48642c3fcb0aa11fa7787b8323fd0e5a Related: Os#4999 --- include/osmocom/gprs/frame_relay.h | 11 ++++++++-- src/gb/frame_relay.c | 41 +++++++++++++++++++++++++++----------- src/gb/gprs_ns2_fr.c | 4 ++-- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/include/osmocom/gprs/frame_relay.h b/include/osmocom/gprs/frame_relay.h index 2860c6be..1be37eec 100644 --- a/include/osmocom/gprs/frame_relay.h +++ b/include/osmocom/gprs/frame_relay.h @@ -87,11 +87,15 @@ struct osmo_fr_link { /* list of data link connections at this link */ struct llist_head dlc_list; + /* optional call-back to be called for each PDU received on an unknown DLC */ int (*unknown_dlc_rx_cb)(void *cb_data, struct msgb *msg); void *unknown_dlc_rx_cb_data; + /* call-back to be called for transmitting on the underlying hardware */ int (*tx_cb)(void *data, struct msgb *msg); - void *tx_cb_data; + /* optional call-back to be called each time the status changes active/inactive */ + void (*status_cb)(struct osmo_fr_link *link, void *cb_data, bool active); + void *cb_data; }; /* Frame Relay Data Link Connection */ @@ -113,8 +117,11 @@ struct osmo_fr_dlc { * NET must wait until USER confirms it implicitly by a seq number check */ bool state_send; + /* call-back to be called for each PDU received on this DLC */ int (*rx_cb)(void *cb_data, struct msgb *msg); - void *rx_cb_data; + /* optional call-back to be called each time the status changes active/inactive */ + void (*status_cb)(struct osmo_fr_dlc *dlc, void *cb_data, bool active); + void *cb_data; }; /* allocate a frame relay network */ diff --git a/src/gb/frame_relay.c b/src/gb/frame_relay.c index 03b847aa..a7e1da8a 100644 --- a/src/gb/frame_relay.c +++ b/src/gb/frame_relay.c @@ -189,6 +189,18 @@ static inline void dlci_to_q922(uint8_t *hdr, uint16_t dlci) hdr[1] = ((dlci << 4) & 0xF0) | 0x01; } +static void dlc_set_active(struct osmo_fr_dlc *dlc, bool active) +{ + if (active == dlc->active) + return; + + dlc->active = active; + + LOGPFRL(dlc->link, LOGL_NOTICE, "DLCI %u became %s\n", dlc->dlci, active ? "active" : "inactive"); + if (dlc->status_cb) + dlc->status_cb(dlc, dlc->cb_data, active); +} + /* allocate a message buffer and put Q.933 Annex A headers (L2 + L3) */ static struct msgb *q933_msgb_alloc(uint16_t dlci, uint8_t prot_disc, uint8_t msg_type) { @@ -285,7 +297,7 @@ static int tx_lmi_q933_status_enq(struct osmo_fr_link *link, uint8_t rep_type) msgb_tlv_put(resp, Q933_IEI_REPORT_TYPE, 1, &rep_type); msgb_put_link_int_verif(resp, link); - return link->tx_cb(link->tx_cb_data, resp); + return link->tx_cb(link->cb_data, resp); } /* Send a Q.933 STATUS of given type over given link */ @@ -327,7 +339,7 @@ static int tx_lmi_q933_status(struct osmo_fr_link *link, uint8_t rep_type) break; } - return link->tx_cb(link->tx_cb_data, resp); + return link->tx_cb(link->cb_data, resp); } @@ -369,7 +381,7 @@ static int rx_lmi_q933_status_enq(struct msgb *msg, struct tlv_parsed *tp) continue; if (dlc->add) { - dlc->active = link->state; + dlc_set_active(dlc, link->state); dlc->add = false; } @@ -417,11 +429,11 @@ static void check_link_state(struct osmo_fr_link *link, bool valid) LOGPFRL(link, LOGL_NOTICE, "Link failed\n"); link->state = false; - if (link->role == FR_ROLE_USER_EQUIPMENT) - return; + if (link->status_cb) + link->status_cb(link, link->cb_data, link->state); llist_for_each_entry(dlc, &link->dlc_list, list) { - dlc->active = false; + dlc_set_active(dlc, false); } } else { /* good link */ @@ -430,16 +442,21 @@ static void check_link_state(struct osmo_fr_link *link, bool valid) LOGPFRL(link, LOGL_NOTICE, "Link recovered\n"); link->state = true; + if (link->status_cb) + link->status_cb(link, link->cb_data, link->state); + if (link->role == FR_ROLE_USER_EQUIPMENT) { /* make sure the next STATUS ENQUIRY is for a full * status report to get the configred DLCs ASAP */ link->polling_count = 0; + /* we must not proceed further below if we're in user role, + * as otherwise link recovery would set all DLCs as active */ return; } llist_for_each_entry(dlc, &link->dlc_list, list) { if (!dlc->add && !dlc->del) - dlc->active = true; + dlc_set_active(dlc, true); } } } @@ -508,7 +525,7 @@ static int parse_full_pvc_status(struct osmo_fr_link *link, struct tlv_parsed *t * using the optional single PVC asynchronous status report. * Ignoring the delete. */ dlc->add = pvc->new; - dlc->active = pvc->active; + dlc_set_active(dlc, pvc->active); dlc->del = 0; } @@ -523,7 +540,7 @@ static int parse_full_pvc_status(struct osmo_fr_link *link, struct tlv_parsed *t } if (!found) { - dlc->active = false; + dlc_set_active(dlc, false); dlc->del = true; } } @@ -575,7 +592,7 @@ static int parse_link_pvc_status(struct osmo_fr_link *link, struct tlv_parsed *t dlc->del = 1; } else { dlc->add = pvc->new; - dlc->active = pvc->active; + dlc_set_active(dlc, pvc->active); dlc->del = 0; } } @@ -771,7 +788,7 @@ int osmo_fr_rx(struct msgb *msg) if (dlc->dlci == dlci) { /* dispatch to handler of respective DLC */ msg->dst = dlc; - return dlc->rx_cb(dlc->rx_cb_data, msg); + return dlc->rx_cb(dlc->cb_data, msg); } } @@ -816,7 +833,7 @@ int osmo_fr_tx_dlc(struct msgb *msg) dlci_to_q922(frh, dlc->dlci); msg->dst = link; - return link->tx_cb(link->tx_cb_data, msg); + return link->tx_cb(link->cb_data, msg); } /* Every T391 seconds, the user equipment sends a STATUS ENQUIRY diff --git a/src/gb/gprs_ns2_fr.c b/src/gb/gprs_ns2_fr.c index 49e92ae2..b5ddf7e9 100644 --- a/src/gb/gprs_ns2_fr.c +++ b/src/gb/gprs_ns2_fr.c @@ -198,7 +198,7 @@ static struct priv_vc *fr_alloc_vc(struct gprs_ns2_vc_bind *bind, return NULL; } - priv->dlc->rx_cb_data = nsvc; + priv->dlc->cb_data = nsvc; priv->dlc->rx_cb = fr_dlci_rx_cb; return priv; @@ -756,7 +756,7 @@ int gprs_ns2_fr_bind(struct gprs_ns2_inst *nsi, } fr_link->tx_cb = fr_tx_cb; - fr_link->tx_cb_data = bind; + fr_link->cb_data = bind; priv->link = fr_link; priv->ifindex = rc = devname2ifindex(netif); -- cgit v1.2.3