gonzui


Format: Advanced Search

t2ex/t2ex_source/kernel/sysmain/src/network_sample/dhclient.cbare sourcepermlink (0.06 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T2EX Software Package
    4:  *
    5:  *    Copyright 2012 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2012/12/12.
   10:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/04.
   11:  *
   12:  *----------------------------------------------------------------------
   13:  */
   14: /*
   15:  * This software package is available for use, modification, 
   16:  * and redistribution in accordance with the terms of the attached 
   17:  * T-License 2.x.
   18:  * If you want to redistribute the source code, you need to attach 
   19:  * the T-License 2.x document.
   20:  * There's no obligation to publish the content, and no obligation 
   21:  * to disclose it to the TRON Forum if you have modified the 
   22:  * software package.
   23:  * You can also distribute the modified source code. In this case, 
   24:  * please register the modification to T-Kernel traceability service.
   25:  * People can know the history of modifications by the service, 
   26:  * and can be sure that the version you have inherited some 
   27:  * modification of a particular version or not.
   28:  *
   29:  *    http://trace.tron.org/tk/?lang=en
   30:  *    http://trace.tron.org/tk/?lang=ja
   31:  *
   32:  * As per the provisions of the T-License 2.x, TRON Forum ensures that 
   33:  * the portion of the software that is copyrighted by Ken Sakamura or 
   34:  * the TRON Forum does not infringe the copyrights of a third party.
   35:  * However, it does not make any warranty other than this.
   36:  * DISCLAIMER: TRON Forum and Ken Sakamura shall not be held
   37:  * responsible for any consequences or damages caused directly or
   38:  * indirectly by the use of this software package.
   39:  *
   40:  * The source codes in bsd_source.tar.gz in this software package are 
   41:  * derived from NetBSD or OpenBSD and not covered under T-License 2.x.
   42:  * They need to be changed or redistributed according to the 
   43:  * representation of each source header.
   44:  */
   45: 
   46: /*
   47:  *      @(#)dhclient.c
   48:  *
   49:  */
   50: 
   51: #include <t2ex/socket.h>
   52: #include <tk/tkernel.h>
   53: #include <tk/errno.h>
   54: #include <tk/devmgr.h>
   55: #include <device/netdrv.h>
   56: 
   57: #include <strings.h>
   58: 
   59: #include "dhcp.h"
   60: #include "route.h"
   61: #include "util.h"
   62: 
   63: struct dhcp_state {
   64:         uint8_t state;
   65:         const char* ifname;
   66:         int xid;
   67:         SYSTIM start_time;
   68:         size_t option_length;
   69:         char hwaddr[6];
   70:         uint32_t yiaddr;
   71:         uint32_t dhcp_server;
   72:         uint32_t mask;
   73:         uint32_t gate;
   74:         uint32_t bcaddr;
   75:         uint32_t dns[2];
   76:         char domain_name[256];
   77: };
   78: 
   79: struct dhcp_packet {
   80:         struct ether_header eth;
   81:         struct ip ip;
   82:         struct udphdr udphdr;
   83:         struct dhcp_message dhcp;
   84: } __packed;
   85: 
   86: static int init_receiver(void)
   87: {
   88:         int re;
   89:         int sd;
   90:         struct sockaddr_in s;
   91: 
   92:         sd = so_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
   93:         DEBUG_PRINT(("init_receiver: so_socket = %d(%d, %d)\n", sd, MERCD(sd), SERCD(sd)));
   94: 
   95:         bzero(&s, sizeof s);
   96:         s.sin_len = sizeof s;
   97:         s.sin_family = AF_INET;
   98:         s.sin_addr.s_addr = htonl(INADDR_ANY);
   99:         s.sin_port = htons(DHCP_CLIENT_PORT);
  100:         re = so_bind(sd, (struct sockaddr*)&s, sizeof s);
  101:         DEBUG_PRINT(("init_receiver: so_bind = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  102: 
  103:         return sd;
  104: }
  105: 
  106: static void init_state(struct dhcp_state* state, const char* ifname)
  107: {
  108:         int re;
  109: 
  110:         bzero(state, sizeof *state);
  111: 
  112:         state->state = DHCP_DISCOVER;
  113: 
  114:         state->ifname = ifname;
  115: 
  116:         // ether address
  117:         re = get_hwaddr(ifname, state->hwaddr);
  118:         DEBUG_PRINT(("init_state: get_hwaddr = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  119: 
  120:         // generate transaction ID
  121:         state->xid = net_random();
  122: 
  123:         // start time
  124:         tk_get_tim(&state->start_time);
  125: }
  126: 
  127: static int send_request(struct dhcp_state* state)
  128: {
  129:         struct dhcp_packet p;
  130:         int i = 0;
  131:         int j;
  132:         int re;
  133:         int fd;
  134:         unsigned long sum;
  135:         int udp_len;
  136:         struct ifreq ifr;
  137: 
  138:         bzero(&ifr, sizeof ifr);
  139:         strncpy(ifr.ifr_name, state->ifname, IFNAMSIZ-1);
  140: 
  141:         bzero(&p, sizeof p);
  142: 
  143:         for(j = 0; j < 6; j++) {
  144:                 p.eth.ether_dhost[j] = 0xffU;
  145:                 p.eth.ether_shost[j] = state->hwaddr[j];
  146:         }
  147:         p.eth.ether_type = htons(0x0800); // IPv4
  148: 
  149:         p.ip.ip_v = IPVERSION;
  150:         p.ip.ip_hl = sizeof p.ip >> 2;
  151:         p.ip.ip_id = state->xid;
  152:         p.ip.ip_ttl = 255;
  153:         p.ip.ip_p = IPPROTO_UDP;
  154:         p.ip.ip_dst.s_addr = htonl(INADDR_BROADCAST);
  155: 
  156:         p.udphdr.uh_sport = htons(DHCP_CLIENT_PORT);
  157:         p.udphdr.uh_dport = htons(DHCP_SERVER_PORT);
  158: 
  159:         p.dhcp.op = DHCP_BOOTREQUEST;
  160:         p.dhcp.hwtype = 1;
  161:         p.dhcp.hwlen = 6;
  162:         p.dhcp.xid = state->xid;
  163:         if ( state->state == DHCP_DISCOVER ) {
  164:                 tk_get_tim(&state->start_time);
  165:         } else {
  166:                 SYSTIM tim;
  167:                 UW time;
  168:                 tk_get_tim(&tim);
  169:                 time = (tim.lo - state->start_time.lo) / 1000;
  170:                 p.dhcp.secs = htons(time > 65535 ? 65535 : time);
  171:         }
  172:         p.dhcp.flags = htons(BROADCAST_FLAG);
  173:         p.dhcp.yiaddr = state->yiaddr;
  174:         memcpy(p.dhcp.chaddr, state->hwaddr, 6);
  175:         p.dhcp.cookie = htonl(MAGIC_COOKIE);
  176: 
  177:         p.dhcp.options[i] = DHO_MESSAGETYPE;
  178:         i++;
  179:         p.dhcp.options[i] = 1;
  180:         i++;
  181:         p.dhcp.options[i] = state->state;
  182:         i++;
  183:         if ( state->state == DHCP_REQUEST ) {
  184:                 p.dhcp.options[i] = DHO_IPADDRESS;
  185:                 i++;
  186:                 p.dhcp.options[i] = sizeof(uint32_t);
  187:                 i++;
  188:                 memcpy(&p.dhcp.options[i], &state->yiaddr, sizeof(uint32_t));
  189:                 i += sizeof(uint32_t);
  190:         }
  191:         p.dhcp.options[i] = DHO_END;
  192:         i++;
  193: 
  194:         state->option_length = i;
  195: 
  196:         udp_len = sizeof p.udphdr + offsetof(struct dhcp_message, options) + state->option_length;
  197:         p.udphdr.uh_ulen = htons(udp_len);
  198:         sum = p.ip.ip_src.s_addr & 0xffffU;
  199:         sum += (p.ip.ip_src.s_addr >> 16) & 0xffffU;
  200:         sum += p.ip.ip_dst.s_addr & 0xffffU;
  201:         sum += (p.ip.ip_dst.s_addr >> 16) & 0xffffU;
  202:         sum += htons(IPPROTO_UDP);
  203:         sum += htons(udp_len);
  204:         p.udphdr.uh_sum = checksum2((unsigned short*)&p.udphdr, udp_len, sum);
  205: 
  206:         p.ip.ip_len = htons(sizeof p.ip + udp_len);
  207:         p.ip.ip_sum = checksum((unsigned short*)&p.ip, sizeof p.ip);
  208: 
  209:         fd = so_bpfopen("/dev/bpf0", O_RDWR);
  210:         DEBUG_PRINT(("send_request: so_bpfopen = %d(%d, %d)\n", fd, MERCD(fd), SERCD(fd)));
  211:         re = so_ioctl(fd, BIOCSETIF, &ifr);
  212:         DEBUG_PRINT(("send_request: so_ioctl = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  213:         re = so_write(fd, &p, sizeof p.eth + sizeof p.ip + udp_len);
  214:         DEBUG_PRINT(("send_request: so_write = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  215:         so_close(fd);
  216: 
  217:         return re;
  218: }
  219: 
  220: static int wait_response(int server, long tmo)
  221: {
  222:         fd_set fds;
  223:         struct timeval tv;
  224:         int re;
  225: 
  226:         FD_ZERO(&fds);
  227:         FD_SET(server, &fds);
  228:         tv.tv_sec = tmo;
  229:         tv.tv_usec = 0;
  230: 
  231:         DEBUG_PRINT(("dhclient: pre-select for %d secs\n", tmo));
  232:         re = so_select(server+1, &fds, NULL, NULL, &tv);
  233:         DEBUG_PRINT(("dhclient: so_select = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  234: 
  235:         return re;
  236: }
  237: 
  238: static void get_params(struct dhcp_message* offer, struct dhcp_state* state)
  239: {
  240:         int i;
  241:         for(i = 0; offer->options[i] != DHO_END; i += offer->options[i+1] + 2) {
  242:                 switch(offer->options[i]) {
  243:                 case DHO_PAD:
  244:                         break;
  245: 
  246:                 case DHO_SUBNETMASK:
  247:                         memcpy(&state->mask, &offer->options[i+2], 4);
  248:                         break;
  249: 
  250:                 case DHO_ROUTER:
  251:                         memcpy(&state->gate, &offer->options[i+2], 4);
  252:                         break;
  253: 
  254:                 case DHO_BROADCAST:
  255:                         memcpy(&state->bcaddr, &offer->options[i+2], 4);
  256:                         break;
  257: 
  258:                 case DHO_SERVERID:
  259:                         memcpy(&state->dhcp_server, &offer->options[i+2], 4);
  260:                         break;
  261: 
  262:                 case DHO_DNSSERVER:
  263:                         memcpy(&state->dns[0], &offer->options[i+2], offer->options[i+1]);
  264:                         break;
  265: 
  266:                 case DHO_DNSDOMAIN:
  267:                         strncpy(state->domain_name, &offer->options[i+2], offer->options[i+1]);
  268:                         break;
  269:                 }
  270:         }
  271: }
  272: 
  273: static int get_response(int server, struct dhcp_state* state)
  274: {
  275:         struct dhcp_message offer;
  276:         struct sockaddr_in ssa;
  277:         socklen_t ssa_len;
  278:         int re;
  279: 
  280:         bzero(&offer, sizeof offer);
  281:         bzero(&ssa, sizeof ssa);
  282:         ssa_len = sizeof ssa;
  283: 
  284:         re = so_recvfrom(server, &offer, sizeof offer, 0, (struct sockaddr*)&ssa, &ssa_len);
  285:         DEBUG_PRINT(("dhclient: so_recvfrom = %d(%d, %d)\n", re, MERCD(re), SERCD(re)));
  286:         if ( re < 0 ) {
  287:                 return re;
  288:         }
  289:         if ( offer.xid != state->xid ) {
  290:                 return 0;
  291:         }
  292:         if ( state->state == DHCP_OFFER ) {
  293:                 state->yiaddr = offer.yiaddr;
  294:         } else {
  295:                 if ( offer.options[2] == DHCP_NAK ) {
  296:                         /*
  297:                          * Start over, returning a packet size which is too large to receive.
  298:                          */
  299:                         return INT32_MAX;
  300:                 }
  301: 
  302:                 get_params(&offer, state);
  303:         }
  304: 
  305:         return re;
  306: }
  307: 
  308: static void setup(const struct dhcp_state* state, const char* ifname)
  309: {
  310:         int i;
  311:         int re;
  312:         struct sockaddr_in sa;
  313:         struct in_addr a;
  314:         int index = so_ifnametoindex(ifname);
  315: #ifdef DEBUG
  316:         char rbuf[18];
  317: #endif
  318: 
  319:         set_ifaddr(ifname, state->yiaddr, state->mask);
  320:         a.s_addr = state->yiaddr;
  321:         DEBUG_PRINT(("%s: IP address = %s\n", ifname, inet_ntop(AF_INET, &a, rbuf, sizeof(rbuf))));
  322:         route_add(INADDR_ANY, state->gate, INADDR_ANY, index, 0);
  323: 
  324:         bzero(&sa, sizeof sa);
  325:         sa.sin_len = sizeof sa;
  326:         sa.sin_family = AF_INET;
  327:         sa.sin_addr.s_addr = INADDR_ANY;
  328:         sa.sin_port = htons(53);
  329:         re = so_resctl(SO_RES_DEL_SERVER, &sa, sizeof sa);
  330:         DEBUG_PRINT(("setup: so_resctl(%s) = %d(%d, %d)\n", "delete", re, MERCD(re), SERCD(re)));
  331: 
  332:         for(i = 0; state->dns[i] != 0 && i < 2; i++ ) {
  333:                 bzero(&sa, sizeof sa);
  334:                 sa.sin_len = sizeof sa;
  335:                 sa.sin_family = AF_INET;
  336:                 sa.sin_addr.s_addr = state->dns[i];
  337:                 sa.sin_port = htons(53);
  338:                 re = so_resctl(SO_RES_ADD_SERVER, &sa, sizeof sa);
  339:                 a.s_addr = state->dns[i];
  340:                 DEBUG_PRINT(("setup: so_resctl(%s) = %d(%d, %d)\n", inet_ntop(AF_INET, &a, rbuf, sizeof(rbuf)), re, MERCD(re), SERCD(re)));
  341:         }
  342: 
  343:         so_resctl(SO_RES_ADD_DOMAIN, (void*)state->domain_name, strlen(state->domain_name) + 1);
  344: }
  345: 
  346: int dhclient(const char* ifname)
  347: {
  348:         int re;
  349:         int receiver;
  350:         struct dhcp_state state;
  351: 
  352:         init_state(&state, ifname);
  353:         receiver = init_receiver();
  354: 
  355:         long tmo = DHCP_BASE;
  356:         while(state.state != 0) {
  357:                 switch(state.state) {
  358:                 case DHCP_DISCOVER:
  359:                 case DHCP_REQUEST:
  360:                         re = send_request(&state);
  361:                         DEBUG_PRINT(("dhclient: [REQUEST:%d] = %d(%d, %d)\n", state.state, re, MERCD(re), SERCD(re)));
  362:                         if ( re < 0 ) {
  363:                                 return re;
  364:                         }
  365:                         state.state = (state.state == DHCP_DISCOVER) ? DHCP_OFFER : DHCP_ACK;
  366:                         break;
  367: 
  368:                 case DHCP_OFFER:
  369:                 case DHCP_ACK:
  370:                         re = wait_response(receiver, tmo);
  371:                         if ( re == 0 ) {
  372:                                 DEBUG_PRINT(("dhclient: select timed out\n"));
  373:                                 // timed out
  374:                                 tmo *= 2;
  375:                                 tmo += net_random() % 3 - 1;
  376:                                 if ( tmo > DHCP_MAX ) {
  377:                                         tmo = DHCP_MAX;
  378:                                 }
  379:                                 state.state = (state.state == DHCP_OFFER) ? DHCP_DISCOVER : DHCP_REQUEST;
  380:                                 continue;
  381:                         } else if ( re < 0 ) {
  382:                                 return re;
  383:                         }
  384: 
  385:                         re = get_response(receiver, &state);
  386:                         if ( re == 0 ) {
  387:                                 // unrelated packet
  388:                                 DEBUG_PRINT(("dhclient: unrelated packet\n"));
  389:                                 continue;
  390:                         } else if ( re == INT32_MAX ) {
  391:                                 state.state = DHCP_DISCOVER;
  392:                                 continue;
  393:                         } else if ( re < 0 ) {
  394:                                 return re;
  395:                         }
  396:                         tmo = DHCP_BASE;
  397:                         state.state = (state.state == DHCP_OFFER) ? DHCP_REQUEST : 0;
  398:                         break;
  399:                 }
  400:         }
  401: 
  402:         so_close(receiver);
  403: 
  404:         setup(&state, ifname);
  405: 
  406:         return 0;
  407: }