레이블이 ioctl인 게시물을 표시합니다. 모든 게시물 표시
레이블이 ioctl인 게시물을 표시합니다. 모든 게시물 표시

2008년 9월 24일 수요일

linux 에서 특정 인터페이스 카드의 상태 읽어오기

MAC 어드레스 얻는것과 마찬가지로 걍 ioctl 쓰는건데.. 역시 샘플로 만들어둔 코드 그냥 지우기 뭐해서 적어둔다. 랜선이 껴진 상태인지 판단하기 위해서 만든 코드인데 현재 내 PC 네트웍을 죽일수가 없어서 아직 테스트는 안해봤다.

내일 출근하면 랜선 뺐다 껴보고, 인터페이스 올리고 내리고 등등 하면서 플래그값 변화를 체크해보자.



#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static void show_ifr_flags(unsigned int flags);

int main()
{
/* 인터페이스 이름을 eth0 으로 고정했는데 시스템 내의
* 인터페이스들을 얻어오려면 SIOCGIFCONF 참고
*/
const char* ifname = "eth0";

struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

int s = socket(PF_INET, SOCK_STREAM, 0);
if(s<0) perror("socket failed"); /* TODO 더 나은 에러처리 */
int r = ioctl(s, SIOCGIFFLAGS, &ifr);
if(r<0) perror("ioctl failed"); /* TODO 더 나은 에러처리 */

show_ifr_flags(ifr.ifr_flags);

close(s);
}

/* 내 시스템에서 net/if.h 를 보면 이 flag 의 타입으로 unsigned short 가
* 쓰였다. 환경마다 다를것 같기도 헌데..
*/
void show_ifr_flags(unsigned int flags)
{
#define SHOW_FLAG(flag, desc) printf("%-16s = %d // %s\n", #flag, (flags&flag)!=0, desc);
SHOW_FLAG(IFF_UP, "Interface is up");
SHOW_FLAG(IFF_BROADCAST, "Broadcast address valid");
SHOW_FLAG(IFF_DEBUG, "Turn on debugging");
SHOW_FLAG(IFF_LOOPBACK, "Is a loopback net");
SHOW_FLAG(IFF_POINTOPOINT, "Interface is point-to-point link");
SHOW_FLAG(IFF_NOTRAILERS, "Avoid use of trailers");
SHOW_FLAG(IFF_RUNNING, "Resources allocated");
SHOW_FLAG(IFF_NOARP, "No address resolution protocol");
SHOW_FLAG(IFF_PROMISC, "Receive all packets");
SHOW_FLAG(IFF_ALLMULTI, "Receive all multicast packets");
SHOW_FLAG(IFF_MASTER, "Master of a load balancer");
SHOW_FLAG(IFF_SLAVE, "Slave of a load balancer");
SHOW_FLAG(IFF_MULTICAST, "Supports multicast");
SHOW_FLAG(IFF_PORTSEL, "Can set media type");
SHOW_FLAG(IFF_AUTOMEDIA, "Auto media select active");
SHOW_FLAG(IFF_DYNAMIC, "Dialup device with changing addresses");
#undef SHOW_FLAG
}


음.. 돌려보고 결과를 적어둔다.

각 상황별 결과 보기


정리하자면
랜선끼고 ifup
IFF_UP = 1 // Interface is up
IFF_RUNNING = 1 // Resources allocated

랜선끼고 ifdown
IFF_UP = 0 // Interface is up
IFF_RUNNING = 0 // Resources allocated

랜선뽑고 ifup
IFF_UP = 1 // Interface is up
IFF_RUNNING = 0 // Resources allocated

랜선뽑고 ifdown
IFF_UP = 0 // Interface is up
IFF_RUNNING = 0 // Resources allocated


linux 에서 특정 인터페이스 카드의 MAC 어드레스 읽어오기

갑자기 이런 코드가 필요해져서 짜봤다.
샘플수준의 코드



/*
eth0 인터페이스의 하드웨어 어드레스(mac) 을 찍어주는 코드

1. 인터페이스 이름은 eth0 라고 가정했다. 런타임에 알아내야 한다면
SIOCGIFCONF 등을 참고

2. 소켓하나가 필요. 다른 예제들을 보니 보통 DGRAM 으로
만드네.. STREAM 으로도 동작엔 문제가 없는듯 한데 DGRAM 이 쓰이는
이유가 뭘까

3. ifreq 구조체 만들어서 적절히 채우고

4. ioctl 콜

5. SIOCGIFHWADDR 를 요청했다면 결과는 ifreq 구조체의
ifr_hwaddr.sa_data 를 6 바이트 읽어내면 된다.
*/
#include <sys/socket.h>
#include <sys/types.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
const char* ifname = "eth0";

int s = socket(AF_INET, SOCK_DGRAM, 0);
if(s < 0) perror("socket fail"); /* TODO 에러처리 */

struct ifreq ifr;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

if(ioctl(s, SIOCGIFHWADDR, &ifr) < 0)
perror("ioctl fail"); /* TODO 에러처리 */

const unsigned char* mac = ifr.ifr_hwaddr.sa_data;
printf("%02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0],
mac[1],
mac[2],
mac[3],
mac[4],
mac[5]);

close(s);
}


음. 추가로 SIOCGIFADDR 로 ip 얻어오는 함수도 만들어봤다. ioctl 쪽은 정말 드럽다. sockaddr_in 때문에 헤더파일 몇개 추가해야 한다는것 잊지 말도록. man inet_ntoa 참고

int get_ip_address(char* ip, int iplen, const char* ifname)
{
int s;
struct ifreq ifr;
struct sockaddr_in* sin;

s = socket(AF_INET, SOCK_DGRAM, 0);
if(s<0) return -1;
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);

if(ioctl(s, SIOCGIFADDR, &ifr) < 0)
{
close(s);
return -1;
}

sin = (struct sockaddr_in*)&ifr.ifr_addr;
strncpy(ip,
inet_ntoa(sin->sin_addr),
iplen);

close(s);
return 0;
}