android dhcp

参考文档:http://www.ietf.org/rfc/rfc2132.txt

http://download.csdn.net/detail/new_abc/4520361这里有一个介绍dhcp的文档,比较详细

看一下dhcp的过程:


Android DHCP客户端的代码在system\core\libnetutils目录下

int do_dhcp(char *iname)
{
    if (ifc_set_addr(iname, 0)) {
        printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
        return -1;
    }

    if (ifc_up(iname)) {
        printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
        return -1;
    }
	sleep(2);
    return dhcp_init_ifc(iname);
}

这里的iname是网口名,如“eth0",ifc_set_addr设置一个全局socket的地址为传下来的网口名字,ifc_up设置网口标志为启动状态。然后主要的工作在dhcp_init_ifc:

int dhcp_init_ifc(const char *ifname)
{
    dhcp_msg discover_msg;
    dhcp_msg request_msg;
    dhcp_msg reply;
    dhcp_msg *msg;
    dhcp_info info;
    int s, r, size;
    int valid_reply;
    uint32_t xid,last,now;
    unsigned char hwaddr[6];
    struct pollfd pfd;
    unsigned int state;
    unsigned int timeout;
    int if_index;
	
    xid = (uint32_t) get_msecs();
    last = (uint32_t) get_msecs();
	
    if (ifc_get_hwaddr(ifname, hwaddr)) { //获取mac地址
        return fatal("cannot obtain interface address");
    }
	
    if (ifc_get_ifindex(ifname, &if_index)) {
        return fatal("cannot obtain interface index");
    }
	
    s = open_raw_socket(ifname, hwaddr, if_index);

    timeout = TIMEOUT_INITIAL;
    state = STATE_SELECTING;
    info.type = 0;
    goto transmit;

    for (;;) {
        pfd.fd = s;
        pfd.events = POLLIN;
        pfd.revents = 0;
	now = (uint32_t) get_msecs();
	if (now > (last + TIMEOUT_INITIAL))
		goto transmit;
	//	LOGD("lijj timeout = %d", timeout);
        r = poll(&pfd, 1, timeout);
        if (r == 0) {
#if VERBOSE
            printerr("TIMEOUT\n");
#endif
            if (timeout >= TIMEOUT_MAX) {
                printerr("timed out\n");
                if ( info.type == DHCPOFFER ) {
                    printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
                    return ifc_configure(ifname, &info);
                }
                errno = ETIME;
                close(s);
                return -1;
            }
            timeout = timeout * 2;

        transmit:
            size = 0;
            msg = NULL;
            switch(state) {
            case STATE_SELECTING:
                msg = &discover_msg;
                size = init_dhcp_discover_msg(msg, hwaddr, xid);//构建dhcp DISCOVER消息
                break;
            case STATE_REQUESTING:
                msg = &request_msg;
                size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);//构建请求消息
                break;
            default:
                r = 0;
            }
            if (size != 0) {
                r = send_message(s, if_index, msg, size);//发送消息
                if (r < 0) {
                    printerr("error sending dhcp msg: %s\n", strerror(errno));
                }
    		last = (uint32_t) get_msecs();
            }
            continue;
        }

        if (r < 0) {
            if ((errno == EAGAIN) || (errno == EINTR)) {
                continue;
            }
            return fatal("poll failed");
        }

        errno = 0;
        r = receive_packet(s, &reply);
        if (r < 0) {
            if (errno != 0) {
                LOGD("receive_packet failed (%d): %s", r, strerror(errno));
                if (errno == ENETDOWN || errno == ENXIO) {
                    return -1;
                }
            }
            continue;
        }

#if VERBOSE > 1
        dump_dhcp_msg(&reply, r);
#endif
        decode_dhcp_msg(&reply, r, &info);//解析返回的dhcp消息

        if (state == STATE_SELECTING) {
            valid_reply = is_valid_reply(&discover_msg, &reply, r);
        } else {
            valid_reply = is_valid_reply(&request_msg, &reply, r);
        }
        if (!valid_reply) {
            printerr("invalid reply\n");
            continue;
        }

        if (verbose) dump_dhcp_info(&info);

        switch(state) {
        case STATE_SELECTING:
            if (info.type == DHCPOFFER) {
                state = STATE_REQUESTING;
                timeout = TIMEOUT_INITIAL;
                xid++;
                goto transmit;
            }
            break;
        case STATE_REQUESTING:
            if (info.type == DHCPACK) {
                printerr("configuring %s\n", ifname);
                close(s);
                return ifc_configure(ifname, &info);
            } else if (info.type == DHCPNAK) {//不能向客户提供这个网络地址或参数
                printerr("configuration request denied\n");
                close(s);
                return -1;
            } else {
                printerr("ignoring %s message in state %d\n",
                         dhcp_type_to_name(info.type), state);
            }
            break;
        }
    }
    close(s);
    return 0;
}

