Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 
0003 #include <linux/cfm_bridge.h>
0004 #include <uapi/linux/cfm_bridge.h>
0005 #include "br_private_cfm.h"
0006 
0007 static struct br_cfm_mep *br_mep_find(struct net_bridge *br, u32 instance)
0008 {
0009     struct br_cfm_mep *mep;
0010 
0011     hlist_for_each_entry(mep, &br->mep_list, head)
0012         if (mep->instance == instance)
0013             return mep;
0014 
0015     return NULL;
0016 }
0017 
0018 static struct br_cfm_mep *br_mep_find_ifindex(struct net_bridge *br,
0019                           u32 ifindex)
0020 {
0021     struct br_cfm_mep *mep;
0022 
0023     hlist_for_each_entry_rcu(mep, &br->mep_list, head,
0024                  lockdep_rtnl_is_held())
0025         if (mep->create.ifindex == ifindex)
0026             return mep;
0027 
0028     return NULL;
0029 }
0030 
0031 static struct br_cfm_peer_mep *br_peer_mep_find(struct br_cfm_mep *mep,
0032                         u32 mepid)
0033 {
0034     struct br_cfm_peer_mep *peer_mep;
0035 
0036     hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head,
0037                  lockdep_rtnl_is_held())
0038         if (peer_mep->mepid == mepid)
0039             return peer_mep;
0040 
0041     return NULL;
0042 }
0043 
0044 static struct net_bridge_port *br_mep_get_port(struct net_bridge *br,
0045                            u32 ifindex)
0046 {
0047     struct net_bridge_port *port;
0048 
0049     list_for_each_entry(port, &br->port_list, list)
0050         if (port->dev->ifindex == ifindex)
0051             return port;
0052 
0053     return NULL;
0054 }
0055 
0056 /* Calculate the CCM interval in us. */
0057 static u32 interval_to_us(enum br_cfm_ccm_interval interval)
0058 {
0059     switch (interval) {
0060     case BR_CFM_CCM_INTERVAL_NONE:
0061         return 0;
0062     case BR_CFM_CCM_INTERVAL_3_3_MS:
0063         return 3300;
0064     case BR_CFM_CCM_INTERVAL_10_MS:
0065         return 10 * 1000;
0066     case BR_CFM_CCM_INTERVAL_100_MS:
0067         return 100 * 1000;
0068     case BR_CFM_CCM_INTERVAL_1_SEC:
0069         return 1000 * 1000;
0070     case BR_CFM_CCM_INTERVAL_10_SEC:
0071         return 10 * 1000 * 1000;
0072     case BR_CFM_CCM_INTERVAL_1_MIN:
0073         return 60 * 1000 * 1000;
0074     case BR_CFM_CCM_INTERVAL_10_MIN:
0075         return 10 * 60 * 1000 * 1000;
0076     }
0077     return 0;
0078 }
0079 
0080 /* Convert the interface interval to CCM PDU value. */
0081 static u32 interval_to_pdu(enum br_cfm_ccm_interval interval)
0082 {
0083     switch (interval) {
0084     case BR_CFM_CCM_INTERVAL_NONE:
0085         return 0;
0086     case BR_CFM_CCM_INTERVAL_3_3_MS:
0087         return 1;
0088     case BR_CFM_CCM_INTERVAL_10_MS:
0089         return 2;
0090     case BR_CFM_CCM_INTERVAL_100_MS:
0091         return 3;
0092     case BR_CFM_CCM_INTERVAL_1_SEC:
0093         return 4;
0094     case BR_CFM_CCM_INTERVAL_10_SEC:
0095         return 5;
0096     case BR_CFM_CCM_INTERVAL_1_MIN:
0097         return 6;
0098     case BR_CFM_CCM_INTERVAL_10_MIN:
0099         return 7;
0100     }
0101     return 0;
0102 }
0103 
0104 /* Convert the CCM PDU value to interval on interface. */
0105 static u32 pdu_to_interval(u32 value)
0106 {
0107     switch (value) {
0108     case 0:
0109         return BR_CFM_CCM_INTERVAL_NONE;
0110     case 1:
0111         return BR_CFM_CCM_INTERVAL_3_3_MS;
0112     case 2:
0113         return BR_CFM_CCM_INTERVAL_10_MS;
0114     case 3:
0115         return BR_CFM_CCM_INTERVAL_100_MS;
0116     case 4:
0117         return BR_CFM_CCM_INTERVAL_1_SEC;
0118     case 5:
0119         return BR_CFM_CCM_INTERVAL_10_SEC;
0120     case 6:
0121         return BR_CFM_CCM_INTERVAL_1_MIN;
0122     case 7:
0123         return BR_CFM_CCM_INTERVAL_10_MIN;
0124     }
0125     return BR_CFM_CCM_INTERVAL_NONE;
0126 }
0127 
0128 static void ccm_rx_timer_start(struct br_cfm_peer_mep *peer_mep)
0129 {
0130     u32 interval_us;
0131 
0132     interval_us = interval_to_us(peer_mep->mep->cc_config.exp_interval);
0133     /* Function ccm_rx_dwork must be called with 1/4
0134      * of the configured CC 'expected_interval'
0135      * in order to detect CCM defect after 3.25 interval.
0136      */
0137     queue_delayed_work(system_wq, &peer_mep->ccm_rx_dwork,
0138                usecs_to_jiffies(interval_us / 4));
0139 }
0140 
0141 static void br_cfm_notify(int event, const struct net_bridge_port *port)
0142 {
0143     u32 filter = RTEXT_FILTER_CFM_STATUS;
0144 
0145     br_info_notify(event, port->br, NULL, filter);
0146 }
0147 
0148 static void cc_peer_enable(struct br_cfm_peer_mep *peer_mep)
0149 {
0150     memset(&peer_mep->cc_status, 0, sizeof(peer_mep->cc_status));
0151     peer_mep->ccm_rx_count_miss = 0;
0152 
0153     ccm_rx_timer_start(peer_mep);
0154 }
0155 
0156 static void cc_peer_disable(struct br_cfm_peer_mep *peer_mep)
0157 {
0158     cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
0159 }
0160 
0161 static struct sk_buff *ccm_frame_build(struct br_cfm_mep *mep,
0162                        const struct br_cfm_cc_ccm_tx_info *const tx_info)
0163 
0164 {
0165     struct br_cfm_common_hdr *common_hdr;
0166     struct net_bridge_port *b_port;
0167     struct br_cfm_maid *maid;
0168     u8 *itu_reserved, *e_tlv;
0169     struct ethhdr *eth_hdr;
0170     struct sk_buff *skb;
0171     __be32 *status_tlv;
0172     __be32 *snumber;
0173     __be16 *mepid;
0174 
0175     skb = dev_alloc_skb(CFM_CCM_MAX_FRAME_LENGTH);
0176     if (!skb)
0177         return NULL;
0178 
0179     rcu_read_lock();
0180     b_port = rcu_dereference(mep->b_port);
0181     if (!b_port) {
0182         kfree_skb(skb);
0183         rcu_read_unlock();
0184         return NULL;
0185     }
0186     skb->dev = b_port->dev;
0187     rcu_read_unlock();
0188     /* The device cannot be deleted until the work_queue functions has
0189      * completed. This function is called from ccm_tx_work_expired()
0190      * that is a work_queue functions.
0191      */
0192 
0193     skb->protocol = htons(ETH_P_CFM);
0194     skb->priority = CFM_FRAME_PRIO;
0195 
0196     /* Ethernet header */
0197     eth_hdr = skb_put(skb, sizeof(*eth_hdr));
0198     ether_addr_copy(eth_hdr->h_dest, tx_info->dmac.addr);
0199     ether_addr_copy(eth_hdr->h_source, mep->config.unicast_mac.addr);
0200     eth_hdr->h_proto = htons(ETH_P_CFM);
0201 
0202     /* Common CFM Header */
0203     common_hdr = skb_put(skb, sizeof(*common_hdr));
0204     common_hdr->mdlevel_version = mep->config.mdlevel << 5;
0205     common_hdr->opcode = BR_CFM_OPCODE_CCM;
0206     common_hdr->flags = (mep->rdi << 7) |
0207                 interval_to_pdu(mep->cc_config.exp_interval);
0208     common_hdr->tlv_offset = CFM_CCM_TLV_OFFSET;
0209 
0210     /* Sequence number */
0211     snumber = skb_put(skb, sizeof(*snumber));
0212     if (tx_info->seq_no_update) {
0213         *snumber = cpu_to_be32(mep->ccm_tx_snumber);
0214         mep->ccm_tx_snumber += 1;
0215     } else {
0216         *snumber = 0;
0217     }
0218 
0219     mepid = skb_put(skb, sizeof(*mepid));
0220     *mepid = cpu_to_be16((u16)mep->config.mepid);
0221 
0222     maid = skb_put(skb, sizeof(*maid));
0223     memcpy(maid->data, mep->cc_config.exp_maid.data, sizeof(maid->data));
0224 
0225     /* ITU reserved (CFM_CCM_ITU_RESERVED_SIZE octets) */
0226     itu_reserved = skb_put(skb, CFM_CCM_ITU_RESERVED_SIZE);
0227     memset(itu_reserved, 0, CFM_CCM_ITU_RESERVED_SIZE);
0228 
0229     /* Generel CFM TLV format:
0230      * TLV type:        one byte
0231      * TLV value length:    two bytes
0232      * TLV value:       'TLV value length' bytes
0233      */
0234 
0235     /* Port status TLV. The value length is 1. Total of 4 bytes. */
0236     if (tx_info->port_tlv) {
0237         status_tlv = skb_put(skb, sizeof(*status_tlv));
0238         *status_tlv = cpu_to_be32((CFM_PORT_STATUS_TLV_TYPE << 24) |
0239                       (1 << 8) |    /* Value length */
0240                       (tx_info->port_tlv_value & 0xFF));
0241     }
0242 
0243     /* Interface status TLV. The value length is 1. Total of 4 bytes. */
0244     if (tx_info->if_tlv) {
0245         status_tlv = skb_put(skb, sizeof(*status_tlv));
0246         *status_tlv = cpu_to_be32((CFM_IF_STATUS_TLV_TYPE << 24) |
0247                       (1 << 8) |    /* Value length */
0248                       (tx_info->if_tlv_value & 0xFF));
0249     }
0250 
0251     /* End TLV */
0252     e_tlv = skb_put(skb, sizeof(*e_tlv));
0253     *e_tlv = CFM_ENDE_TLV_TYPE;
0254 
0255     return skb;
0256 }
0257 
0258 static void ccm_frame_tx(struct sk_buff *skb)
0259 {
0260     skb_reset_network_header(skb);
0261     dev_queue_xmit(skb);
0262 }
0263 
0264 /* This function is called with the configured CC 'expected_interval'
0265  * in order to drive CCM transmission when enabled.
0266  */
0267 static void ccm_tx_work_expired(struct work_struct *work)
0268 {
0269     struct delayed_work *del_work;
0270     struct br_cfm_mep *mep;
0271     struct sk_buff *skb;
0272     u32 interval_us;
0273 
0274     del_work = to_delayed_work(work);
0275     mep = container_of(del_work, struct br_cfm_mep, ccm_tx_dwork);
0276 
0277     if (time_before_eq(mep->ccm_tx_end, jiffies)) {
0278         /* Transmission period has ended */
0279         mep->cc_ccm_tx_info.period = 0;
0280         return;
0281     }
0282 
0283     skb = ccm_frame_build(mep, &mep->cc_ccm_tx_info);
0284     if (skb)
0285         ccm_frame_tx(skb);
0286 
0287     interval_us = interval_to_us(mep->cc_config.exp_interval);
0288     queue_delayed_work(system_wq, &mep->ccm_tx_dwork,
0289                usecs_to_jiffies(interval_us));
0290 }
0291 
0292 /* This function is called with 1/4 of the configured CC 'expected_interval'
0293  * in order to detect CCM defect after 3.25 interval.
0294  */
0295 static void ccm_rx_work_expired(struct work_struct *work)
0296 {
0297     struct br_cfm_peer_mep *peer_mep;
0298     struct net_bridge_port *b_port;
0299     struct delayed_work *del_work;
0300 
0301     del_work = to_delayed_work(work);
0302     peer_mep = container_of(del_work, struct br_cfm_peer_mep, ccm_rx_dwork);
0303 
0304     /* After 13 counts (4 * 3,25) then 3.25 intervals are expired */
0305     if (peer_mep->ccm_rx_count_miss < 13) {
0306         /* 3.25 intervals are NOT expired without CCM reception */
0307         peer_mep->ccm_rx_count_miss++;
0308 
0309         /* Start timer again */
0310         ccm_rx_timer_start(peer_mep);
0311     } else {
0312         /* 3.25 intervals are expired without CCM reception.
0313          * CCM defect detected
0314          */
0315         peer_mep->cc_status.ccm_defect = true;
0316 
0317         /* Change in CCM defect status - notify */
0318         rcu_read_lock();
0319         b_port = rcu_dereference(peer_mep->mep->b_port);
0320         if (b_port)
0321             br_cfm_notify(RTM_NEWLINK, b_port);
0322         rcu_read_unlock();
0323     }
0324 }
0325 
0326 static u32 ccm_tlv_extract(struct sk_buff *skb, u32 index,
0327                struct br_cfm_peer_mep *peer_mep)
0328 {
0329     __be32 *s_tlv;
0330     __be32 _s_tlv;
0331     u32 h_s_tlv;
0332     u8 *e_tlv;
0333     u8 _e_tlv;
0334 
0335     e_tlv = skb_header_pointer(skb, index, sizeof(_e_tlv), &_e_tlv);
0336     if (!e_tlv)
0337         return 0;
0338 
0339     /* TLV is present - get the status TLV */
0340     s_tlv = skb_header_pointer(skb,
0341                    index,
0342                    sizeof(_s_tlv), &_s_tlv);
0343     if (!s_tlv)
0344         return 0;
0345 
0346     h_s_tlv = ntohl(*s_tlv);
0347     if ((h_s_tlv >> 24) == CFM_IF_STATUS_TLV_TYPE) {
0348         /* Interface status TLV */
0349         peer_mep->cc_status.tlv_seen = true;
0350         peer_mep->cc_status.if_tlv_value = (h_s_tlv & 0xFF);
0351     }
0352 
0353     if ((h_s_tlv >> 24) == CFM_PORT_STATUS_TLV_TYPE) {
0354         /* Port status TLV */
0355         peer_mep->cc_status.tlv_seen = true;
0356         peer_mep->cc_status.port_tlv_value = (h_s_tlv & 0xFF);
0357     }
0358 
0359     /* The Sender ID TLV is not handled */
0360     /* The Organization-Specific TLV is not handled */
0361 
0362     /* Return the length of this tlv.
0363      * This is the length of the value field plus 3 bytes for size of type
0364      * field and length field
0365      */
0366     return ((h_s_tlv >> 8) & 0xFFFF) + 3;
0367 }
0368 
0369 /* note: already called with rcu_read_lock */
0370 static int br_cfm_frame_rx(struct net_bridge_port *port, struct sk_buff *skb)
0371 {
0372     u32 mdlevel, interval, size, index, max;
0373     const struct br_cfm_common_hdr *hdr;
0374     struct br_cfm_peer_mep *peer_mep;
0375     const struct br_cfm_maid *maid;
0376     struct br_cfm_common_hdr _hdr;
0377     struct br_cfm_maid _maid;
0378     struct br_cfm_mep *mep;
0379     struct net_bridge *br;
0380     __be32 *snumber;
0381     __be32 _snumber;
0382     __be16 *mepid;
0383     __be16 _mepid;
0384 
0385     if (port->state == BR_STATE_DISABLED)
0386         return 0;
0387 
0388     hdr = skb_header_pointer(skb, 0, sizeof(_hdr), &_hdr);
0389     if (!hdr)
0390         return 1;
0391 
0392     br = port->br;
0393     mep = br_mep_find_ifindex(br, port->dev->ifindex);
0394     if (unlikely(!mep))
0395         /* No MEP on this port - must be forwarded */
0396         return 0;
0397 
0398     mdlevel = hdr->mdlevel_version >> 5;
0399     if (mdlevel > mep->config.mdlevel)
0400         /* The level is above this MEP level - must be forwarded */
0401         return 0;
0402 
0403     if ((hdr->mdlevel_version & 0x1F) != 0) {
0404         /* Invalid version */
0405         mep->status.version_unexp_seen = true;
0406         return 1;
0407     }
0408 
0409     if (mdlevel < mep->config.mdlevel) {
0410         /* The level is below this MEP level */
0411         mep->status.rx_level_low_seen = true;
0412         return 1;
0413     }
0414 
0415     if (hdr->opcode == BR_CFM_OPCODE_CCM) {
0416         /* CCM PDU received. */
0417         /* MA ID is after common header + sequence number + MEP ID */
0418         maid = skb_header_pointer(skb,
0419                       CFM_CCM_PDU_MAID_OFFSET,
0420                       sizeof(_maid), &_maid);
0421         if (!maid)
0422             return 1;
0423         if (memcmp(maid->data, mep->cc_config.exp_maid.data,
0424                sizeof(maid->data)))
0425             /* MA ID not as expected */
0426             return 1;
0427 
0428         /* MEP ID is after common header + sequence number */
0429         mepid = skb_header_pointer(skb,
0430                        CFM_CCM_PDU_MEPID_OFFSET,
0431                        sizeof(_mepid), &_mepid);
0432         if (!mepid)
0433             return 1;
0434         peer_mep = br_peer_mep_find(mep, (u32)ntohs(*mepid));
0435         if (!peer_mep)
0436             return 1;
0437 
0438         /* Interval is in common header flags */
0439         interval = hdr->flags & 0x07;
0440         if (mep->cc_config.exp_interval != pdu_to_interval(interval))
0441             /* Interval not as expected */
0442             return 1;
0443 
0444         /* A valid CCM frame is received */
0445         if (peer_mep->cc_status.ccm_defect) {
0446             peer_mep->cc_status.ccm_defect = false;
0447 
0448             /* Change in CCM defect status - notify */
0449             br_cfm_notify(RTM_NEWLINK, port);
0450 
0451             /* Start CCM RX timer */
0452             ccm_rx_timer_start(peer_mep);
0453         }
0454 
0455         peer_mep->cc_status.seen = true;
0456         peer_mep->ccm_rx_count_miss = 0;
0457 
0458         /* RDI is in common header flags */
0459         peer_mep->cc_status.rdi = (hdr->flags & 0x80) ? true : false;
0460 
0461         /* Sequence number is after common header */
0462         snumber = skb_header_pointer(skb,
0463                          CFM_CCM_PDU_SEQNR_OFFSET,
0464                          sizeof(_snumber), &_snumber);
0465         if (!snumber)
0466             return 1;
0467         if (ntohl(*snumber) != (mep->ccm_rx_snumber + 1))
0468             /* Unexpected sequence number */
0469             peer_mep->cc_status.seq_unexp_seen = true;
0470 
0471         mep->ccm_rx_snumber = ntohl(*snumber);
0472 
0473         /* TLV end is after common header + sequence number + MEP ID +
0474          * MA ID + ITU reserved
0475          */
0476         index = CFM_CCM_PDU_TLV_OFFSET;
0477         max = 0;
0478         do { /* Handle all TLVs */
0479             size = ccm_tlv_extract(skb, index, peer_mep);
0480             index += size;
0481             max += 1;
0482         } while (size != 0 && max < 4); /* Max four TLVs possible */
0483 
0484         return 1;
0485     }
0486 
0487     mep->status.opcode_unexp_seen = true;
0488 
0489     return 1;
0490 }
0491 
0492 static struct br_frame_type cfm_frame_type __read_mostly = {
0493     .type = cpu_to_be16(ETH_P_CFM),
0494     .frame_handler = br_cfm_frame_rx,
0495 };
0496 
0497 int br_cfm_mep_create(struct net_bridge *br,
0498               const u32 instance,
0499               struct br_cfm_mep_create *const create,
0500               struct netlink_ext_ack *extack)
0501 {
0502     struct net_bridge_port *p;
0503     struct br_cfm_mep *mep;
0504 
0505     ASSERT_RTNL();
0506 
0507     if (create->domain == BR_CFM_VLAN) {
0508         NL_SET_ERR_MSG_MOD(extack,
0509                    "VLAN domain not supported");
0510         return -EINVAL;
0511     }
0512     if (create->domain != BR_CFM_PORT) {
0513         NL_SET_ERR_MSG_MOD(extack,
0514                    "Invalid domain value");
0515         return -EINVAL;
0516     }
0517     if (create->direction == BR_CFM_MEP_DIRECTION_UP) {
0518         NL_SET_ERR_MSG_MOD(extack,
0519                    "Up-MEP not supported");
0520         return -EINVAL;
0521     }
0522     if (create->direction != BR_CFM_MEP_DIRECTION_DOWN) {
0523         NL_SET_ERR_MSG_MOD(extack,
0524                    "Invalid direction value");
0525         return -EINVAL;
0526     }
0527     p = br_mep_get_port(br, create->ifindex);
0528     if (!p) {
0529         NL_SET_ERR_MSG_MOD(extack,
0530                    "Port is not related to bridge");
0531         return -EINVAL;
0532     }
0533     mep = br_mep_find(br, instance);
0534     if (mep) {
0535         NL_SET_ERR_MSG_MOD(extack,
0536                    "MEP instance already exists");
0537         return -EEXIST;
0538     }
0539 
0540     /* In PORT domain only one instance can be created per port */
0541     if (create->domain == BR_CFM_PORT) {
0542         mep = br_mep_find_ifindex(br, create->ifindex);
0543         if (mep) {
0544             NL_SET_ERR_MSG_MOD(extack,
0545                        "Only one Port MEP on a port allowed");
0546             return -EINVAL;
0547         }
0548     }
0549 
0550     mep = kzalloc(sizeof(*mep), GFP_KERNEL);
0551     if (!mep)
0552         return -ENOMEM;
0553 
0554     mep->create = *create;
0555     mep->instance = instance;
0556     rcu_assign_pointer(mep->b_port, p);
0557 
0558     INIT_HLIST_HEAD(&mep->peer_mep_list);
0559     INIT_DELAYED_WORK(&mep->ccm_tx_dwork, ccm_tx_work_expired);
0560 
0561     if (hlist_empty(&br->mep_list))
0562         br_add_frame(br, &cfm_frame_type);
0563 
0564     hlist_add_tail_rcu(&mep->head, &br->mep_list);
0565 
0566     return 0;
0567 }
0568 
0569 static void mep_delete_implementation(struct net_bridge *br,
0570                       struct br_cfm_mep *mep)
0571 {
0572     struct br_cfm_peer_mep *peer_mep;
0573     struct hlist_node *n_store;
0574 
0575     ASSERT_RTNL();
0576 
0577     /* Empty and free peer MEP list */
0578     hlist_for_each_entry_safe(peer_mep, n_store, &mep->peer_mep_list, head) {
0579         cancel_delayed_work_sync(&peer_mep->ccm_rx_dwork);
0580         hlist_del_rcu(&peer_mep->head);
0581         kfree_rcu(peer_mep, rcu);
0582     }
0583 
0584     cancel_delayed_work_sync(&mep->ccm_tx_dwork);
0585 
0586     RCU_INIT_POINTER(mep->b_port, NULL);
0587     hlist_del_rcu(&mep->head);
0588     kfree_rcu(mep, rcu);
0589 
0590     if (hlist_empty(&br->mep_list))
0591         br_del_frame(br, &cfm_frame_type);
0592 }
0593 
0594 int br_cfm_mep_delete(struct net_bridge *br,
0595               const u32 instance,
0596               struct netlink_ext_ack *extack)
0597 {
0598     struct br_cfm_mep *mep;
0599 
0600     ASSERT_RTNL();
0601 
0602     mep = br_mep_find(br, instance);
0603     if (!mep) {
0604         NL_SET_ERR_MSG_MOD(extack,
0605                    "MEP instance does not exists");
0606         return -ENOENT;
0607     }
0608 
0609     mep_delete_implementation(br, mep);
0610 
0611     return 0;
0612 }
0613 
0614 int br_cfm_mep_config_set(struct net_bridge *br,
0615               const u32 instance,
0616               const struct br_cfm_mep_config *const config,
0617               struct netlink_ext_ack *extack)
0618 {
0619     struct br_cfm_mep *mep;
0620 
0621     ASSERT_RTNL();
0622 
0623     mep = br_mep_find(br, instance);
0624     if (!mep) {
0625         NL_SET_ERR_MSG_MOD(extack,
0626                    "MEP instance does not exists");
0627         return -ENOENT;
0628     }
0629 
0630     mep->config = *config;
0631 
0632     return 0;
0633 }
0634 
0635 int br_cfm_cc_config_set(struct net_bridge *br,
0636              const u32 instance,
0637              const struct br_cfm_cc_config *const config,
0638              struct netlink_ext_ack *extack)
0639 {
0640     struct br_cfm_peer_mep *peer_mep;
0641     struct br_cfm_mep *mep;
0642 
0643     ASSERT_RTNL();
0644 
0645     mep = br_mep_find(br, instance);
0646     if (!mep) {
0647         NL_SET_ERR_MSG_MOD(extack,
0648                    "MEP instance does not exists");
0649         return -ENOENT;
0650     }
0651 
0652     /* Check for no change in configuration */
0653     if (memcmp(config, &mep->cc_config, sizeof(*config)) == 0)
0654         return 0;
0655 
0656     if (config->enable && !mep->cc_config.enable)
0657         /* CC is enabled */
0658         hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head)
0659             cc_peer_enable(peer_mep);
0660 
0661     if (!config->enable && mep->cc_config.enable)
0662         /* CC is disabled */
0663         hlist_for_each_entry(peer_mep, &mep->peer_mep_list, head)
0664             cc_peer_disable(peer_mep);
0665 
0666     mep->cc_config = *config;
0667     mep->ccm_rx_snumber = 0;
0668     mep->ccm_tx_snumber = 1;
0669 
0670     return 0;
0671 }
0672 
0673 int br_cfm_cc_peer_mep_add(struct net_bridge *br, const u32 instance,
0674                u32 mepid,
0675                struct netlink_ext_ack *extack)
0676 {
0677     struct br_cfm_peer_mep *peer_mep;
0678     struct br_cfm_mep *mep;
0679 
0680     ASSERT_RTNL();
0681 
0682     mep = br_mep_find(br, instance);
0683     if (!mep) {
0684         NL_SET_ERR_MSG_MOD(extack,
0685                    "MEP instance does not exists");
0686         return -ENOENT;
0687     }
0688 
0689     peer_mep = br_peer_mep_find(mep, mepid);
0690     if (peer_mep) {
0691         NL_SET_ERR_MSG_MOD(extack,
0692                    "Peer MEP-ID already exists");
0693         return -EEXIST;
0694     }
0695 
0696     peer_mep = kzalloc(sizeof(*peer_mep), GFP_KERNEL);
0697     if (!peer_mep)
0698         return -ENOMEM;
0699 
0700     peer_mep->mepid = mepid;
0701     peer_mep->mep = mep;
0702     INIT_DELAYED_WORK(&peer_mep->ccm_rx_dwork, ccm_rx_work_expired);
0703 
0704     if (mep->cc_config.enable)
0705         cc_peer_enable(peer_mep);
0706 
0707     hlist_add_tail_rcu(&peer_mep->head, &mep->peer_mep_list);
0708 
0709     return 0;
0710 }
0711 
0712 int br_cfm_cc_peer_mep_remove(struct net_bridge *br, const u32 instance,
0713                   u32 mepid,
0714                   struct netlink_ext_ack *extack)
0715 {
0716     struct br_cfm_peer_mep *peer_mep;
0717     struct br_cfm_mep *mep;
0718 
0719     ASSERT_RTNL();
0720 
0721     mep = br_mep_find(br, instance);
0722     if (!mep) {
0723         NL_SET_ERR_MSG_MOD(extack,
0724                    "MEP instance does not exists");
0725         return -ENOENT;
0726     }
0727 
0728     peer_mep = br_peer_mep_find(mep, mepid);
0729     if (!peer_mep) {
0730         NL_SET_ERR_MSG_MOD(extack,
0731                    "Peer MEP-ID does not exists");
0732         return -ENOENT;
0733     }
0734 
0735     cc_peer_disable(peer_mep);
0736 
0737     hlist_del_rcu(&peer_mep->head);
0738     kfree_rcu(peer_mep, rcu);
0739 
0740     return 0;
0741 }
0742 
0743 int br_cfm_cc_rdi_set(struct net_bridge *br, const u32 instance,
0744               const bool rdi, struct netlink_ext_ack *extack)
0745 {
0746     struct br_cfm_mep *mep;
0747 
0748     ASSERT_RTNL();
0749 
0750     mep = br_mep_find(br, instance);
0751     if (!mep) {
0752         NL_SET_ERR_MSG_MOD(extack,
0753                    "MEP instance does not exists");
0754         return -ENOENT;
0755     }
0756 
0757     mep->rdi = rdi;
0758 
0759     return 0;
0760 }
0761 
0762 int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance,
0763              const struct br_cfm_cc_ccm_tx_info *const tx_info,
0764              struct netlink_ext_ack *extack)
0765 {
0766     struct br_cfm_mep *mep;
0767 
0768     ASSERT_RTNL();
0769 
0770     mep = br_mep_find(br, instance);
0771     if (!mep) {
0772         NL_SET_ERR_MSG_MOD(extack,
0773                    "MEP instance does not exists");
0774         return -ENOENT;
0775     }
0776 
0777     if (memcmp(tx_info, &mep->cc_ccm_tx_info, sizeof(*tx_info)) == 0) {
0778         /* No change in tx_info. */
0779         if (mep->cc_ccm_tx_info.period == 0)
0780             /* Transmission is not enabled - just return */
0781             return 0;
0782 
0783         /* Transmission is ongoing, the end time is recalculated */
0784         mep->ccm_tx_end = jiffies +
0785                   usecs_to_jiffies(tx_info->period * 1000000);
0786         return 0;
0787     }
0788 
0789     if (tx_info->period == 0 && mep->cc_ccm_tx_info.period == 0)
0790         /* Some change in info and transmission is not ongoing */
0791         goto save;
0792 
0793     if (tx_info->period != 0 && mep->cc_ccm_tx_info.period != 0) {
0794         /* Some change in info and transmission is ongoing
0795          * The end time is recalculated
0796          */
0797         mep->ccm_tx_end = jiffies +
0798                   usecs_to_jiffies(tx_info->period * 1000000);
0799 
0800         goto save;
0801     }
0802 
0803     if (tx_info->period == 0 && mep->cc_ccm_tx_info.period != 0) {
0804         cancel_delayed_work_sync(&mep->ccm_tx_dwork);
0805         goto save;
0806     }
0807 
0808     /* Start delayed work to transmit CCM frames. It is done with zero delay
0809      * to send first frame immediately
0810      */
0811     mep->ccm_tx_end = jiffies + usecs_to_jiffies(tx_info->period * 1000000);
0812     queue_delayed_work(system_wq, &mep->ccm_tx_dwork, 0);
0813 
0814 save:
0815     mep->cc_ccm_tx_info = *tx_info;
0816 
0817     return 0;
0818 }
0819 
0820 int br_cfm_mep_count(struct net_bridge *br, u32 *count)
0821 {
0822     struct br_cfm_mep *mep;
0823 
0824     *count = 0;
0825 
0826     rcu_read_lock();
0827     hlist_for_each_entry_rcu(mep, &br->mep_list, head)
0828         *count += 1;
0829     rcu_read_unlock();
0830 
0831     return 0;
0832 }
0833 
0834 int br_cfm_peer_mep_count(struct net_bridge *br, u32 *count)
0835 {
0836     struct br_cfm_peer_mep *peer_mep;
0837     struct br_cfm_mep *mep;
0838 
0839     *count = 0;
0840 
0841     rcu_read_lock();
0842     hlist_for_each_entry_rcu(mep, &br->mep_list, head)
0843         hlist_for_each_entry_rcu(peer_mep, &mep->peer_mep_list, head)
0844             *count += 1;
0845     rcu_read_unlock();
0846 
0847     return 0;
0848 }
0849 
0850 bool br_cfm_created(struct net_bridge *br)
0851 {
0852     return !hlist_empty(&br->mep_list);
0853 }
0854 
0855 /* Deletes the CFM instances on a specific bridge port
0856  */
0857 void br_cfm_port_del(struct net_bridge *br, struct net_bridge_port *port)
0858 {
0859     struct hlist_node *n_store;
0860     struct br_cfm_mep *mep;
0861 
0862     ASSERT_RTNL();
0863 
0864     hlist_for_each_entry_safe(mep, n_store, &br->mep_list, head)
0865         if (mep->create.ifindex == port->dev->ifindex)
0866             mep_delete_implementation(br, mep);
0867 }