Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Management Component Transport Protocol (MCTP) - routing
0004  * implementation.
0005  *
0006  * This is currently based on a simple routing table, with no dst cache. The
0007  * number of routes should stay fairly small, so the lookup cost is small.
0008  *
0009  * Copyright (c) 2021 Code Construct
0010  * Copyright (c) 2021 Google
0011  */
0012 
0013 #include <linux/idr.h>
0014 #include <linux/mctp.h>
0015 #include <linux/netdevice.h>
0016 #include <linux/rtnetlink.h>
0017 #include <linux/skbuff.h>
0018 
0019 #include <net/mctp.h>
0020 #include <net/mctpdevice.h>
0021 #include <net/netlink.h>
0022 #include <net/sock.h>
0023 
0024 static int mctp_neigh_add(struct mctp_dev *mdev, mctp_eid_t eid,
0025               enum mctp_neigh_source source,
0026               size_t lladdr_len, const void *lladdr)
0027 {
0028     struct net *net = dev_net(mdev->dev);
0029     struct mctp_neigh *neigh;
0030     int rc;
0031 
0032     mutex_lock(&net->mctp.neigh_lock);
0033     if (mctp_neigh_lookup(mdev, eid, NULL) == 0) {
0034         rc = -EEXIST;
0035         goto out;
0036     }
0037 
0038     if (lladdr_len > sizeof(neigh->ha)) {
0039         rc = -EINVAL;
0040         goto out;
0041     }
0042 
0043     neigh = kzalloc(sizeof(*neigh), GFP_KERNEL);
0044     if (!neigh) {
0045         rc = -ENOMEM;
0046         goto out;
0047     }
0048     INIT_LIST_HEAD(&neigh->list);
0049     neigh->dev = mdev;
0050     mctp_dev_hold(neigh->dev);
0051     neigh->eid = eid;
0052     neigh->source = source;
0053     memcpy(neigh->ha, lladdr, lladdr_len);
0054 
0055     list_add_rcu(&neigh->list, &net->mctp.neighbours);
0056     rc = 0;
0057 out:
0058     mutex_unlock(&net->mctp.neigh_lock);
0059     return rc;
0060 }
0061 
0062 static void __mctp_neigh_free(struct rcu_head *rcu)
0063 {
0064     struct mctp_neigh *neigh = container_of(rcu, struct mctp_neigh, rcu);
0065 
0066     mctp_dev_put(neigh->dev);
0067     kfree(neigh);
0068 }
0069 
0070 /* Removes all neighbour entries referring to a device */
0071 void mctp_neigh_remove_dev(struct mctp_dev *mdev)
0072 {
0073     struct net *net = dev_net(mdev->dev);
0074     struct mctp_neigh *neigh, *tmp;
0075 
0076     mutex_lock(&net->mctp.neigh_lock);
0077     list_for_each_entry_safe(neigh, tmp, &net->mctp.neighbours, list) {
0078         if (neigh->dev == mdev) {
0079             list_del_rcu(&neigh->list);
0080             /* TODO: immediate RTM_DELNEIGH */
0081             call_rcu(&neigh->rcu, __mctp_neigh_free);
0082         }
0083     }
0084 
0085     mutex_unlock(&net->mctp.neigh_lock);
0086 }
0087 
0088 static int mctp_neigh_remove(struct mctp_dev *mdev, mctp_eid_t eid,
0089                  enum mctp_neigh_source source)
0090 {
0091     struct net *net = dev_net(mdev->dev);
0092     struct mctp_neigh *neigh, *tmp;
0093     bool dropped = false;
0094 
0095     mutex_lock(&net->mctp.neigh_lock);
0096     list_for_each_entry_safe(neigh, tmp, &net->mctp.neighbours, list) {
0097         if (neigh->dev == mdev && neigh->eid == eid &&
0098             neigh->source == source) {
0099             list_del_rcu(&neigh->list);
0100             /* TODO: immediate RTM_DELNEIGH */
0101             call_rcu(&neigh->rcu, __mctp_neigh_free);
0102             dropped = true;
0103         }
0104     }
0105 
0106     mutex_unlock(&net->mctp.neigh_lock);
0107     return dropped ? 0 : -ENOENT;
0108 }
0109 
0110 static const struct nla_policy nd_mctp_policy[NDA_MAX + 1] = {
0111     [NDA_DST]       = { .type = NLA_U8 },
0112     [NDA_LLADDR]        = { .type = NLA_BINARY, .len = MAX_ADDR_LEN },
0113 };
0114 
0115 static int mctp_rtm_newneigh(struct sk_buff *skb, struct nlmsghdr *nlh,
0116                  struct netlink_ext_ack *extack)
0117 {
0118     struct net *net = sock_net(skb->sk);
0119     struct net_device *dev;
0120     struct mctp_dev *mdev;
0121     struct ndmsg *ndm;
0122     struct nlattr *tb[NDA_MAX + 1];
0123     int rc;
0124     mctp_eid_t eid;
0125     void *lladdr;
0126     int lladdr_len;
0127 
0128     rc = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, nd_mctp_policy,
0129              extack);
0130     if (rc < 0) {
0131         NL_SET_ERR_MSG(extack, "lladdr too large?");
0132         return rc;
0133     }
0134 
0135     if (!tb[NDA_DST]) {
0136         NL_SET_ERR_MSG(extack, "Neighbour EID must be specified");
0137         return -EINVAL;
0138     }
0139 
0140     if (!tb[NDA_LLADDR]) {
0141         NL_SET_ERR_MSG(extack, "Neighbour lladdr must be specified");
0142         return -EINVAL;
0143     }
0144 
0145     eid = nla_get_u8(tb[NDA_DST]);
0146     if (!mctp_address_unicast(eid)) {
0147         NL_SET_ERR_MSG(extack, "Invalid neighbour EID");
0148         return -EINVAL;
0149     }
0150 
0151     lladdr = nla_data(tb[NDA_LLADDR]);
0152     lladdr_len = nla_len(tb[NDA_LLADDR]);
0153 
0154     ndm = nlmsg_data(nlh);
0155 
0156     dev = __dev_get_by_index(net, ndm->ndm_ifindex);
0157     if (!dev)
0158         return -ENODEV;
0159 
0160     mdev = mctp_dev_get_rtnl(dev);
0161     if (!mdev)
0162         return -ENODEV;
0163 
0164     if (lladdr_len != dev->addr_len) {
0165         NL_SET_ERR_MSG(extack, "Wrong lladdr length");
0166         return -EINVAL;
0167     }
0168 
0169     return mctp_neigh_add(mdev, eid, MCTP_NEIGH_STATIC,
0170             lladdr_len, lladdr);
0171 }
0172 
0173 static int mctp_rtm_delneigh(struct sk_buff *skb, struct nlmsghdr *nlh,
0174                  struct netlink_ext_ack *extack)
0175 {
0176     struct net *net = sock_net(skb->sk);
0177     struct nlattr *tb[NDA_MAX + 1];
0178     struct net_device *dev;
0179     struct mctp_dev *mdev;
0180     struct ndmsg *ndm;
0181     int rc;
0182     mctp_eid_t eid;
0183 
0184     rc = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, nd_mctp_policy,
0185              extack);
0186     if (rc < 0) {
0187         NL_SET_ERR_MSG(extack, "incorrect format");
0188         return rc;
0189     }
0190 
0191     if (!tb[NDA_DST]) {
0192         NL_SET_ERR_MSG(extack, "Neighbour EID must be specified");
0193         return -EINVAL;
0194     }
0195     eid = nla_get_u8(tb[NDA_DST]);
0196 
0197     ndm = nlmsg_data(nlh);
0198     dev = __dev_get_by_index(net, ndm->ndm_ifindex);
0199     if (!dev)
0200         return -ENODEV;
0201 
0202     mdev = mctp_dev_get_rtnl(dev);
0203     if (!mdev)
0204         return -ENODEV;
0205 
0206     return mctp_neigh_remove(mdev, eid, MCTP_NEIGH_STATIC);
0207 }
0208 
0209 static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event,
0210                unsigned int flags, struct mctp_neigh *neigh)
0211 {
0212     struct net_device *dev = neigh->dev->dev;
0213     struct nlmsghdr *nlh;
0214     struct ndmsg *hdr;
0215 
0216     nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags);
0217     if (!nlh)
0218         return -EMSGSIZE;
0219 
0220     hdr = nlmsg_data(nlh);
0221     hdr->ndm_family = AF_MCTP;
0222     hdr->ndm_ifindex = dev->ifindex;
0223     hdr->ndm_state = 0; // TODO other state bits?
0224     if (neigh->source == MCTP_NEIGH_STATIC)
0225         hdr->ndm_state |= NUD_PERMANENT;
0226     hdr->ndm_flags = 0;
0227     hdr->ndm_type = RTN_UNICAST; // TODO: is loopback RTN_LOCAL?
0228 
0229     if (nla_put_u8(skb, NDA_DST, neigh->eid))
0230         goto cancel;
0231 
0232     if (nla_put(skb, NDA_LLADDR, dev->addr_len, neigh->ha))
0233         goto cancel;
0234 
0235     nlmsg_end(skb, nlh);
0236 
0237     return 0;
0238 cancel:
0239     nlmsg_cancel(skb, nlh);
0240     return -EMSGSIZE;
0241 }
0242 
0243 static int mctp_rtm_getneigh(struct sk_buff *skb, struct netlink_callback *cb)
0244 {
0245     struct net *net = sock_net(skb->sk);
0246     int rc, idx, req_ifindex;
0247     struct mctp_neigh *neigh;
0248     struct ndmsg *ndmsg;
0249     struct {
0250         int idx;
0251     } *cbctx = (void *)cb->ctx;
0252 
0253     ndmsg = nlmsg_data(cb->nlh);
0254     req_ifindex = ndmsg->ndm_ifindex;
0255 
0256     idx = 0;
0257     rcu_read_lock();
0258     list_for_each_entry_rcu(neigh, &net->mctp.neighbours, list) {
0259         if (idx < cbctx->idx)
0260             goto cont;
0261 
0262         rc = 0;
0263         if (req_ifindex == 0 || req_ifindex == neigh->dev->dev->ifindex)
0264             rc = mctp_fill_neigh(skb, NETLINK_CB(cb->skb).portid,
0265                          cb->nlh->nlmsg_seq,
0266                          RTM_NEWNEIGH, NLM_F_MULTI, neigh);
0267 
0268         if (rc)
0269             break;
0270 cont:
0271         idx++;
0272     }
0273     rcu_read_unlock();
0274 
0275     cbctx->idx = idx;
0276     return skb->len;
0277 }
0278 
0279 int mctp_neigh_lookup(struct mctp_dev *mdev, mctp_eid_t eid, void *ret_hwaddr)
0280 {
0281     struct net *net = dev_net(mdev->dev);
0282     struct mctp_neigh *neigh;
0283     int rc = -EHOSTUNREACH; // TODO: or ENOENT?
0284 
0285     rcu_read_lock();
0286     list_for_each_entry_rcu(neigh, &net->mctp.neighbours, list) {
0287         if (mdev == neigh->dev && eid == neigh->eid) {
0288             if (ret_hwaddr)
0289                 memcpy(ret_hwaddr, neigh->ha,
0290                        sizeof(neigh->ha));
0291             rc = 0;
0292             break;
0293         }
0294     }
0295     rcu_read_unlock();
0296     return rc;
0297 }
0298 
0299 /* namespace registration */
0300 static int __net_init mctp_neigh_net_init(struct net *net)
0301 {
0302     struct netns_mctp *ns = &net->mctp;
0303 
0304     INIT_LIST_HEAD(&ns->neighbours);
0305     mutex_init(&ns->neigh_lock);
0306     return 0;
0307 }
0308 
0309 static void __net_exit mctp_neigh_net_exit(struct net *net)
0310 {
0311     struct netns_mctp *ns = &net->mctp;
0312     struct mctp_neigh *neigh;
0313 
0314     list_for_each_entry(neigh, &ns->neighbours, list)
0315         call_rcu(&neigh->rcu, __mctp_neigh_free);
0316 }
0317 
0318 /* net namespace implementation */
0319 
0320 static struct pernet_operations mctp_net_ops = {
0321     .init = mctp_neigh_net_init,
0322     .exit = mctp_neigh_net_exit,
0323 };
0324 
0325 int __init mctp_neigh_init(void)
0326 {
0327     rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_NEWNEIGH,
0328                  mctp_rtm_newneigh, NULL, 0);
0329     rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_DELNEIGH,
0330                  mctp_rtm_delneigh, NULL, 0);
0331     rtnl_register_module(THIS_MODULE, PF_MCTP, RTM_GETNEIGH,
0332                  NULL, mctp_rtm_getneigh, 0);
0333 
0334     return register_pernet_subsys(&mctp_net_ops);
0335 }
0336 
0337 void __exit mctp_neigh_exit(void)
0338 {
0339     unregister_pernet_subsys(&mctp_net_ops);
0340     rtnl_unregister(PF_MCTP, RTM_GETNEIGH);
0341     rtnl_unregister(PF_MCTP, RTM_DELNEIGH);
0342     rtnl_unregister(PF_MCTP, RTM_NEWNEIGH);
0343 }