patch-2.1.89 linux/net/core/rtnetlink.c
Next file: linux/net/core/scm.c
Previous file: linux/net/core/neighbour.c
Back to the patch index
Back to the overall index
- Lines: 372
- Date:
Sun Mar 1 14:40:40 1998
- Orig file:
v2.1.88/linux/net/core/rtnetlink.c
- Orig date:
Thu Feb 12 20:56:14 1998
diff -u --recursive --new-file v2.1.88/linux/net/core/rtnetlink.c linux/net/core/rtnetlink.c
@@ -74,81 +74,29 @@
#define _X 2 /* exclusive access to tables required */
#define _G 4 /* GET request */
-static unsigned char rtm_properties[RTM_MAX-RTM_BASE+1] =
+static const int rtm_min[(RTM_MAX+1-RTM_BASE)/4] =
{
- _S|_X, /* RTM_NEWLINK */
- _S|_X, /* RTM_DELLINK */
- _G, /* RTM_GETLINK */
- 0,
-
- _S|_X, /* RTM_NEWADDR */
- _S|_X, /* RTM_DELADDR */
- _G, /* RTM_GETADDR */
- 0,
-
- _S|_X, /* RTM_NEWROUTE */
- _S|_X, /* RTM_DELROUTE */
- _G, /* RTM_GETROUTE */
- 0,
-
- _S|_X, /* RTM_NEWNEIGH */
- _S|_X, /* RTM_DELNEIGH */
- _G, /* RTM_GETNEIGH */
- 0,
-
- _S|_X, /* RTM_NEWRULE */
- _S|_X, /* RTM_DELRULE */
- _G, /* RTM_GETRULE */
- 0
+ NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+ NLMSG_LENGTH(sizeof(struct ifaddrmsg)),
+ NLMSG_LENGTH(sizeof(struct rtmsg)),
+ NLMSG_LENGTH(sizeof(struct ndmsg)),
+ NLMSG_LENGTH(sizeof(struct rtmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg)),
+ NLMSG_LENGTH(sizeof(struct tcmsg))
};
-static int rtnetlink_get_rta(struct kern_rta *rta, struct rtattr *attr, int attrlen)
+static const int rta_max[(RTM_MAX+1-RTM_BASE)/4] =
{
- void **rta_data = (void**)rta;
-
- while (RTA_OK(attr, attrlen)) {
- int type = attr->rta_type;
- if (type != RTA_UNSPEC) {
- if (type > RTA_MAX)
- return -EINVAL;
- rta_data[type-1] = RTA_DATA(attr);
- }
- attr = RTA_NEXT(attr, attrlen);
- }
- return 0;
-}
-
-static int rtnetlink_get_ifa(struct kern_ifa *ifa, struct rtattr *attr, int attrlen)
-{
- void **ifa_data = (void**)ifa;
-
- while (RTA_OK(attr, attrlen)) {
- int type = attr->rta_type;
- if (type != IFA_UNSPEC) {
- if (type > IFA_MAX)
- return -EINVAL;
- ifa_data[type-1] = RTA_DATA(attr);
- }
- attr = RTA_NEXT(attr, attrlen);
- }
- return 0;
-}
-
-static int rtnetlink_get_ga(struct rtattr **rta, int sz,
- struct rtattr *attr, int attrlen)
-{
- while (RTA_OK(attr, attrlen)) {
- int type = attr->rta_type;
- if (type > 0) {
- if (type > sz)
- return -EINVAL;
- rta[type-1] = attr;
- }
- attr = RTA_NEXT(attr, attrlen);
- }
- return 0;
-}
-
+ IFLA_MAX,
+ IFA_MAX,
+ RTA_MAX,
+ NDA_MAX,
+ RTA_MAX,
+ TCA_MAX,
+ TCA_MAX,
+ TCA_MAX
+};
void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data)
{
@@ -161,6 +109,7 @@
memcpy(RTA_DATA(rta), data, attrlen);
}
+#ifdef CONFIG_RTNL_OLD_IFINFO
static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct device *dev,
int type, pid_t pid, u32 seq)
{
@@ -195,9 +144,55 @@
nlmsg_failure:
rtattr_failure:
- skb_put(skb, b - skb->tail);
+ skb_trim(skb, b - skb->data);
return -1;
}
+#else
+static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct device *dev,
+ int type, pid_t pid, u32 seq)
+{
+ struct ifinfomsg *r;
+ struct nlmsghdr *nlh;
+ unsigned char *b = skb->tail;
+
+ nlh = NLMSG_PUT(skb, pid, seq, type, sizeof(*r));
+ if (pid) nlh->nlmsg_flags |= NLM_F_MULTI;
+ r = NLMSG_DATA(nlh);
+ r->ifi_family = AF_UNSPEC;
+ r->ifi_type = dev->type;
+ r->ifi_index = dev->ifindex;
+ r->ifi_flags = dev->flags;
+ r->ifi_change = ~0U;
+
+ RTA_PUT(skb, IFLA_IFNAME, strlen(dev->name)+1, dev->name);
+ if (dev->addr_len) {
+ RTA_PUT(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr);
+ RTA_PUT(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast);
+ }
+ if (1) {
+ unsigned mtu = dev->mtu;
+ RTA_PUT(skb, IFLA_MTU, sizeof(mtu), &mtu);
+ }
+ if (dev->ifindex != dev->iflink)
+ RTA_PUT(skb, IFLA_LINK, sizeof(int), &dev->iflink);
+ if (dev->qdisc_sleeping->ops)
+ RTA_PUT(skb, IFLA_QDISC,
+ strlen(dev->qdisc_sleeping->ops->id) + 1,
+ dev->qdisc_sleeping->ops->id);
+ if (dev->get_stats) {
+ struct net_device_stats *stats = dev->get_stats(dev);
+ if (stats)
+ RTA_PUT(skb, IFLA_STATS, sizeof(*stats), stats);
+ }
+ nlh->nlmsg_len = skb->tail - b;
+ return skb->len;
+
+nlmsg_failure:
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+#endif
int rtnetlink_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
{
@@ -242,12 +237,15 @@
return skb->len;
}
-
void rtmsg_ifinfo(int type, struct device *dev)
{
struct sk_buff *skb;
+#ifdef CONFIG_RTNL_OLD_IFINFO
int size = NLMSG_SPACE(sizeof(struct ifinfomsg)+
RTA_LENGTH(sizeof(struct net_device_stats)));
+#else
+ int size = NLMSG_GOODSIZE;
+#endif
skb = alloc_skb(size, GFP_KERNEL);
if (!skb)
@@ -273,49 +271,68 @@
extern __inline__ int
rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
{
- union {
- struct kern_rta rta;
- struct kern_ifa ifa;
- struct rtattr *ga[RTA_MAX-1];
- } u;
- struct rtmsg *rtm;
- struct ifaddrmsg *ifm;
- struct ndmsg *ndm;
+ struct rtnetlink_link *link;
+ struct rtnetlink_link *link_tab;
+ struct rtattr *rta[RTATTR_MAX];
+
int exclusive = 0;
+ int sz_idx, kind;
+ int min_len;
int family;
int type;
int err;
+ /* Only requests are handled by kernel now */
if (!(nlh->nlmsg_flags&NLM_F_REQUEST))
return 0;
+
type = nlh->nlmsg_type;
+
+ /* A control message: ignore them */
if (type < RTM_BASE)
return 0;
+
+ /* Unknown message: reply with EINVAL */
if (type > RTM_MAX)
goto err_inval;
+ type -= RTM_BASE;
+
+ /* All the messages must have at least 1 byte length */
if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct rtgenmsg)))
return 0;
+
family = ((struct rtgenmsg*)NLMSG_DATA(nlh))->rtgen_family;
- if (family > NPROTO || rtnetlink_links[family] == NULL) {
+ if (family > NPROTO) {
*errp = -EAFNOSUPPORT;
return -1;
}
- if (rtm_properties[type-RTM_BASE]&_S) {
- if (NETLINK_CREDS(skb)->uid) {
- *errp = -EPERM;
- return -1;
- }
+
+ link_tab = rtnetlink_links[family];
+ if (link_tab == NULL)
+ link_tab = rtnetlink_links[AF_UNSPEC];
+ link = &link_tab[type];
+
+ sz_idx = type>>2;
+ kind = type&3;
+
+ if (kind != 2 && NETLINK_CREDS(skb)->uid) {
+ *errp = -EPERM;
+ return -1;
}
- if (rtm_properties[type-RTM_BASE]&_G && nlh->nlmsg_flags&NLM_F_DUMP) {
- if (rtnetlink_links[family][type-RTM_BASE].dumpit == NULL)
+
+ if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) {
+ if (link->dumpit == NULL)
+ link = &(rtnetlink_links[AF_UNSPEC][type]);
+
+ if (link->dumpit == NULL)
goto err_inval;
/* Super-user locks all the tables to get atomic snapshot */
if (NETLINK_CREDS(skb)->uid == 0 && nlh->nlmsg_flags&NLM_F_ATOMIC)
atomic_inc(&rtnl_rlockct);
if ((*errp = netlink_dump_start(rtnl, skb, nlh,
- rtnetlink_links[family][type-RTM_BASE].dumpit,
+ link->dumpit,
rtnetlink_done)) != 0) {
if (NETLINK_CREDS(skb)->uid == 0 && nlh->nlmsg_flags&NLM_F_ATOMIC)
atomic_dec(&rtnl_rlockct);
@@ -324,68 +341,41 @@
skb_pull(skb, NLMSG_ALIGN(nlh->nlmsg_len));
return -1;
}
- if (rtm_properties[type-RTM_BASE]&_X) {
+
+ if (kind != 2) {
if (rtnl_exlock_nowait()) {
*errp = 0;
return -1;
}
exclusive = 1;
}
-
- memset(&u, 0, sizeof(u));
- switch (nlh->nlmsg_type) {
- case RTM_NEWROUTE:
- case RTM_DELROUTE:
- case RTM_GETROUTE:
- case RTM_NEWRULE:
- case RTM_DELRULE:
- case RTM_GETRULE:
- rtm = NLMSG_DATA(nlh);
- if (nlh->nlmsg_len < sizeof(*rtm))
- goto err_inval;
-
- if (rtm->rtm_optlen &&
- rtnetlink_get_rta(&u.rta, RTM_RTA(rtm), rtm->rtm_optlen) < 0)
- goto err_inval;
- break;
-
- case RTM_NEWADDR:
- case RTM_DELADDR:
- case RTM_GETADDR:
- ifm = NLMSG_DATA(nlh);
- if (nlh->nlmsg_len < sizeof(*ifm))
- goto err_inval;
+ memset(&rta, 0, sizeof(rta));
- if (nlh->nlmsg_len > NLMSG_LENGTH(sizeof(*ifm)) &&
- rtnetlink_get_ifa(&u.ifa, IFA_RTA(ifm),
- nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ifm))) < 0)
- goto err_inval;
- break;
- case RTM_NEWNEIGH:
- case RTM_DELNEIGH:
- case RTM_GETNEIGH:
- ndm = NLMSG_DATA(nlh);
- if (nlh->nlmsg_len < sizeof(*ndm))
- goto err_inval;
-
- if (nlh->nlmsg_len > NLMSG_LENGTH(sizeof(*ndm)) &&
- rtnetlink_get_ga(u.ga, NDA_MAX, NDA_RTA(ndm),
- nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*ndm))) < 0)
- goto err_inval;
- break;
-
- case RTM_NEWLINK:
- case RTM_DELLINK:
- case RTM_GETLINK:
- /* Not urgent and even not necessary */
- default:
+ min_len = rtm_min[sz_idx];
+ if (nlh->nlmsg_len < min_len)
goto err_inval;
+
+ if (nlh->nlmsg_len > min_len) {
+ int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
+ struct rtattr *attr = (void*)nlh + NLMSG_ALIGN(min_len);
+
+ while (RTA_OK(attr, attrlen)) {
+ unsigned flavor = attr->rta_type;
+ if (flavor) {
+ if (flavor > rta_max[sz_idx])
+ goto err_inval;
+ rta[flavor-1] = attr;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
}
- if (rtnetlink_links[family][type-RTM_BASE].doit == NULL)
+ if (link->doit == NULL)
+ link = &(rtnetlink_links[AF_UNSPEC][type]);
+ if (link->doit == NULL)
goto err_inval;
- err = rtnetlink_links[family][type-RTM_BASE].doit(skb, nlh, (void *)&u);
+ err = link->doit(skb, nlh, (void *)&rta);
if (exclusive)
rtnl_exunlock();
@@ -480,8 +470,8 @@
{ NULL, rtnetlink_dump_all, },
{ NULL, NULL, },
- { NULL, NULL, },
- { NULL, NULL, },
+ { neigh_add, NULL, },
+ { neigh_delete, NULL, },
{ NULL, neigh_dump_info, },
{ NULL, NULL, },
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov