source: libcf++/trunk/src/macaddr.cpp@ 4

Last change on this file since 4 was 4, checked in by cheese, 9 years ago

#1 commit prototype

File size: 8.8 KB
Line 
1/**
2 * @file macaddr.cpp
3 * @author https://kldp.org/node/26319
4 * @brief getting mac address
5 */
6#include <stdio.h>
7#include <fcntl.h>
8#include <stdlib.h>
9#include <string.h>
10#include <errno.h>
11#include <sys/types.h>
12
13#ifndef WIN32
14#include <unistd.h>
15#include <sys/poll.h>
16
17#ifndef _LINUX
18#include <sys/dlpi.h>
19#include <sys/stropts.h>
20#else
21#ifdef _HAVE_STROPTS_H
22#include <sys/stropts.h>
23#endif
24#endif
25
26#else
27# pragma comment(lib, "iphlpapi.lib")
28#include <windows.h>
29#include <lm.h>
30#include <Lmwksta.h>
31#include <assert.h>
32#include <iphlpapi.h>
33#endif
34
35#include <signal.h>
36#include <ctype.h>
37
38#ifdef _LINUX
39#include <sys/ioctl.h>
40#include <sys/types.h>
41#include <sys/socket.h>
42#include <netinet/in.h>
43#include <linux/if.h>
44#endif
45
46#ifdef _HPUX
47#include <netio.h>
48#include <sys/ioctl.h>
49#endif
50
51#ifdef _AIX
52#include <sys/ndd_var.h>
53#include <sys/kinfo.h>
54
55/* in C++, 'getkerninfo()' function is not declared automatically. */
56extern "C" int getkerninfo (int, char *, int *, int32long64_t);
57#endif
58
59#ifdef _SOLARIS
60#define BSD_COMP
61#include <sys/types.h>
62#include <sys/ioctl.h>
63#include <sys/socket.h>
64#include <sys/utsname.h>
65#include <netinet/in.h>
66#include <netdb.h>
67#include <net/if_arp.h>
68#include <net/if.h>
69#include <net/if_dl.h>
70#include <net/if_types.h>
71#include <arpa/inet.h>
72#include <stropts.h>
73#endif
74
75#ifndef WIN32
76
77#undef DLPI_DEV
78
79#ifdef HPUX
80static const char *dlpi_dev[] = {"/dev/dlpi", ""};
81#define DLPI_DEV
82#endif
83
84#ifdef AIX
85static const char *dlpi_dev[] = {"/dev/dlpi/et", "/dev/dlpi/en",
86"/dev/dlpi/tr", "/dev/dlpi/fddi", ""};
87#define DLPI_DEV
88/* AIX: remember to set up /etc/pse.conf or /etc/dlpi.conf */
89#endif
90
91#ifdef SunOS
92static const char *dlpi_dev[] = {"/dev/hme", "/dev/ie", "/dev/le", "/dev/eri"};
93#define DLPI_DEV
94#endif
95
96#if !defined(DLPI_DEV) && !defined(_LINUX)
97static const char *dlpi_dev[] = {"/dev/dlpi", ""};
98/* unknown OS - hope that this will work ??? */
99#define DLPI_DEV
100#endif
101
102/**********************************************************************/
103/*
104* implementation
105*/
106
107#define INSAP 22
108#define OUTSAP 24
109
110#include <sys/types.h>
111#include <fcntl.h>
112#include <errno.h>
113#include <stdio.h>
114#include <string.h>
115#include <signal.h>
116#include <ctype.h>
117
118#define bcopy(source, destination, length) memcpy(destination, source, length)
119
120#define AREA_SZ 5000 /*­=­* buffer length in bytes *­=­*/
121#define GOT_CTRL 1
122#define GOT_DATA 2
123#define GOT_BOTH 3
124#define GOT_INTR 4
125#define GOT_ERR 128
126
127#ifndef _LINUX
128static u_long ctl_area[AREA_SZ];
129static u_long dat_area[AREA_SZ];
130static struct strbuf ctl = {AREA_SZ, 0, (char *)ctl_area};
131static struct strbuf dat = {AREA_SZ, 0, (char *)dat_area};
132
133/*­=­* get a message from a stream; return type of message *­=­*/
134static int GetMsg (int fd)
135{
136 int flags = 0;
137 int res, ret;
138 ctl_area[0] = 0;
139 dat_area[0] = 0;
140 ret = 0;
141 res = getmsg(fd, &ctl, &dat, &flags);
142 if(res < 0) {
143 if(errno == EINTR) {
144 return(GOT_INTR);
145 } else {
146 return(GOT_ERR);
147 }
148 }
149 if(ctl.len > 0) {
150 ret |= GOT_CTRL;
151 }
152 if(dat.len > 0) {
153 ret |= GOT_DATA;
154 } return(ret);
155}
156
157/*­=­* verify that dl_primitive in ctl_area = prim *­=­*/
158static int CheckCtrl (unsigned int prim)
159{
160 dl_error_ack_t *err_ack = (dl_error_ack_t *)ctl_area;
161 if(err_ack->dl_primitive != prim) {
162 return GOT_ERR;
163 } return 0;
164}
165
166/*­=­* put a control message on a stream *­=­*/
167static int PutCtrl (int fd, int len, int pri)
168{
169 ctl.len = len;
170 if(putmsg(fd, &ctl, 0, pri) < 0) {
171 return GOT_ERR;
172 } return 0;
173}
174
175/*­=­* put a control + data message on a stream *­=­*/
176static int PutBoth (int fd, int clen, int dlen, int pri)
177{
178 ctl.len = clen;
179 dat.len = dlen;
180 if(putmsg(fd, &ctl, &dat, pri) < 0) {
181 return GOT_ERR;
182 } return 0;
183}
184
185/*­=­* open file descriptor and attach *­=­*/
186static int OpenDL (const char *dev, int ppa, int *fd)
187{
188 dl_attach_req_t *attach_req = (dl_attach_req_t *)ctl_area;
189 if((*fd = open(dev, O_RDWR)) == -1) {
190 return GOT_ERR;
191 }
192 attach_req->dl_primitive = DL_ATTACH_REQ;
193 attach_req->dl_ppa = ppa;
194 PutCtrl (*fd, sizeof(dl_attach_req_t), 0);
195 GetMsg (*fd);
196 return CheckCtrl (DL_OK_ACK);
197}
198
199/*­=­* send DL_BIND_REQ *­=­*/
200static int BindDL (int fd, int sap, u_char *addr)
201{
202 dl_bind_req_t *bind_req = (dl_bind_req_t *)ctl_area;
203 dl_bind_ack_t *bind_ack = (dl_bind_ack_t *)ctl_area;
204 bind_req->dl_primitive = DL_BIND_REQ;
205 bind_req->dl_sap = sap;
206 bind_req->dl_max_conind = 1;
207 bind_req->dl_service_mode = DL_CLDLS;
208 bind_req->dl_conn_mgmt = 0;
209 bind_req->dl_xidtest_flg = 0;
210 PutCtrl (fd, sizeof(dl_bind_req_t), 0);
211 GetMsg (fd);
212 if (GOT_ERR == CheckCtrl (DL_BIND_ACK)) {
213 return GOT_ERR;
214 }
215 bcopy((u_char *)bind_ack + bind_ack->dl_addr_offset, addr,
216 bind_ack->dl_addr_length);
217 return 0;
218}
219
220/**********************************************************************/
221/*
222* interface:
223* function DLPI - get the mac address of the "first" interface
224*
225* parameter: addr: an array of six bytes, has to be allocated by the
226caller
227*
228* return: 0 if OK, -1 if the address could not be determined
229*
230*/
231
232static long DLPI ( char *addr)
233{
234 int fd;
235 int ppa;
236 u_char mac_addr[25];
237
238 const char **dev;
239
240 for (dev = dlpi_dev; **dev != '\0'; ++dev) {
241 for (ppa=0; ppa<10; ++ppa) {
242 if (GOT_ERR != OpenDL (*dev, ppa, &fd)) {
243 if (GOT_ERR != BindDL (fd, INSAP, mac_addr)) {
244 bcopy( mac_addr, addr, 6);
245 return 0;
246 }
247 }
248 close(fd);
249 }
250 } return -1;
251}
252#endif //#ifndef _LINUX
253
254
255#endif //#ifndef WIN32
256
257
258long GetMACAddress (char *addr)
259{
260
261#ifdef WIN32
262
263 IP_ADAPTER_INFO AdapterInfo[16]; // Allocate information
264 // for up to 16 NICs
265 DWORD dwBufLen = sizeof(AdapterInfo); // Save memory size of buffer
266 PIP_ADAPTER_INFO pAdapterInfo;
267
268 DWORD dwStatus = GetAdaptersInfo( // Call GetAdapterInfo
269 AdapterInfo, // [out] buffer to receive data
270 &dwBufLen); // [in] size of receive data buffer
271 assert(dwStatus == ERROR_SUCCESS); // Verify return value is
272 // valid, no buffer overflow
273
274 pAdapterInfo = AdapterInfo; // Contains pointer to
275 // current adapter info
276 do {
277 // PrintMACaddress(pAdapterInfo->Address); // Print MAC address
278/*
279 fprintf( stderr, "%02X %02X %02X %02X %02X %02X\n",
280 pAdapterInfo->Address[0],
281 pAdapterInfo->Address[1],
282 pAdapterInfo->Address[2],
283 pAdapterInfo->Address[3],
284 pAdapterInfo->Address[4],
285 pAdapterInfo->Address[5]
286 ); // Print MAC address
287*/
288 memcpy (addr, pAdapterInfo->Address, 6);
289 if( addr[0] != '\0' || addr[1] != '\0' || addr[2] != '\0' || addr[3] != '\0' || addr[4] != '\0' || addr[5] != '\0' ) break;
290
291 pAdapterInfo = pAdapterInfo->Next; // Progress through
292 // linked list
293 }
294 while(pAdapterInfo); // Terminate if last adapter
295
296
297 return 0;
298
299#else
300
301 /* implementation for Linux */
302#ifdef _LINUX
303 struct ifreq ifr;
304 struct ifreq *IFR;
305 struct ifconf ifc;
306 char buf[1024];
307 int s, i;
308 int ok = 0;
309
310 s = socket(AF_INET, SOCK_DGRAM, 0);
311 if (s==-1) {
312 return -1;
313 }
314
315 ifc.ifc_len = sizeof(buf);
316 ifc.ifc_buf = buf;
317 ioctl(s, SIOCGIFCONF, &ifc);
318
319 IFR = ifc.ifc_req;
320 for (i = ifc.ifc_len / (int)sizeof(struct ifreq); --i >= 0; IFR++) {
321
322 strcpy(ifr.ifr_name, IFR->ifr_name);
323 if (ioctl(s, SIOCGIFFLAGS, &ifr) == 0) {
324 if (! (ifr.ifr_flags & IFF_LOOPBACK)) {
325 if (ioctl(s, SIOCGIFHWADDR, &ifr) == 0) {
326 ok = 1;
327 break;
328 }
329 }
330 }
331 }
332
333 close(s);
334 if (ok) {
335 bcopy( ifr.ifr_hwaddr.sa_data, addr, 6);
336 }
337 else {
338 return -1;
339 }
340 return 0;
341#else
342
343 /* implementation for HP-UX */
344#ifdef _HPUX
345 return DLPI (addr);
346#endif /* HPUX */
347
348
349 /* implementation for AIX */
350#ifdef _AIX
351
352 int size;
353 struct kinfo_ndd *nddp;
354
355 size = getkerninfo(KINFO_NDD, 0, 0, 0);
356 if (size <= 0) {
357 goto DLPI;
358 }
359 nddp = (struct kinfo_ndd *)malloc(size);
360
361 if (!nddp) {
362 goto DLPI;
363 }
364 if (getkerninfo(KINFO_NDD, (char *)nddp, &size, 0) < 0) {
365 free(nddp);
366 goto DLPI;
367 }
368 bcopy(nddp->ndd_addr, addr, 6);
369 free(nddp);
370 return 0;
371#endif
372
373#ifdef _SOLARIS
374 int sockfd;
375 struct arpreq myarp;
376 struct sockaddr_in *sin;
377 struct utsname myname;
378 struct hostent *hp;
379
380 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
381 if (sockfd == -1)
382 goto DLPI;
383
384 if (uname(&myname) < 0)
385 goto DLPI;
386
387 if ((hp = gethostbyname(myname.nodename)) == NULL)
388 goto DLPI;
389
390 sin = (struct sockaddr_in *) &myarp.arp_pa;
391 memset (sin, 0x00, sizeof(struct sockaddr_in));
392 memcpy (&sin->sin_addr, *hp->h_addr_list, sizeof(struct in_addr));
393
394 if (ioctl(sockfd, SIOCGARP, &myarp) != 0)
395 goto DLPI;
396
397 memcpy (addr, myarp.arp_ha.sa_data, 6);
398 return 0;
399#endif
400
401
402DLPI:
403 return DLPI (addr);
404#endif //#ifdef _LINUX
405
406
407#endif //#ifdef WIN32
408}
409
410/***********************************************************************/
411/*
412 * Main (only for testing)
413 */
414#ifdef _MAC_TEST
415int main( int argc, char **argv)
416{
417 long stat;
418 int i;
419 u_char addr[8] = {0,};
420
421 stat = GetMacAddress (addr);
422 if (0 == stat) {
423 printf( "MAC address = ");
424 for (i=0; i<6; ++i) {
425 printf("%2.2x", addr[i]);
426 }
427 printf( "\n");
428 }
429 else {
430 fprintf( stderr, "can't get MAC address\n");
431 exit( 1);
432 }
433 return 0;
434}
435#endif
Note: See TracBrowser for help on using the repository browser.