bootp.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:8k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12. #include <time.h>
  13. #include "global.h"
  14. #include "mbuf.h"
  15. #include "socket.h"
  16. #include "netuser.h"
  17. #include "udp.h"
  18. #include "iface.h"
  19. #include "ip.h"
  20. #include "internet.h"
  21. #include "domain.h"
  22. #include "rip.h"
  23. #include "cmdparse.h"
  24. #include "bootp.h"
  25. static int bootp_rx(struct iface *ifp,struct mbuf *bp);
  26. static void ntoh_bootp(struct mbuf **bpp,struct bootp *bootpp);
  27. static int mask2width(int32 mask);
  28. #define BOOTP_TIMEOUT 30 /* Time limit for booting       */
  29. #define BOOTP_RETRANS 5 /* The inteval between sendings */
  30. int WantBootp = 0;
  31. static int SilentStartup = 0;
  32. int
  33. dobootp(argc,argv,p)
  34. int argc;
  35. char *argv[];
  36. void *p;
  37. {
  38. struct iface *ifp = NULL;
  39. struct socket lsock, fsock;
  40. struct mbuf *bp;
  41. struct udp_cb *bootp_cb;
  42. register uint8 *cp;
  43. time_t        now, /* The current time (seconds)   */
  44.       starttime, /* The start time of sending BOOTP */
  45.       lastsendtime; /* The last time of sending BOOTP  */
  46. int i;
  47. if(argc < 2) /* default to the first interface */
  48. ifp = Ifaces;
  49. else {
  50. for(i = 1; i != argc; ++i){
  51. if((ifp = if_lookup(argv[i])) != NULL) 
  52. continue;
  53. else if(strncmp(argv[i], "silent", strlen(argv[i])) == 0)
  54. SilentStartup = 1;
  55. else if(strncmp(argv[i], "noisy", strlen(argv[i])) == 0)
  56. SilentStartup = 0;
  57. else {
  58. printf("bootp [net_name] [silent] [noisy]n");
  59. return 1;
  60. }
  61. }
  62. }
  63. if(ifp == NULL)
  64. return 0;
  65. lsock.address = ifp->addr;
  66. lsock.port = IPPORT_BOOTPC;
  67. bootp_cb = open_udp(&lsock,NULL);
  68. fsock.address = ifp->broadcast;
  69. fsock.port = IPPORT_BOOTPS;
  70.    /* Get boot starting time */
  71.    time(&starttime);
  72.    lastsendtime = 0;
  73.    /* Send the bootp request packet until a response is received or time
  74.    out */
  75.    for(;;){
  76. /* Allow bootp packets should be passed through iproute. */
  77. WantBootp = 1;
  78. /* Get the current time */
  79. time(&now);
  80. /* Stop, if time out */
  81. if(now - starttime >= BOOTP_TIMEOUT){
  82. printf("bootp: timed out, values not setn");
  83. break;
  84. }
  85. /* Don't flood the network, send in intervals */
  86. if(now - lastsendtime > BOOTP_RETRANS){
  87. if(!SilentStartup) printf("Requesting...n");
  88. /* Allocate BOOTP packet and fill it in */
  89. if((bp = alloc_mbuf(sizeof(struct bootp))) == NULL)
  90. break;
  91. cp = bp->data; /* names per the RFC: */
  92. *cp++ = BOOTREQUEST; /* op */
  93. *cp++ = ifp->iftype->type; /* htype */
  94. *cp++ = ifp->iftype->hwalen; /* hlen */
  95. *cp++ = 0; /* hops */
  96. cp = put32(cp,(int32) now); /* xid */
  97. cp = put16(cp, now - starttime);/* secs */
  98. cp = put16(cp, 0); /* unused */
  99. cp = put32(cp, ifp->addr); /* ciaddr */
  100. cp = put32(cp, 0L); /* yiaddr */
  101. cp = put32(cp, 0L); /* siaddr */
  102. cp = put32(cp, 0L); /* giaddr */
  103. memcpy(cp, ifp->hwaddr, ifp->iftype->hwalen);
  104. cp += 16; /* chaddr */
  105. memset(cp, 0, 64); /* sname */
  106. cp += 64;
  107. memset(cp, 0, 128); /* file */
  108. cp += 128;
  109. memset(cp, 0, 64); /* vend */
  110. cp += 64;
  111. bp->cnt = cp - bp->data;
  112. /* assert(bp->cnt == BOOTP_LEN) */
  113. /* Send out one BOOTP Request packet as a broadcast */
  114. send_udp(&lsock, &fsock,0,0,&bp,bp->cnt,0,0);
  115. lastsendtime = now;
  116. }
  117. /* Give other tasks a chance to run. */
  118. kwait(NULL);
  119. /* Test for and process any replies */
  120. if(recv_udp(bootp_cb, &fsock, &bp) > -1){
  121. if(bootp_rx(ifp,bp))
  122. break;
  123. } else if(Net_error != WOULDBLK){
  124. printf("bootp: Net_error %d, no values setn",
  125.  Net_error);
  126. break;
  127. }
  128.    }
  129. WantBootp = 0;
  130. del_udp(bootp_cb);
  131. return 0;
  132. }
  133. /* Process BOOTP input received from 'interface'. */
  134. static int
  135. bootp_rx(ifp,bp)
  136. struct iface *ifp;
  137. struct mbuf *bp;
  138. {
  139. int  ch;
  140. int     count;
  141. int32  gateway = 0;
  142. int32  nameserver = 0;
  143. int32  broadcast, netmask;
  144. struct route  *rp;
  145. struct bootp reply;
  146. uint8 *cp;
  147. if(len_p(bp) != sizeof(struct bootp)){
  148. free_p(&bp);
  149. return 0;
  150. }
  151. ntoh_bootp(&bp, &reply);
  152. free_p(&bp);
  153. if(reply.op != BOOTREPLY) 
  154. return 0;
  155. if(!SilentStartup)
  156. printf("Network %s configured:n", ifp->name);
  157. if(ifp->addr == 0){
  158. Ip_addr = (int) reply.yiaddr.s_addr; /* yiaddr */
  159. ifp->addr =  reply.yiaddr.s_addr; /* yiaddr */
  160. if(!SilentStartup)
  161. printf("     IP address: %sn",  
  162. inet_ntoa(ifp->addr));
  163. }
  164. /* now process the vendor-specific block, check for cookie first. */
  165. cp = reply.vend;
  166. if(get32(cp) != 0x63825363L){
  167. printf("Invalid magic cookie.n");
  168. return(0);
  169. }
  170. cp += 4;
  171. while(((ch = *cp) != BOOTP_END) && (++cp < (reply.vend + 64))) 
  172. switch(ch){
  173. case BOOTP_PAD: /* They're just padding */
  174. continue;
  175. case BOOTP_SUBNET: /* fixed length, 4 octets */
  176. cp++; /* moved past length */
  177. /* Set the netmask */
  178.          /* Remove old entry if it exists */
  179. netmask = get32(cp);
  180. cp += 4;
  181.          rp = rt_blookup(ifp->addr & ifp->netmask,mask2width(ifp->netmask));
  182.          if(rp != NULL)
  183.                  rt_drop(rp->target,rp->bits);
  184.          ifp->netmask = netmask;
  185.          rt_add(ifp->addr,mask2width(ifp->netmask),0L,ifp,0L,0L,0);
  186. if(!SilentStartup)
  187. printf("     Subnet mask: %sn", inet_ntoa(netmask));
  188. /* Set the broadcast */
  189. broadcast = ifp->addr | ~(ifp->netmask);
  190.          rp = rt_blookup(ifp->broadcast,32);
  191.          if(rp != NULL && rp->iface == ifp)
  192.                  rt_drop(ifp->broadcast,32);
  193.          ifp->broadcast = broadcast;
  194.          rt_add(ifp->broadcast,32,0L,ifp,1L,0L,1);
  195. if(!SilentStartup)
  196. printf("     Broadcast: %sn", inet_ntoa(broadcast));
  197. break;
  198. case BOOTP_HOSTNAME:
  199. count = (int) *cp;
  200. cp++;
  201. if(Hostname != NULL)
  202. free(Hostname);
  203. Hostname = mallocw(count);
  204. strncpy(Hostname, (char *)cp, count);
  205. cp += count;
  206. if(!SilentStartup)
  207. printf("     Hostname: %sn", Hostname);
  208. break;
  209. case BOOTP_DNS:
  210. count = (int) *cp;
  211. cp++;
  212. while(count){
  213. nameserver = get32(cp);
  214. add_nameserver(nameserver);
  215. if(!SilentStartup)
  216. printf("     Nameserver: %sn", inet_ntoa(nameserver));
  217. cp += 4;
  218. count -= 4;
  219. }
  220. break;
  221. case BOOTP_GATEWAY:
  222. count = (int) *cp;
  223. cp++;
  224. gateway = get32(cp);
  225. /* Add the gateway as the default */
  226. rt_add(0,0,gateway,ifp,1,0,0);
  227. if(!SilentStartup)
  228. printf("     Default gateway: %sn", inet_ntoa(gateway));
  229. cp += count;
  230. break;
  231. default: /* variable field we don't know about */
  232. count = (int) *cp;
  233. cp++;
  234. cp += count;
  235. break;
  236. }
  237. rt_add(ifp->addr,mask2width(ifp->netmask),0L,ifp,1,0,0);
  238. return(1);
  239. }
  240. static void
  241. ntoh_bootp(bpp, bootpp)
  242. struct mbuf **bpp;
  243. struct bootp *bootpp;
  244. {
  245. bootpp->op = pullchar(bpp);                  /* op */
  246. bootpp->htype = pullchar(bpp); /* htype */
  247. bootpp->hlen = pullchar(bpp); /* hlen */
  248. bootpp->hops = pullchar(bpp); /* hops */
  249. bootpp->xid = pull32(bpp); /* xid */
  250. bootpp->secs = pull16(bpp); /* secs */
  251. bootpp->unused = pull16(bpp); /* unused */
  252. bootpp->ciaddr.s_addr = pull32(bpp); /* ciaddr */
  253. bootpp->yiaddr.s_addr = pull32(bpp); /* ciaddr */
  254. bootpp->siaddr.s_addr = pull32(bpp); /* siaddr */
  255. bootpp->giaddr.s_addr = pull32(bpp); /* giaddr */
  256. pullup(bpp, bootpp->chaddr, 16); /* chaddr */
  257. pullup(bpp, bootpp->sname, 64); /* sname */
  258. pullup(bpp, bootpp->file, 128); /* file name */
  259. pullup(bpp, bootpp->vend, 64); /* vendor */
  260. }
  261. int
  262. bootp_validPacket(
  263. struct ip *ip,
  264. struct mbuf *bp
  265. ){
  266. struct udp udp;
  267. struct mbuf *bp1;
  268. /* Must be a udp packet */
  269. if(ip->protocol !=  UDP_PTCL) 
  270. return 0;
  271. /* Invalid if packet is not the right size */
  272. if(len_p(bp) != (sizeof(struct udp) + sizeof(struct bootp)))
  273. return 0;
  274. /* Invalid if not a udp bootp packet */
  275. dup_p(&bp1,bp,0,len_p(bp));
  276. ntohudp(&udp, &bp);
  277. free_p(&bp);
  278. return (udp.dest == IPPORT_BOOTPC) ? 1 : 0;
  279. }
  280. /* Given a network mask, return the number of contiguous 1-bits starting
  281.  * from the most significant bit.
  282.  */
  283. static int
  284. mask2width(mask)
  285. int32 mask;
  286. {
  287.         int width,i;
  288.         width = 0;
  289.         for(i = 31;i >= 0;i--){
  290.                 if(!(mask & (1L << i)))
  291.                         break;
  292.                 width++;
  293.         }
  294.         return width;
  295. }