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