这里大概过程是:

1、进行一些初始化后转到goto transmit;

2、此时state为STATE_SELECTING,所以初始化discover消息,接着调用send_message发送discover消息,然后回到for循环,阻塞在下一次poll,直到超时,如果中间一直未收到回应,则不停的发discover消息,收到回应消息则r>0;

3、调用receive_packet接收消息

4、decode_dhcp_msg解析消息,相应的信息保存在dhcp_info结构中

5、判断回应的消息是否为DHCPOFFER,是则将状态改为STATE_REQUESTING,跳转到transmit

6、发送REQUESTING消息,然后阻塞,等待回应

7、接收消息,decode_dhcp_msg解析消息,相应的信息保存在dhcp_info结构中

8、判断回应的消息是否为DHCPNAK,是则关闭套接字,调用ifc_configure设置相应地址信息,如果消息为DHCPNAK,则说明服务器不能向客户提供这个网络地址或参数,返回 error


基本的消息处理流程就是这样,再来看一下构建discover消息

int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
{
    uint8_t *x;

    x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);

    *x++ = OPT_PARAMETER_LIST;//由n个option组成
    *x++ = 4;
    *x++ = OPT_SUBNET_MASK;
    *x++ = OPT_GATEWAY;
    *x++ = OPT_DNS;
    *x++ = OPT_BROADCAST_ADDR;

    *x++ = OPT_END;

    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
}

static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
{
    uint8_t *x;

    memset(msg, 0, sizeof(dhcp_msg));

    msg->op = OP_BOOTREQUEST;
    msg->htype = HTYPE_ETHER;
    msg->hlen = 6;
    msg->hops = 0;

    msg->flags = 0; // htons(FLAGS_BROADCAST);

    msg->xid = xid;

    memcpy(msg->chaddr, hwaddr, 6);

    x = msg->options;

    *x++ = OPT_COOKIE1;//起标识作用,标识这是一个dhcp消息
    *x++ = OPT_COOKIE2;
    *x++ = OPT_COOKIE3;
    *x++ = OPT_COOKIE4;

    *x++ = OPT_MESSAGE_TYPE; //DHCP协议交互的控制报文类型
    *x++ = 1;					//DHCP Discover
    *x++ = type;

    return x;
}

这里比较简单,构建request消息也是一样的

我们可以在discover或者request消息中添加自己的option,让dhcp服务器收到后进行相应的解析

如在discover消息中:

int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
{
    uint8_t *x;
	int length;
    x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);

    *x++ = OPT_PARAMETER_LIST;//由n个option组成
    *x++ = 4;
    *x++ = OPT_SUBNET_MASK;
    *x++ = OPT_GATEWAY;
    *x++ = OPT_DNS;
    *x++ = OPT_BROADCAST_ADDR;
#ifdef TEST_DHCP
    /*****************************
		标识  长度  数据
    *****************************/
	
    length = strlen("THIS is a Test");
    *x++ = 188;
    *x++ = length;
    memcpy(x,"THIS is a Test",length);
    x += length;
#endif
    *x++ = OPT_END;

    return DHCP_MSG_FIXED_SIZE + (x - msg->options);
}

我们加了一个Tag为188的选项,注意这里option的格式。然后重新编译一下dhcp,抓个包,我们可以看到

没有加时


可以看到多了一个option.


包:http://download.csdn.net/detail/new_abc/4522426


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值