先来看nlmsghdr:
struct nlmsghdr {
_u32 nlmsg_len;
_u32 nlmsg_type;
_u16 nlmsg_flags;
_u32 nlmsg_seq;
_u32 nlmsg_pid;
};
nlmsg_type决定这次要执行的操作,如查询当前路由表信息,所使用的就是RTM_GETROUTE。标准nlmsg_type包括:NLMSG_NOOP,
NLMSG_DONE,
NLMSG_ERROR等。根据采用的nlmsg_type不同,还要选取不同的数据结构来填充到nlmsghdr后面:
操作 数据结构
RTM_NEWLINK ifinfomsg
RTM_DELLINK
RTM_GETLINK
RTM_NEWADDR ifaddrmsg
RTM_DELADDR
RTM_GETADDR
RTM_NEWROUTE rtmsg
RTM_DELROUTE
RTM_GETROUTE
RTM_NEWNEIGH ndmsg/nda_chcheinfo
RTM_DELNEIGH
RTM_GETNEIGH
RTM_NEWRULE rtmsg
RTM_DELRULE
RTM_GETRULE
RTM_NEWQDISC tcmsg
RTM_DELQDISC
RTM_GETQDISC
RTM_NEWTCLASS tcmsg
RTM_DELTCLASS
RTM_GETTCLASS
RTM_NEWTFILTER tcmsg
RTM_DELTFILTER
RTM_GETTFILTER
由于情形众多,我从现在开始将用一个特定的例子来说明问题。我们的目的是从内核读取IPV4路由表信息。从上面表看,nlmsg_type一定使用RTM_xxxROUTE操作,对应的数据结构是rtmsg。既然是读取,那么应该是RTM_GETROUTE了。
struct rtmsg {
unsigned char rtm_family;
unsigned char rtm_dst_len;
unsigned char rtm_src_len; (2.4.10头文件的注释标反了?)
unsigned char rtm_tos;
unsigned char rtm_table;
unsigned char rtm_protocol;
unsigned char rtm_scope;
unsigned char rtm_type;
unsigned int rtm_flags;
};
对于RTM_GETROUTE操作来说,我们只需指定两个成员:rtm_family:AF_INET, rtm_table:
RT_TABLE_MAIN。其他成员都初始化为0即可。将这个结构体跟nlmsghdr结合起来,得到我们自己的新结构体:
struct {
struct nlmsghdr nl;
struct rtmsg rt;
}req;
struct kern_rta
{
void *rta_dst;
void *rta_src;
int *rta_iif;
int *rta_oif;
void *rta_gw;
u32 *rta_priority;
void *rta_prefsrc;
struct rtattr *rta_mx;
struct rtattr *rta_mp;
unsigned char *rta_protoinfo;
unsigned char *rta_flow;
struct rta_cacheinfo *rta_ci;
};
Note that this structure has a one to one correspondance with
the routing table attributes so that the typecasting makes
sense.
enum rtattr_type_t
{
RTA_UNSPEC,
RTA_DST,
RTA_SRC,
RTA_IIF,
RTA_OIF,
RTA_GATEWAY,
RTA_PRIORITY,
RTA_PREFSRC,
RTA_METRICS,
RTA_MULTIPATH,
RTA_PROTOINFO,
RTA_FLOW,
RTA_CACHEINFO
};
struct rtentry
{
unsigned long rt_pad1;
struct sockaddr
rt_dst;
struct sockaddr
rt_gateway;
struct sockaddr
rt_genmask;
unsigned short rt_flags;
short
rt_pad2;
unsigned long rt_pad3;
void
*rt_pad4;
short
rt_metric;
char
*rt_dev;
unsigned long
rt_mtu;
#ifndef __KERNEL__
#define rt_mss
rt_mtu
#endif
unsigned long
rt_window;
unsigned short
rt_irtt;
};
#define
RTF_UP
0x0001
#define
RTF_GATEWAY
0x0002
#define
RTF_HOST
0x0004
#define RTF_REINSTATE
0x0008
#define
RTF_DYNAMIC
0x0010
#define
RTF_MODIFIED
0x0020
#define
RTF_MTU
0x0040
#define
RTF_MSS
RTF_MTU
#define
RTF_WINDOW
0x0080
#define
RTF_IRTT
0x0100
#define
RTF_REJECT
0x0200
fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct
rtmsg *rtm,
struct kern_rta *rta, struct rtentry *r)
{
int plen;
u32 *ptr;
memset(rtm, 0, sizeof(*rtm));
memset(rta, 0, sizeof(*rta));
if (r->rt_dst.sa_family != AF_INET)
return -EAFNOSUPPORT;
plen = 32;
ptr = &((struct
sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;
if (!(r->rt_flags&RTF_HOST)) {
u32 mask = ((struct
sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;
if (r->rt_genmask.sa_family != AF_INET) {
if
(mask || r->rt_genmask.sa_family)
return -EAFNOSUPPORT;
}
if (bad_mask(mask, *ptr))
return -EINVAL;
plen = inet_mask_len(mask);
}
nl->nlmsg_flags = NLM_F_REQUEST;
nl->nlmsg_pid = 0;
nl->nlmsg_seq = 0;
nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));
if (cmd == SIOCDELRT) {
nl->nlmsg_type = RTM_DELROUTE;
nl->nlmsg_flags = 0;
} else {
nl->nlmsg_type = RTM_NEWROUTE;
nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;
rtm->rtm_protocol = RTPROT_BOOT;
}
rtm->rtm_dst_len = plen;
rta->rta_dst = ptr;
if (r->rt_metric) {
*(u32*)&r->rt_pad3 =
r->rt_metric - 1;
rta->rta_priority =
(u32*)&r->rt_pad3;
}
if (r->rt_flags&RTF_REJECT) {
rtm->rtm_scope = RT_SCOPE_HOST;
rtm->rtm_type = RTN_UNREACHABLE;
return 0;
}
rtm->rtm_scope = RT_SCOPE_NOWHERE;
rtm->rtm_type = RTN_UNICAST;
if (r->rt_dev) {
#ifdef CONFIG_IP_ALIAS
char *colon;
#endif
struct net_device *dev;
char devname[IFNAMSIZ];
if (copy_from_user(devname, r->rt_dev,
IFNAMSIZ-1))
return -EFAULT;
devname[IFNAMSIZ-1] = 0;
#ifdef CONFIG_IP_ALIAS
colon = strchr(devname, ':');
if (colon)
*colon = 0;
#endif
dev = dev_get(devname);
if (!dev)
return -ENODEV;
rta->rta_oif =
&dev->ifindex;
#ifdef CONFIG_IP_ALIAS
if (colon) {
struct in_ifaddr *ifa;
struct in_device *in_dev = dev->ip_ptr;
if (!in_dev)
return -ENODEV;
*colon =
':';
for (ifa = in_dev->ifa_list; ifa; ifa =
ifa->ifa_next)
if (strcmp(ifa->ifa_label, devname) == 0)
break;
if (ifa == NULL)
return -ENODEV;
rta->rta_prefsrc =
&ifa->ifa_local;
}
#endif
}
ptr = &((struct
sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;
if (r->rt_gateway.sa_family == AF_INET
&& *ptr) {
rta->rta_gw = ptr;
if (r->rt_flags&RTF_GATEWAY
&& inet_addr_type(*ptr) ==
RTN_UNICAST)
rtm->rtm_scope = RT_SCOPE_UNIVERSE;
}
if (cmd == SIOCDELRT)
return 0;
if (r->rt_flags&RTF_GATEWAY
&& rta->rta_gw ==
NULL)
return -EINVAL;
if (rtm->rtm_scope == RT_SCOPE_NOWHERE)
rtm->rtm_scope = RT_SCOPE_LINK;
if
(r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT))
{
struct rtattr *rec;
struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)),
GFP_KERNEL);
if (mx == NULL)
return -ENOMEM;
rta->rta_mx = mx;
mx->rta_type = RTA_METRICS;
mx->rta_len = RTA_LENGTH(0);
if (r->rt_flags&RTF_MTU) {
rec = (void*)((char*)mx +
RTA_ALIGN(mx->rta_len));
rec->rta_type = RTAX_MTU;
rec->rta_len = RTA_LENGTH(4);
mx->rta_len += RTA_LENGTH(4);
*(u32*)RTA_DATA(rec) = r->rt_mtu;
}
if (r->rt_flags&RTF_WINDOW) {
rec = (void*)((char*)mx +
RTA_ALIGN(mx->rta_len));
rec->rta_type = RTAX_WINDOW;
rec->rta_len = RTA_LENGTH(4);
mx->rta_len += RTA_LENGTH(4);
*(u32*)RTA_DATA(rec) = r->rt_window;
}
if (r->rt_flags&RTF_IRTT) {
rec = (void*)((char*)mx +
RTA_ALIGN(mx->rta_len));
rec->rta_type = RTAX_RTT;
rec->rta_len = RTA_LENGTH(4);
mx->rta_len += RTA_LENGTH(4);
*(u32*)RTA_DATA(rec) = r->rt_irtt;
}
}
return 0;
}
加载中,请稍候......