2017-12-19 4 views
0

VLAN 인터페이스의 속성을 만들고 설정하는 코드를 작성했습니다. IP 주소를 설정할 수 있지만 게이트웨이 주소를 설정하고 장치 플래그를 읽는 데 문제가 있습니다. 코드를보고 잘못된 것이 무엇인지 제안하십시오.IOCTL 반환 해당 장치 없음

generic_ioctrlcall 함수에서 오류가 발생합니다.

/** 
* Create socket function 
*/ 
int create_socket() 
{ 

    int sockfd = 0; 

    sockfd = socket(AF_INET, SOCK_DGRAM, 0); 
    if(sockfd == -1){ 
    fprintf(stderr, "Could not get socket.\n"); 
    return -1; 
    } 

    return sockfd; 

} 

/** 
* Generic ioctrlcall to reduce code size 
*/ 
int generic_ioctrlcall(int sockfd, u_long *flags, struct ifreq *ifr) { 

    if (ioctl(sockfd, (long unsigned int)flags, &ifr) < 0) { 
    fprintf(stderr, "ioctl: %s\n", (char *)flags); 
    return -1; 
    } 
    return 1; 
} 

/** 
* Set route with metric 100 
*/ 
int set_route(int sockfd, char *gateway_addr, struct sockaddr_in *addr) { 

    struct rtentry route; 
    int err = 0; 
    memset(&route, 0, sizeof(route)); 
    addr = (struct sockaddr_in*) &route.rt_gateway; 
    addr->sin_family = AF_INET; 
    addr->sin_addr.s_addr = inet_addr(gateway_addr); 
    addr = (struct sockaddr_in*) &route.rt_dst; 
    addr->sin_family = AF_INET; 
    addr->sin_addr.s_addr = inet_addr("0.0.0.0"); 
    addr = (struct sockaddr_in*) &route.rt_genmask; 
    addr->sin_family = AF_INET; 
    addr->sin_addr.s_addr = inet_addr("0.0.0.0"); 
    route.rt_flags = RTF_UP | RTF_GATEWAY; 
    route.rt_metric = 100; 

    if ((err = ioctl(sockfd, SIOCADDRT, &route)) < 0) { 
    fprintf(stderr, "ioctl: %s\n", (char *)flags); 
    return -1; 
    } 
    return 1; 

} 

/** 
* Set ip function 
*/ 
int set_ip(char *iface_name, char *ip_addr, char *gateway_addr) 
{ 
    if(!iface_name) 
    return -1; 

    struct ifreq ifr; 
    struct sockaddr_in sin; 
    int sockfd = create_socket(); 

    sin.sin_family = AF_INET; 

    // Convert IP from numbers and dots to binary notation 
    inet_aton(ip_addr,&sin.sin_addr.s_addr); 

    /* get interface name */ 
    strncpy(ifr.ifr_name, iface_name, IFNAMSIZ); 

    /* Read interface flags */ 
    generic_ioctrlcall(sockfd, (u_long *)"SIOCGIFFLAGS", &ifr); 

    /* 
    * Expected in <net/if.h> according to 
    * "UNIX Network Programming". 
    */ 
    #ifdef ifr_flags 
    # define IRFFLAGS  ifr_flags 
    #else /* Present on kFreeBSD */ 
    # define IRFFLAGS  ifr_flagshigh 
    #endif 

    // If interface is down, bring it up 
    if (ifr.IRFFLAGS | ~(IFF_UP)) { 
    ifr.IRFFLAGS |= IFF_UP; 
    generic_ioctrlcall(sockfd, (u_long *)"SIOCSIFFLAGS", &ifr); 
    } 

    // Set route 
    set_route(sockfd, gateway_addr, &sin); 

    memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr)); 

    // Set interface address 
    if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { 
    fprintf(stderr, "Cannot set IP address. "); 
    perror(ifr.ifr_name); 
    return -1; 
    }    
    #undef IRFFLAGS 

    return 0; 
} 
+0

오류가 발생하면 다른 시스템 호출보다 먼저 'perrot()'을 호출해야합니다. 그렇지 않으면 여기에서와 같이 올바른 메시지를받지 못합니다. – EJP

답변

0

여기에는 많은 문제가 있습니다. 가장 근본적인 원인은 ioctl의 두 번째 인수가 문자열에 대한 포인터가 아닌 긴 정수라는 것입니다.

generic_ioctrlcall(sockfd, (u_long *)"SIOCGIFFLAGS", &ifr); 

의 정수 값에 대한 포인터는 예상 한대로 생성되지 않습니다. 기타 문제 :

(1) ioctl은 두 번째 인수로 긴 정수를 사용하므로 왜 정수를 가리키는 포인터를 전달하려고 했습니까? 정수를 인수로 전달하십시오.

(2) 정수에 대한 포인터를 전달하는 소원을 경우, 당신은 같은 것을 할 필요가있을 것이다 :

u_long ioctl_arg = SIOCGIFFLAGS; 
generic_ioctrlcall(sockfd, &ioctl_arg, &ifr); 

(3) 당신은 변환 할 수 없습니다 뾰족한-하기에 정수 단순히 그것을 캐스팅하여 정수. 포인터를 역 참조 할 필요가 있습니다. 즉 :

Change: 
    if (ioctl(sockfd, (long unsigned int)flags, &ifr) < 0) { 
to: 
    if (ioctl(sockfd, *flags, &ifr) < 0) { 

(4) ioctl 실패, 당신은 무엇이 잘못되었는지 파악하기 위해 (더 나은 아직하거나, 해당 텍스트 번역) 실패 후를 errno를 인쇄해야합니다

if (ioctl(sockfd, *flags, &ifr) < 0) { 
    fprintf(stderr, "ioctl: flags %ld errno %d/%s\n", *flags, errno, strerror(errno)); 

그리고 귀하의 generic_ioctl 전화 중 errno 전화가 ENODEV (해당 기기 없음) 일 가능성은 거의 없습니다. 이는 제목에서 알 수 있습니다. 유효한 ioctl 정수 인수를 형성하는 포인터 - 문자 - 문자열의 기회가 매우 희박하기 때문에 errnoEINVAL이 될 가능성이 훨씬 높습니다.

+0

나는 위에서 언급 한 모든 점을 시도했다. 하지만 여전히 같은 오류가 나타납니다. 다른 가능성? –

+0

또한 이제 set_route에서 오류가 발생합니다. 잘못된 인수 –