tLinux.c - plan9port - [fork] Plan 9 from user space | |
git clone git://src.adamsgaard.dk/plan9port | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
tLinux.c (5339B) | |
--- | |
1 #include <u.h> | |
2 #include <sys/ioctl.h> | |
3 #include <sys/socket.h> | |
4 #include <netinet/in.h> | |
5 #include <arpa/inet.h> | |
6 #include <asm/types.h> | |
7 #include <net/if_arp.h> | |
8 #include <linux/netlink.h> | |
9 #include <linux/rtnetlink.h> | |
10 #include <net/if.h> | |
11 #include <libc.h> | |
12 #include <ip.h> | |
13 | |
14 /* | |
15 * Use netlink sockets to find interfaces. | |
16 * Thanks to Erik Quanstrom. | |
17 */ | |
18 static int | |
19 netlinkrequest(int fd, int type, int (*fn)(struct nlmsghdr *h, Ipifc**, … | |
20 Ipifc **ifc, int index) | |
21 { | |
22 char buf[1024]; | |
23 int n; | |
24 struct sockaddr_nl nl; | |
25 struct { | |
26 struct nlmsghdr nlh; | |
27 struct rtgenmsg g; | |
28 } req; | |
29 struct nlmsghdr *h; | |
30 | |
31 memset(&nl, 0, sizeof nl); | |
32 nl.nl_family = AF_NETLINK; | |
33 | |
34 memset(&req, 0, sizeof req); | |
35 req.nlh.nlmsg_len = sizeof req; | |
36 req.nlh.nlmsg_type = type; | |
37 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; | |
38 req.nlh.nlmsg_pid = 0; | |
39 req.nlh.nlmsg_seq = 1; | |
40 req.g.rtgen_family = AF_NETLINK; | |
41 | |
42 if(sendto(fd, (void*)&req, sizeof req, 0, (struct sockaddr*)&nl,… | |
43 return -1; | |
44 | |
45 while((n=read(fd, buf, sizeof buf)) > 0){ | |
46 for(h=(struct nlmsghdr*)buf; NLMSG_OK(h, n); h = NLMSG_N… | |
47 if(h->nlmsg_type == NLMSG_DONE) | |
48 return 0; | |
49 if(h->nlmsg_type == NLMSG_ERROR){ | |
50 werrstr("netlink error"); | |
51 return -1; | |
52 } | |
53 if(fn(h, ifc, index) < 0) | |
54 return -1; | |
55 } | |
56 } | |
57 werrstr("netlink error"); | |
58 return -1; | |
59 } | |
60 | |
61 static int | |
62 devsocket(void) | |
63 { | |
64 /* we couldn't care less which one; just want to talk to the ker… | |
65 static int dumb[3] = { AF_INET, AF_PACKET, AF_INET6 }; | |
66 int i, fd; | |
67 | |
68 for(i=0; i<nelem(dumb); i++) | |
69 if((fd = socket(dumb[i], SOCK_DGRAM, 0)) >= 0) | |
70 return fd; | |
71 return -1; | |
72 } | |
73 | |
74 static int | |
75 parsertattr(struct rtattr **dst, int ndst, struct nlmsghdr *h, int type,… | |
76 { | |
77 struct rtattr *src; | |
78 int len; | |
79 | |
80 len = h->nlmsg_len - NLMSG_LENGTH(skip); | |
81 if(len < 0 || h->nlmsg_type != type){ | |
82 werrstr("attrs too short"); | |
83 return -1; | |
84 } | |
85 src = (struct rtattr*)((char*)NLMSG_DATA(h) + NLMSG_ALIGN(skip)); | |
86 | |
87 memset(dst, 0, ndst*sizeof dst[0]); | |
88 for(; RTA_OK(src, len); src = RTA_NEXT(src, len)) | |
89 if(src->rta_type < ndst) | |
90 dst[src->rta_type] = src; | |
91 return 0; | |
92 } | |
93 | |
94 static void | |
95 rta2ip(int af, uchar *ip, struct rtattr *rta) | |
96 { | |
97 memset(ip, 0, IPaddrlen); | |
98 | |
99 switch(af){ | |
100 case AF_INET: | |
101 memmove(ip, v4prefix, IPv4off); | |
102 memmove(ip+IPv4off, RTA_DATA(rta), IPv4addrlen); | |
103 break; | |
104 case AF_INET6: | |
105 memmove(ip, RTA_DATA(rta), IPaddrlen); | |
106 break; | |
107 } | |
108 } | |
109 | |
110 static int | |
111 getlink(struct nlmsghdr *h, Ipifc **ipifclist, int index) | |
112 { | |
113 char *p; | |
114 int fd; | |
115 struct rtattr *attr[IFLA_MAX+1]; | |
116 struct ifinfomsg *ifi; | |
117 Ipifc *ifc; | |
118 | |
119 ifi = (struct ifinfomsg*)NLMSG_DATA(h); | |
120 if(index >= 0 && ifi->ifi_index != index) | |
121 return 0; | |
122 | |
123 ifc = mallocz(sizeof *ifc, 1); | |
124 if(ifc == nil) | |
125 return -1; | |
126 ifc->index = ifi->ifi_index; | |
127 | |
128 while(*ipifclist) | |
129 ipifclist = &(*ipifclist)->next; | |
130 *ipifclist = ifc; | |
131 | |
132 if(parsertattr(attr, nelem(attr), h, RTM_NEWLINK, sizeof(struct … | |
133 return -1; | |
134 | |
135 if(attr[IFLA_IFNAME]) | |
136 p = (char*)RTA_DATA(attr[IFLA_IFNAME]); | |
137 else | |
138 p = "nil"; | |
139 strecpy(ifc->dev, ifc->dev+sizeof ifc->dev, p); | |
140 | |
141 if(attr[IFLA_MTU]) | |
142 ifc->mtu = *(int*)RTA_DATA(attr[IFLA_MTU]); | |
143 | |
144 /* | |
145 * Does not work on old Linux systems, | |
146 * and not really necessary for my purposes. | |
147 * Uncomment if you want it bad. | |
148 * | |
149 if(attr[IFLA_STATS]){ | |
150 struct rtnl_link_stats *s; | |
151 | |
152 s = RTA_DATA(attr[IFLA_STATS]); | |
153 ifc->pktin = s->rx_packets; | |
154 ifc->pktout = s->tx_packets; | |
155 ifc->errin = s->rx_errors; | |
156 ifc->errout = s->tx_errors; | |
157 } | |
158 * | |
159 */ | |
160 | |
161 if((fd = devsocket()) > 0){ | |
162 struct ifreq ifr; | |
163 | |
164 memset(&ifr, 0, sizeof ifr); | |
165 strncpy(ifr.ifr_name, p, IFNAMSIZ); | |
166 ifr.ifr_mtu = 0; | |
167 if(ioctl(fd, SIOCGIFMTU, &ifr) >= 0) | |
168 ifc->rp.linkmtu = ifr.ifr_mtu; | |
169 | |
170 memset(&ifr, 0, sizeof ifr); | |
171 strncpy(ifr.ifr_name, p, IFNAMSIZ); | |
172 if(ioctl(fd, SIOCGIFHWADDR, &ifr) >= 0 | |
173 && ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) | |
174 memmove(ifc->ether, ifr.ifr_hwaddr.sa_data, 6); | |
175 | |
176 close(fd); | |
177 } | |
178 return 0; | |
179 } | |
180 | |
181 static int | |
182 getaddr(struct nlmsghdr *h, Ipifc **ipifclist, int index) | |
183 { | |
184 int mask; | |
185 Ipifc *ifc; | |
186 Iplifc *lifc, **l; | |
187 struct ifaddrmsg *ifa; | |
188 struct rtattr *attr[IFA_MAX+1]; | |
189 | |
190 USED(index); | |
191 | |
192 ifa = (struct ifaddrmsg*)NLMSG_DATA(h); | |
193 for(ifc=*ipifclist; ifc; ifc=ifc->next) | |
194 if(ifc->index == ifa->ifa_index) | |
195 break; | |
196 if(ifc == nil) | |
197 return 0; | |
198 if(parsertattr(attr, nelem(attr), h, RTM_NEWADDR, sizeof(struct … | |
199 return -1; | |
200 | |
201 lifc = mallocz(sizeof *lifc, 1); | |
202 if(lifc == nil) | |
203 return -1; | |
204 for(l=&ifc->lifc; *l; l=&(*l)->next) | |
205 ; | |
206 *l = lifc; | |
207 | |
208 if(attr[IFA_ADDRESS] == nil) | |
209 attr[IFA_ADDRESS] = attr[IFA_LOCAL]; | |
210 if(attr[IFA_ADDRESS] == nil) | |
211 return 0; | |
212 | |
213 rta2ip(ifa->ifa_family, lifc->ip, attr[IFA_ADDRESS]); | |
214 | |
215 mask = ifa->ifa_prefixlen/8; | |
216 if(ifa->ifa_family == AF_INET) | |
217 mask += IPv4off; | |
218 memset(lifc->mask, 0xFF, mask); | |
219 memmove(lifc->net, lifc->ip, mask); | |
220 | |
221 if(attr[IFA_CACHEINFO]){ | |
222 struct ifa_cacheinfo *ci; | |
223 | |
224 ci = RTA_DATA(attr[IFA_CACHEINFO]); | |
225 lifc->preflt = ci->ifa_prefered; | |
226 lifc->validlt = ci->ifa_valid; | |
227 } | |
228 return 0; | |
229 } | |
230 | |
231 Ipifc* | |
232 readipifc(char *net, Ipifc *ifc, int index) | |
233 { | |
234 int fd; | |
235 | |
236 USED(net); | |
237 freeipifc(ifc); | |
238 ifc = nil; | |
239 | |
240 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); | |
241 if(fd < 0) | |
242 return nil; | |
243 ifc = nil; | |
244 if(netlinkrequest(fd, RTM_GETLINK, getlink, &ifc, index) < 0 | |
245 || netlinkrequest(fd, RTM_GETADDR, getaddr, &ifc, index) < 0){ | |
246 close(fd); | |
247 freeipifc(ifc); | |
248 return nil; | |
249 } | |
250 close(fd); | |
251 return ifc; | |
252 } |