1 /* This file is part of Netwib. Read and honor its license.
2 */
3
4 /*-------------------------------------------------------------*/
5 /***
6 Used by :
7 Linux
8 Solaris
9 ***/
10
11 /*-------------------------------------------------------------*/
netwib_priv_conf_devices_ioctl_hw(int fd,netwib_conststring device,netwib_device_hwtype * phwtype,netwib_eth * peth)12 static netwib_err netwib_priv_conf_devices_ioctl_hw(int fd,
13 netwib_conststring device,
14 netwib_device_hwtype *phwtype,
15 netwib_eth *peth)
16 #if defined NETWIBDEF_SYSNAME_Linux
17 {
18 struct ifreq ifr;
19 int reti;
20
21 netwib_c_memset(&ifr, 0, sizeof(ifr));
22 netwib_c_strcpy(ifr.ifr_name, device);
23 ifr.ifr_addr.sa_family = AF_INET;
24 reti = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
25 if (reti < 0) {
26 return(NETWIB_ERR_FUIOCTL);
27 }
28
29 switch(ifr.ifr_hwaddr.sa_family) {
30 case ARPHRD_ETHER :
31 *phwtype = NETWIB_DEVICE_HWTYPE_ETHER;
32 netwib_c_memcpy(peth->b, &ifr.ifr_hwaddr.sa_data, NETWIB_ETH_LEN);
33 break;
34 case ARPHRD_LOOPBACK :
35 *phwtype = NETWIB_DEVICE_HWTYPE_LOOPBACK;
36 break;
37 case ARPHRD_PPP :
38 *phwtype = NETWIB_DEVICE_HWTYPE_PPP;
39 break;
40 default :
41 *phwtype = NETWIB_DEVICE_HWTYPE_UNKNOWN;
42 break;
43 }
44
45 return(NETWIB_ERR_OK);
46 }
47 #elif defined NETWIBDEF_SYSNAME_Solaris
48 {
49 netwib_ptr buf;
50 netwib_data pbufeth;
51 dl_info_req_t ireq;
52 dl_phys_addr_req_t pareq;
53 int fd2;
54 netwib_err ret;
55
56 if (!netwib_c_strcmp(device, "lo0")) {
57 *phwtype = NETWIB_DEVICE_HWTYPE_LOOPBACK;
58 return(NETWIB_ERR_OK);
59 }
60
61 ret = netwib_priv_dlpi_open(device, &fd2);
62 if (ret != NETWIB_ERR_OK) {
63 /* if we are not root, we cannot retrieve device type and
64 address. */
65 *phwtype = NETWIB_DEVICE_HWTYPE_UNKNOWN;
66 return(NETWIB_ERR_OK);
67 }
68
69 netwib_er(netwib_ptr_malloc(2048, &buf));
70 ret = NETWIB_ERR_OK;
71
72 /* ask type */
73 ireq.dl_primitive = DL_INFO_REQ;
74 netwib_eg(netwib_priv_dlpi_putmsg(fd2, &ireq, sizeof(ireq), 0));
75 netwib_eg(netwib_priv_dlpi_getmsg(fd2, DL_INFO_ACK_SIZE, buf));
76 switch((int)((dl_info_ack_t *)buf)->dl_mac_type) {
77 case DL_ETHER :
78 *phwtype = NETWIB_DEVICE_HWTYPE_ETHER;
79 break;
80 default :
81 *phwtype = NETWIB_DEVICE_HWTYPE_UNKNOWN;
82 break;
83 }
84
85 /* obtain Ethernet address */
86 if (*phwtype == NETWIB_DEVICE_HWTYPE_ETHER) {
87 pareq.dl_primitive = DL_PHYS_ADDR_REQ;
88 pareq.dl_addr_type = DL_CURR_PHYS_ADDR;
89 netwib_eg(netwib_priv_dlpi_putmsg(fd2, &pareq, sizeof(pareq), 0));
90 netwib_eg(netwib_priv_dlpi_getmsg(fd2, DL_PHYS_ADDR_ACK_SIZE, buf));
91 pbufeth = (netwib_data)buf + ((dl_phys_addr_ack_t*)buf)->dl_addr_offset;
92 if (pbufeth[0] == 0 && pbufeth[1] == 0 && pbufeth[2] == 0 &&
93 pbufeth[3] == 0 && pbufeth[4] == 0 && pbufeth[5] == 0) {
94 *phwtype = NETWIB_DEVICE_HWTYPE_UNKNOWN;
95 } else {
96 netwib_c_memcpy(peth->b, pbufeth, NETWIB_ETH_LEN);
97 }
98 }
99
100 netwib_gotolabel:
101 close(fd2);
102 netwib_er(netwib_ptr_free(&buf));
103 fd = fd; /* for compiler warning */
104 return(ret);
105 }
106 #endif
107
108 /*-------------------------------------------------------------*/
netwib_priv_conf_devices_ioctl_dev(netwib_priv_confwork * pcw,int fd,netwib_conststring device)109 static netwib_err netwib_priv_conf_devices_ioctl_dev(netwib_priv_confwork *pcw,
110 int fd,
111 netwib_conststring device)
112 {
113 netwib_priv_confwork_devices *pcd;
114 netwib_bool pcdset;
115 netwib_err ret;
116 struct ifreq ifr;
117 int reti;
118
119 netwib_er(netwib_priv_confwork_devices_init(&pcd));
120
121 /* prepare for error handling */
122 pcdset = NETWIB_FALSE;
123 ret = NETWIB_ERR_OK;
124
125 /* set device */
126 netwib_eg(netwib_buf_append_string(device, &pcd->device));
127 pcdset = NETWIB_TRUE;
128
129 /* get hwtype */
130 netwib_eg(netwib_priv_conf_devices_ioctl_hw(fd, device, &pcd->hwtype,
131 &pcd->eth));
132
133 /* get mtu */
134 netwib_c_memset(&ifr, 0, sizeof(ifr));
135 netwib_c_strcpy(ifr.ifr_name, device);
136 ifr.ifr_addr.sa_family = AF_INET;
137 reti = ioctl(fd, SIOCGIFMTU, (char *)&ifr);
138 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
139 #if defined NETWIBDEF_SYSNAME_Solaris
140 pcd->mtu = ifr.ifr_metric;
141 #else
142 pcd->mtu = ifr.ifr_mtu;
143 #endif
144
145 /* save value */
146 netwib_eg(netwib_priv_confwork_devices_add(pcw, pcd));
147 pcdset = NETWIB_FALSE;
148
149 /* clean and leave */
150 netwib_gotolabel:
151 if (pcdset) {
152 netwib_er(netwib_priv_confwork_devices_close(&pcd));
153 }
154 return(ret);
155 }
156
157 /*-------------------------------------------------------------*/
netwib_priv_conf_devices_ioctl(netwib_priv_confwork * pcw)158 static netwib_err netwib_priv_conf_devices_ioctl(netwib_priv_confwork *pcw)
159 {
160 netwib_priv_confwork_ip *pci;
161 netwib_uint32 numif, i;
162 netwib_bool pciset;
163 netwib_err ret;
164 struct ifconf ifc;
165 struct ifreq ireqbuf[100];
166 struct ifreq ifr;
167 int fd, reti;
168
169 /* prepare for error handling */
170 pciset = NETWIB_FALSE;
171 ret = NETWIB_ERR_OK;
172
173 /* work on this socket */
174 fd = socket(AF_INET, SOCK_DGRAM, 0);
175 if (fd < 0) {
176 return(NETWIB_ERR_FUSOCKET);
177 }
178
179 #if defined NETWIBDEF_SYSNAME_Linux
180 #if defined ifr_ifindex
181 /* first obtain all devices (a device with IP address 0.0.0.0 is not
182 retrieved by SIOCGIFCONF). However, we still have to do the job in
183 SIOCGIFCONF loop, because aliases are not retrieved here.
184 This only works for kernels >= 2.1.50. For previous versions, we
185 could read /proc/net/dev (not implemented in netwib). */
186 for (i = 1; ; i++) {
187 netwib_c_memset(&ifr, 0, sizeof(ifr));
188 ifr.ifr_ifindex = i;
189 reti = ioctl(fd, SIOCGIFNAME, (char *)&ifr);
190 if (reti < 0) break;
191 netwib_eg(netwib_priv_conf_devices_ioctl_dev(pcw, fd, ifr.ifr_name));
192 }
193 #endif
194 #endif
195
196 /* store config in buffer */
197 ifc.ifc_len = sizeof(ireqbuf);
198 ifc.ifc_ifcu.ifcu_req = ireqbuf;
199 netwib_c_memset((char *)ireqbuf, 0, sizeof(ireqbuf));
200 reti = ioctl(fd, SIOCGIFCONF, (char *)&ifc);
201 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
202
203 /* loop for each device */
204 numif = ifc.ifc_len / sizeof(struct ifreq);
205 for (i = 0; i < numif; i++) {
206 /** DEVICE **/
207 netwib_eg(netwib_priv_conf_devices_ioctl_dev(pcw, fd,
208 ireqbuf[i].ifr_name));
209 /** IP **/
210 /* get flags */
211 netwib_c_memset(&ifr, 0, sizeof(ifr));
212 netwib_c_strcpy(ifr.ifr_name, ireqbuf[i].ifr_name);
213 #if defined NETWIBDEF_SYSNAME_Solaris
214 /* Solaris 8 does not support alias (elx0:1) for SIOCGIFFLAGS */
215 {
216 netwib_string pc;
217 pc = netwib_c_strchr(ifr.ifr_name, ':');
218 if (pc != NULL) {
219 *pc = '\0';
220 }
221 }
222 #endif
223 ifr.ifr_addr.sa_family = AF_INET;
224 reti = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
225 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
226 if ( ! (ifr.ifr_flags & IFF_UP) ) {
227 continue;
228 }
229 netwib_eg(netwib_priv_confwork_ip_init(&pci));
230 pciset = NETWIB_TRUE;
231 /* get ptp */
232 if (ifr.ifr_flags & IFF_POINTOPOINT) {
233 pci->ispointtopoint = NETWIB_TRUE;
234 }
235 /* get device */
236 netwib_eg(netwib_buf_append_string(ireqbuf[i].ifr_name, &pci->device));
237 /* get ip */
238 netwib_c_memset(&ifr, 0, sizeof(ifr));
239 netwib_c_strcpy(ifr.ifr_name, ireqbuf[i].ifr_name);
240 ifr.ifr_addr.sa_family = AF_INET;
241 reti = ioctl(fd, SIOCGIFADDR, (char *)&ifr);
242 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
243 netwib_eg(netwib_priv_sa_ip_init_sa((const netwib_priv_sockaddr_unalign *)&ifr.ifr_addr, &pci->ip));
244 /* get mask */
245 netwib_c_memset(&ifr, 0, sizeof(ifr));
246 netwib_c_strcpy(ifr.ifr_name, ireqbuf[i].ifr_name);
247 ifr.ifr_addr.sa_family = AF_INET;
248 reti = ioctl(fd, SIOCGIFNETMASK, (char *)&ifr);
249 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
250 netwib_eg(netwib_priv_sa_ip_init_sa((const netwib_priv_sockaddr_unalign *)&ifr.ifr_addr, &pci->mask));
251 /* get ptpip */
252 if (pci->ispointtopoint) {
253 netwib_c_memset(&ifr, 0, sizeof(ifr));
254 netwib_c_strcpy(ifr.ifr_name, ireqbuf[i].ifr_name);
255 ifr.ifr_addr.sa_family = AF_INET;
256 reti = ioctl(fd, SIOCGIFDSTADDR, (char *)&ifr);
257 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
258 netwib_eg(netwib_priv_sa_ip_init_sa((const netwib_priv_sockaddr_unalign *)&ifr.ifr_addr, &pci->pointtopointip));
259 }
260 /* save value */
261 netwib_eg(netwib_priv_confwork_ip_add(pcw, pci));
262 pciset = NETWIB_FALSE;
263 }
264
265 /* clean and leave */
266 netwib_gotolabel:
267 close(fd);
268 if (pciset) {
269 netwib_er(netwib_priv_confwork_ip_close(&pci));
270 }
271 return(ret);
272 }
273
274 /*-------------------------------------------------------------*/
275 #if defined NETWIBDEF_SYSNAME_Solaris
276 static netwib_err netwib_priv_conf_devices_ioctl6(netwib_priv_confwork *pcw);
277 #if NETWIBDEF_HAVEVAR_SIOCGLIFCONF == 1
278 /* we have to redefine this struct because system ones only work
279 on 64 bit platforms... This is an adapted copy of net/if.h.
280 Anyone knows why Sun made this stupid choice ? */
281 struct netwib_lifreq {
282 char lifr_name[LIFNAMSIZ]; /* if name, e.g. "en0" */
283 union {
284 int lifru_addrlen; /* for subnet/token etc */
285 uint_t lifru_ppa; /* SIOCSLIFNAME */
286 } lifr_lifru1;
287 /* padding because ia32 "long long"s are only 4-byte aligned. */
288 int lifr_pad0;
289 union {
290 struct sockaddr_storage lifru_addr;
291 struct sockaddr_storage lifru_dstaddr;
292 struct sockaddr_storage lifru_broadaddr;
293 struct sockaddr_storage lifru_token; /* With lifr_addrlen */
294 struct sockaddr_storage lifru_subnet; /* With lifr_addrlen */
295 int lifru_index; /* interface index */
296 uint32_t lifru_flags1; /* Flags for SIOC?LIFFLAGS */
297 uint32_t lifru_flags2; /* Flags for SIOC?LIFFLAGS */
298 int lifru_metric;
299 uint_t lifru_mtu;
300 char lifru_data[1]; /* interface dependent data */
301 char lifru_enaddr[6];
302 int lif_muxid[2]; /* mux id's for arp and ip */
303 struct lif_nd_req lifru_nd_req;
304 struct lif_ifinfo_req lifru_ifinfo_req;
305 } lifr_lifru;
306 };
307 struct netwib_lifconf {
308 sa_family_t lifc_family;
309 int lifc_flags; /* request specific interfaces */
310 int lifc_len; /* size of associated buffer */
311 union {
312 caddr_t lifcu_buf;
313 struct netwib_lifreq *lifcu_req;
314 } lifc_lifcu;
315 };
316 #define NETWIB_SIOCGLIFADDR _IOWR('i', 113, struct netwib_lifreq)
317 #define NETWIB_SIOCGLIFDSTADDR _IOWR('i', 115, struct netwib_lifreq)
318 #define NETWIB_SIOCGLIFFLAGS _IOWR('i', 117, struct netwib_lifreq)
319 #define NETWIB_SIOCGLIFMTU _IOWR('i', 122, struct netwib_lifreq)
320 #define NETWIB_SIOCGLIFNETMASK _IOWR('i', 125, struct netwib_lifreq)
321 #define NETWIB_SIOCGLIFSUBNET _IOWR('i', 138, struct netwib_lifreq)
322 /* end of copy */
netwib_priv_conf_devices_ioctl6(netwib_priv_confwork * pcw)323 static netwib_err netwib_priv_conf_devices_ioctl6(netwib_priv_confwork *pcw)
324 {
325 netwib_priv_confwork_devices *pcd;
326 netwib_priv_confwork_ip *pci;
327 netwib_uint32 numif, i;
328 netwib_bool pcdset, pciset;
329 netwib_err ret;
330 struct netwib_lifconf lifc;
331 struct netwib_lifreq lireqbuf[100];
332 struct netwib_lifreq lifr;
333 netwib_priv_sockaddr_unalign *psa;
334 int fd, reti;
335
336 /* prepare for error handling */
337 pcdset = NETWIB_FALSE;
338 pciset = NETWIB_FALSE;
339 ret = NETWIB_ERR_OK;
340
341 /* work on this socket */
342 fd = socket(AF_INET6, SOCK_DGRAM, 0);
343 if (fd < 0) {
344 return(NETWIB_ERR_FUSOCKET);
345 }
346
347 /* store config in buffer */
348 lifc.lifc_len = sizeof(lireqbuf);
349 lifc.lifc_lifcu.lifcu_req = lireqbuf;
350 lifc.lifc_family = AF_INET6;
351 netwib_c_memset((char *)lireqbuf, 0, sizeof(lireqbuf));
352 reti = ioctl(fd, SIOCGLIFCONF, (char *)&lifc);
353 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
354
355 /* loop for each device */
356 numif = lifc.lifc_len / sizeof(struct netwib_lifreq);
357 for (i = 0; i < numif; i++) {
358 /** DEVICE **/
359 netwib_eg(netwib_priv_confwork_devices_init(&pcd));
360 pcdset = NETWIB_TRUE;
361 /* get device */
362 netwib_eg(netwib_buf_append_string(lireqbuf[i].lifr_name, &pcd->device));
363 /* get hwtype */
364 netwib_eg(netwib_priv_conf_devices_ioctl_hw(fd, lireqbuf[i].lifr_name,
365 &pcd->hwtype, &pcd->eth));
366 /* get mtu */
367 netwib_c_memset(&lifr, 0, sizeof(lifr));
368 netwib_c_strcpy(lifr.lifr_name, lireqbuf[i].lifr_name);
369 lifr.lifr_lifru.lifru_addr.ss_family = AF_INET6;
370 reti = ioctl(fd, NETWIB_SIOCGLIFMTU, (char *)&lifr);
371 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
372 pcd->mtu = lifr.lifr_lifru.lifru_mtu;
373 /* save value */
374 netwib_eg(netwib_priv_confwork_devices_add(pcw, pcd));
375 pcdset = NETWIB_FALSE;
376 /** IP **/
377 /* get flags */
378 netwib_c_memset(&lifr, 0, sizeof(lifr));
379 netwib_c_strcpy(lifr.lifr_name, lireqbuf[i].lifr_name);
380 #if defined NETWIBDEF_SYSNAME_Solaris
381 /* Solaris 8 does not support alias (elx0:1) for SIOCGIFFLAGS */
382 {
383 netwib_string pc;
384 pc = netwib_c_strchr(lifr.lifr_name, ':');
385 if (pc != NULL) {
386 *pc = '\0';
387 }
388 }
389 #endif
390 lifr.lifr_lifru.lifru_addr.ss_family = AF_INET6;
391 reti = ioctl(fd, NETWIB_SIOCGLIFFLAGS, (char *)&lifr);
392 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
393 if ( ! (lifr.lifr_lifru.lifru_flags1 & IFF_UP) ) {
394 continue;
395 }
396 netwib_eg(netwib_priv_confwork_ip_init(&pci));
397 pciset = NETWIB_TRUE;
398 /* get ptp */
399 if (lifr.lifr_lifru.lifru_flags1 & IFF_POINTOPOINT) {
400 pci->ispointtopoint = NETWIB_TRUE;
401 }
402 /* get device */
403 netwib_eg(netwib_buf_append_string(lireqbuf[i].lifr_name, &pci->device));
404 /* get ip */
405 netwib_c_memset(&lifr, 0, sizeof(lifr));
406 netwib_c_strcpy(lifr.lifr_name, lireqbuf[i].lifr_name);
407 lifr.lifr_lifru.lifru_addr.ss_family = AF_INET6;
408 reti = ioctl(fd, NETWIB_SIOCGLIFADDR, (char *)&lifr);
409 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
410 psa = (netwib_priv_sockaddr_unalign*)&lifr.lifr_lifru.lifru_addr;
411 netwib_eg(netwib_priv_sa_ip_init_sa(psa, &pci->ip));
412 /* get prefix */
413 netwib_c_memset(&lifr, 0, sizeof(lifr));
414 netwib_c_strcpy(lifr.lifr_name, lireqbuf[i].lifr_name);
415 lifr.lifr_lifru.lifru_addr.ss_family = AF_INET6;
416 reti = ioctl(fd, NETWIB_SIOCGLIFNETMASK, (char *)&lifr);
417 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
418 psa = (netwib_priv_sockaddr_unalign*)&lifr.lifr_lifru.lifru_addr;
419 netwib_eg(netwib_priv_ip_maskprefix_init_sa(psa, NULL, &pci->prefix));
420 /* get ptpip */
421 if (pci->ispointtopoint) {
422 netwib_c_memset(&lifr, 0, sizeof(lifr));
423 netwib_c_strcpy(lifr.lifr_name, lireqbuf[i].lifr_name);
424 lifr.lifr_lifru.lifru_addr.ss_family = AF_INET6;
425 reti = ioctl(fd, NETWIB_SIOCGLIFDSTADDR, (char *)&lifr);
426 netwib_ig(reti, NETWIB_ERR_FUIOCTL);
427 psa = (netwib_priv_sockaddr_unalign*)&lifr.lifr_lifru.lifru_addr;
428 netwib_eg(netwib_priv_sa_ip_init_sa(psa, &pci->pointtopointip));
429 }
430 /* save value */
431 netwib_eg(netwib_priv_confwork_ip_add(pcw, pci));
432 pciset = NETWIB_FALSE;
433 }
434
435 /* clean and leave */
436 netwib_gotolabel:
437 close(fd);
438 if (pcdset) {
439 netwib_er(netwib_priv_confwork_devices_close(&pcd));
440 }
441 if (pciset) {
442 netwib_er(netwib_priv_confwork_ip_close(&pci));
443 }
444 return(ret);
445 }
446 #else
netwib_priv_conf_devices_ioctl6(netwib_priv_confwork * pcw)447 static netwib_err netwib_priv_conf_devices_ioctl6(netwib_priv_confwork *pcw)
448 {
449 pcw = pcw; /* for compiler warning */
450 return(NETWIB_ERR_OK);
451 }
452 #endif
453 #endif
454
455
456