LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (http://www.linuxquestions.org/questions/linux-networking-3/)
-   -   Program to assign globa lIPv6 address and bind() to the previously assigned address. (http://www.linuxquestions.org/questions/linux-networking-3/program-to-assign-globa-lipv6-address-and-bind-to-the-previously-assigned-address-803903/)

mwnn 04-24-2010 02:53 AM

Program to assign globa lIPv6 address and bind() to the previously assigned address.
 
Consider the following program:
Code:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>

#define IPV6_BINARY_LEN 128

int32_t set_ip_addr(const char *dev, const char *ip, int32_t prefix_len);

int main(int argc, char *argv[])
{
        struct sockaddr_in6 sa;
        int32_t sd;
        int32_t local_errno;
        int32_t one = 1;
        int32_t ret;

        if (argc != 4) {
                fprintf(stderr, "Usage: %s <dev> <ip address> <prefix Length>.\n",
                        argv[0]);
                goto out1;
        }

        ret = set_ip_addr(argv[1], argv[2], atoi(argv[3]));
        if (ret == -1) {
                fprintf(stderr, "Unable to set IP address.\n");
                goto out1;
        }

        sd = socket(AF_INET6, SOCK_DGRAM, 0);
        if (sd == -1) {
                perror("socket");
                goto out1;
        }

        ret = setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (void *)&one,
                        sizeof(one));
        if (ret == -1) {
                perror("setsockopt");
                goto out1;
        }

        ret = setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one,
                        sizeof(one));
        if (ret == -1) {
                perror("setsockopt");
                goto out1;
        }

        memset(&sa, 0, sizeof(sa));
        sa.sin6_family = AF_INET6;
        sa.sin6_port = htons(4915);
        sa.sin6_scope_id = 0;
        ret = inet_pton(AF_INET6, argv[2], sa.sin6_addr.s6_addr);
        if (ret != 1) {
                perror("inet_pton");
                goto out2;
        }
#if 0
        printf("Sleeping before bind ...\n");
        sleep(30);
#endif
        ret = bind(sd, (struct sockaddr *)&sa, sizeof(sa));
        if (ret == -1) {
                local_errno = errno;
                printf("errno = %d.\n", errno);
                perror("bind");
                goto out2;
        }

        printf("Bind success!\n");

        close(sd);

        exit(0);
out2:
        close(sd);
out1:
        exit(1);
}

struct in6_ifreq {
        struct in6_addr        ifr6_addr;
        uint32_t        ifr6_prefixlen;
        int                ifr6_ifindex;
};

int32_t set_ip_addr(const char *dev, const char *ip, int32_t prefix_len)
{
        struct in6_ifreq in6_ifreq;
        struct ifreq ifreq;
        uint8_t ip_bin[IPV6_BINARY_LEN];
        int32_t sd;
        int32_t one = 1;
        int32_t ret;

        if ((dev == NULL) || (ip == NULL) || (prefix_len < 0)) {
                fprintf(stderr, "%s: Invalid arguments.\n", __func__);
                goto out1;
        }

        ret = inet_pton(AF_INET6, ip, ip_bin);
        if (ret != 1) {
                perror("inet_pton");
                goto out1;
        }

        sd = socket(AF_INET6, SOCK_DGRAM, 0);
        if (sd == -1) {
                perror("socket");
                goto out1;
        }

        ret = setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&one,
                        sizeof(one));
        if (ret == -1) {
                perror("setsockopt");
                goto out1;
        }

        memset(&ifreq, 0, sizeof(ifreq));
        strncpy(ifreq.ifr_name, dev, IFNAMSIZ - 1);
        ret = ioctl(sd, SIOCGIFINDEX, &ifreq);
        if (ret == -1) {
                perror("ioctl");
                goto out2;
        }

        memset(&in6_ifreq, 0, sizeof(in6_ifreq));
        ret = inet_pton(AF_INET6, ip, &in6_ifreq.ifr6_addr.s6_addr);
        if (ret != 1) {
                perror("inet_pton");
                goto out2;
        }

        in6_ifreq.ifr6_ifindex = ifreq.ifr_ifindex;
        in6_ifreq.ifr6_prefixlen = prefix_len;

        ret = ioctl(sd, SIOCSIFADDR, &in6_ifreq);
        if (ret == -1) {
                perror("ioctl");
                goto out2;
        }

        return 0;

out2:
        close(sd);
out1:
        return -1;
}

The program can be executed as shown below:
Code:

# ./set_ip_and_bind eth0 2001:0db8:0:f101::1 64
The bind() call fails with errno 99 (Cannot assign requested address).
If the sleep(30) is enabled the bind() call executes successfully.

mwnn 04-25-2010 12:11 AM

In Linux-2.6.33, the function ipv6_add_addr() in addrconf.c sets ifa->flags to IFA_F_TENTATIVE. This is set to IFA_F_PERMANENT only after "Duplicate Address Detection" procedure is completed successfully. In the above listed program, bind() is being called immediately after assigning the IP address. Hence the inet6_bind() in af_inet6.c fails since ifa->flags is still set to IFA_F_TENTATIVE. This issue can probably be resolved by using the IFA_F_NODAD flag (which disables "Duplicate address detection" procedure). So the question is, how do I pass this flag from userspace to the kernel?

lprasanna 10-07-2010 03:29 AM

bind fails with 99 after SIOCSIFADDR ioctl
 
Hi all,

Did u find any solution for the problem??

I am also seeing the same issue...
Even if i keep a sleep also, i am unable to bind with 99 error.

I am using Fedora 2.6.28.9-x86_64 kernel.

Any help will be appreciated...

thanks,
Lakshmi


All times are GMT -5. The time now is 10:57 PM.