]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/nfsclient/bootp_subr.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / nfsclient / bootp_subr.c
1 /*-
2  * Copyright (c) 1995 Gordon Ross, Adam Glass
3  * Copyright (c) 1992 Regents of the University of California.
4  * All rights reserved.
5  *
6  * This software was developed by the Computer Systems Engineering group
7  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
8  * contributed to Berkeley.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Lawrence Berkeley Laboratory and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * based on:
39  *      nfs/krpc_subr.c
40  *      $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
41  */
42
43 #include <sys/cdefs.h>
44 __FBSDID("$FreeBSD$");
45
46 #include "opt_bootp.h"
47
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/sockio.h>
52 #include <sys/malloc.h>
53 #include <sys/mount.h>
54 #include <sys/mbuf.h>
55 #include <sys/proc.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <sys/sysctl.h>
59 #include <sys/uio.h>
60
61 #include <net/if.h>
62 #include <net/route.h>
63
64 #include <netinet/in.h>
65 #include <net/if_types.h>
66 #include <net/if_dl.h>
67
68 #include <rpc/rpcclnt.h>
69
70 #include <nfs/rpcv2.h>
71 #include <nfs/nfsproto.h>
72 #include <nfsclient/nfs.h>
73 #include <nfsclient/nfsdiskless.h>
74 #include <nfsclient/krpc.h>
75 #include <nfs/xdr_subs.h>
76
77
78 #define BOOTP_MIN_LEN           300     /* Minimum size of bootp udp packet */
79
80 #ifndef BOOTP_SETTLE_DELAY
81 #define BOOTP_SETTLE_DELAY 3
82 #endif
83
84 /*
85  * What is the longest we will wait before re-sending a request?
86  * Note this is also the frequency of "RPC timeout" messages.
87  * The re-send loop count sup linearly to this maximum, so the
88  * first complaint will happen after (1+2+3+4+5)=15 seconds.
89  */
90 #define MAX_RESEND_DELAY 5      /* seconds */
91
92 /* Definitions from RFC951 */
93 struct bootp_packet {
94         u_int8_t op;
95         u_int8_t htype;
96         u_int8_t hlen;
97         u_int8_t hops;
98         u_int32_t xid;
99         u_int16_t secs;
100         u_int16_t flags;
101         struct in_addr ciaddr;
102         struct in_addr yiaddr;
103         struct in_addr siaddr;
104         struct in_addr giaddr;
105         unsigned char chaddr[16];
106         char sname[64];
107         char file[128];
108         unsigned char vend[1222];
109 };
110
111 struct bootpc_ifcontext {
112         struct bootpc_ifcontext *next;
113         struct bootp_packet call;
114         struct bootp_packet reply;
115         int replylen;
116         int overload;
117         struct socket *so;
118         struct ifreq ireq;
119         struct ifnet *ifp;
120         struct sockaddr_dl *sdl;
121         struct sockaddr_in myaddr;
122         struct sockaddr_in netmask;
123         struct sockaddr_in gw;
124         struct sockaddr_in broadcast;   /* Different for each interface */
125         int gotgw;
126         int gotnetmask;
127         int gotrootpath;
128         int outstanding;
129         int sentmsg;
130         u_int32_t xid;
131         enum {
132                 IF_BOOTP_UNRESOLVED,
133                 IF_BOOTP_RESOLVED,
134                 IF_BOOTP_FAILED,
135                 IF_DHCP_UNRESOLVED,
136                 IF_DHCP_OFFERED,
137                 IF_DHCP_RESOLVED,
138                 IF_DHCP_FAILED,
139         } state;
140         int dhcpquerytype;              /* dhcp type sent */
141         struct in_addr dhcpserver;
142         int gotdhcpserver;
143 };
144
145 #define TAG_MAXLEN 1024
146 struct bootpc_tagcontext {
147         char buf[TAG_MAXLEN + 1];
148         int overload;
149         int badopt;
150         int badtag;
151         int foundopt;
152         int taglen;
153 };
154
155 struct bootpc_globalcontext {
156         struct bootpc_ifcontext *interfaces;
157         struct bootpc_ifcontext *lastinterface;
158         u_int32_t xid;
159         int gotrootpath;
160         int gotgw;
161         int ifnum;
162         int secs;
163         int starttime;
164         struct bootp_packet reply;
165         int replylen;
166         struct bootpc_ifcontext *setrootfs;
167         struct bootpc_ifcontext *sethostname;
168         struct bootpc_tagcontext tmptag;
169         struct bootpc_tagcontext tag;
170 };
171
172 #define IPPORT_BOOTPC 68
173 #define IPPORT_BOOTPS 67
174
175 #define BOOTP_REQUEST 1
176 #define BOOTP_REPLY 2
177
178 /* Common tags */
179 #define TAG_PAD           0  /* Pad option, implicit length 1 */
180 #define TAG_SUBNETMASK    1  /* RFC 950 subnet mask */
181 #define TAG_ROUTERS       3  /* Routers (in order of preference) */
182 #define TAG_HOSTNAME     12  /* Client host name */
183 #define TAG_ROOT         17  /* Root path */
184
185 /* DHCP specific tags */
186 #define TAG_OVERLOAD     52  /* Option Overload */
187 #define TAG_MAXMSGSIZE   57  /* Maximum DHCP Message Size */
188
189 #define TAG_END         255  /* End Option (i.e. no more options) */
190
191 /* Overload values */
192 #define OVERLOAD_FILE     1
193 #define OVERLOAD_SNAME    2
194
195 /* Site specific tags: */
196 #define TAG_ROOTOPTS    130
197 #define TAG_COOKIE      134     /* ascii info for userland, via sysctl */
198
199 #define TAG_DHCP_MSGTYPE 53
200 #define TAG_DHCP_REQ_ADDR 50
201 #define TAG_DHCP_SERVERID 54
202 #define TAG_DHCP_LEASETIME 51
203
204 #define TAG_VENDOR_INDENTIFIER 60
205
206 #define DHCP_NOMSG    0
207 #define DHCP_DISCOVER 1
208 #define DHCP_OFFER    2
209 #define DHCP_REQUEST  3
210 #define DHCP_ACK      5
211
212 static char bootp_cookie[128];
213 SYSCTL_STRING(_kern, OID_AUTO, bootp_cookie, CTLFLAG_RD,
214         bootp_cookie, 0, "Cookie (T134) supplied by bootp server");
215
216 /* mountd RPC */
217 static int      md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp,
218                     int *fhsizep, struct nfs_args *args, struct thread *td);
219 static int      setfs(struct sockaddr_in *addr, char *path, char *p,
220                     const struct in_addr *siaddr);
221 static int      getdec(char **ptr);
222 static int      getip(char **ptr, struct in_addr *ip);
223 static void     mountopts(struct nfs_args *args, char *p);
224 static int      xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
225 static int      xdr_int_decode(struct mbuf **ptr, int *iptr);
226 static void     print_in_addr(struct in_addr addr);
227 static void     print_sin_addr(struct sockaddr_in *addr);
228 static void     clear_sinaddr(struct sockaddr_in *sin);
229 static void     allocifctx(struct bootpc_globalcontext *gctx);
230 static void     bootpc_compose_query(struct bootpc_ifcontext *ifctx,
231                     struct bootpc_globalcontext *gctx, struct thread *td);
232 static unsigned char *bootpc_tag(struct bootpc_tagcontext *tctx,
233                     struct bootp_packet *bp, int len, int tag);
234 static void bootpc_tag_helper(struct bootpc_tagcontext *tctx,
235                     unsigned char *start, int len, int tag);
236
237 #ifdef BOOTP_DEBUG
238 void bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma);
239 void bootpboot_p_ma(struct sockaddr *ma);
240 void bootpboot_p_rtentry(struct rtentry *rt);
241 void bootpboot_p_tree(struct radix_node *rn);
242 void bootpboot_p_rtlist(void);
243 void bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa);
244 void bootpboot_p_iflist(void);
245 #endif
246
247 static int      bootpc_call(struct bootpc_globalcontext *gctx,
248                     struct thread *td);
249
250 static int      bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
251                     struct bootpc_globalcontext *gctx, struct thread *td);
252
253 static int      bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
254                     struct bootpc_globalcontext *gctx, struct thread *td);
255
256 static void     bootpc_decode_reply(struct nfsv3_diskless *nd,
257                     struct bootpc_ifcontext *ifctx,
258                     struct bootpc_globalcontext *gctx);
259
260 static int      bootpc_received(struct bootpc_globalcontext *gctx,
261                     struct bootpc_ifcontext *ifctx);
262
263 static __inline int bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx);
264 static __inline int bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx);
265 static __inline int bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx);
266
267 /*
268  * In order to have multiple active interfaces with address 0.0.0.0
269  * and be able to send data to a selected interface, we perform
270  * some tricks:
271  *
272  *  - The 'broadcast' address is different for each interface.
273  *
274  *  - We temporarily add routing pointing 255.255.255.255 to the
275  *    selected interface broadcast address, thus the packet sent
276  *    goes to that interface.
277  */
278
279 #ifdef BOOTP_DEBUG
280 void
281 bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma)
282 {
283
284         if (sa == NULL) {
285                 printf("(sockaddr *) <null>");
286                 return;
287         }
288         switch (sa->sa_family) {
289         case AF_INET:
290         {
291                 struct sockaddr_in *sin;
292
293                 sin = (struct sockaddr_in *) sa;
294                 printf("inet ");
295                 print_sin_addr(sin);
296                 if (ma != NULL) {
297                         sin = (struct sockaddr_in *) ma;
298                         printf(" mask ");
299                         print_sin_addr(sin);
300                 }
301         }
302         break;
303         case AF_LINK:
304         {
305                 struct sockaddr_dl *sli;
306                 int i;
307
308                 sli = (struct sockaddr_dl *) sa;
309                 printf("link %.*s ", sli->sdl_nlen, sli->sdl_data);
310                 for (i = 0; i < sli->sdl_alen; i++) {
311                         if (i > 0)
312                                 printf(":");
313                         printf("%x", ((unsigned char *) LLADDR(sli))[i]);
314                 }
315         }
316         break;
317         default:
318                 printf("af%d", sa->sa_family);
319         }
320 }
321
322 void
323 bootpboot_p_ma(struct sockaddr *ma)
324 {
325
326         if (ma == NULL) {
327                 printf("<null>");
328                 return;
329         }
330         printf("%x", *(int *)ma);
331 }
332
333 void
334 bootpboot_p_rtentry(struct rtentry *rt)
335 {
336
337         bootpboot_p_sa(rt_key(rt), rt_mask(rt));
338         printf(" ");
339         bootpboot_p_ma(rt->rt_genmask);
340         printf(" ");
341         bootpboot_p_sa(rt->rt_gateway, NULL);
342         printf(" ");
343         printf("flags %x", (unsigned short) rt->rt_flags);
344         printf(" %d", (int) rt->rt_rmx.rmx_expire);
345         printf(" %s\n", rt->rt_ifp->if_xname);
346 }
347
348 void
349 bootpboot_p_tree(struct radix_node *rn)
350 {
351
352         while (rn != NULL) {
353                 if (rn->rn_bit < 0) {
354                         if ((rn->rn_flags & RNF_ROOT) != 0) {
355                         } else {
356                                 bootpboot_p_rtentry((struct rtentry *) rn);
357                         }
358                         rn = rn->rn_dupedkey;
359                 } else {
360                         bootpboot_p_tree(rn->rn_left);
361                         bootpboot_p_tree(rn->rn_right);
362                         return;
363                 }
364         }
365 }
366
367 void
368 bootpboot_p_rtlist(void)
369 {
370
371         printf("Routing table:\n");
372         RADIX_NODE_LOCK(rt_tables[AF_INET]);    /* could sleep XXX */
373         bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
374         RADIX_NODE_UNLOCK(rt_tables[AF_INET]);
375 }
376
377 void
378 bootpboot_p_if(struct ifnet *ifp, struct ifaddr *ifa)
379 {
380
381         printf("%s flags %x, addr ",
382                ifp->if_xname, ifp->if_flags);
383         print_sin_addr((struct sockaddr_in *) ifa->ifa_addr);
384         printf(", broadcast ");
385         print_sin_addr((struct sockaddr_in *) ifa->ifa_dstaddr);
386         printf(", netmask ");
387         print_sin_addr((struct sockaddr_in *) ifa->ifa_netmask);
388         printf("\n");
389 }
390
391 void
392 bootpboot_p_iflist(void)
393 {
394         struct ifnet *ifp;
395         struct ifaddr *ifa;
396
397         printf("Interface list:\n");
398         IFNET_RLOCK(); /* could sleep, but okay for debugging XXX */
399         for (ifp = TAILQ_FIRST(&ifnet);
400              ifp != NULL;
401              ifp = TAILQ_NEXT(ifp, if_link)) {
402                 for (ifa = TAILQ_FIRST(&ifp->if_addrhead);
403                      ifa != NULL;
404                      ifa = TAILQ_NEXT(ifa, ifa_link))
405                         if (ifa->ifa_addr->sa_family == AF_INET)
406                                 bootpboot_p_if(ifp, ifa);
407         }
408         IFNET_RUNLOCK();
409 }
410 #endif /* defined(BOOTP_DEBUG) */
411
412 static void
413 clear_sinaddr(struct sockaddr_in *sin)
414 {
415
416         bzero(sin, sizeof(*sin));
417         sin->sin_len = sizeof(*sin);
418         sin->sin_family = AF_INET;
419         sin->sin_addr.s_addr = INADDR_ANY; /* XXX: htonl(INAADDR_ANY) ? */
420         sin->sin_port = 0;
421 }
422
423 static void
424 allocifctx(struct bootpc_globalcontext *gctx)
425 {
426         struct bootpc_ifcontext *ifctx;
427         ifctx = (struct bootpc_ifcontext *) malloc(sizeof(*ifctx),
428                                                    M_TEMP, M_WAITOK | M_ZERO);
429         if (ifctx == NULL)
430                 panic("Failed to allocate bootp interface context structure");
431
432         ifctx->xid = gctx->xid;
433 #ifdef BOOTP_NO_DHCP
434         ifctx->state = IF_BOOTP_UNRESOLVED;
435 #else
436         ifctx->state = IF_DHCP_UNRESOLVED;
437 #endif
438         gctx->xid += 0x100;
439         if (gctx->interfaces != NULL)
440                 gctx->lastinterface->next = ifctx;
441         else
442                 gctx->interfaces = ifctx;
443         gctx->lastinterface = ifctx;
444 }
445
446 static __inline int
447 bootpc_ifctx_isresolved(struct bootpc_ifcontext *ifctx)
448 {
449
450         if (ifctx->state == IF_BOOTP_RESOLVED ||
451             ifctx->state == IF_DHCP_RESOLVED)
452                 return 1;
453         return 0;
454 }
455
456 static __inline int
457 bootpc_ifctx_isunresolved(struct bootpc_ifcontext *ifctx)
458 {
459
460         if (ifctx->state == IF_BOOTP_UNRESOLVED ||
461             ifctx->state == IF_DHCP_UNRESOLVED)
462                 return 1;
463         return 0;
464 }
465
466 static __inline int
467 bootpc_ifctx_isfailed(struct bootpc_ifcontext *ifctx)
468 {
469
470         if (ifctx->state == IF_BOOTP_FAILED ||
471             ifctx->state == IF_DHCP_FAILED)
472                 return 1;
473         return 0;
474 }
475
476 static int
477 bootpc_received(struct bootpc_globalcontext *gctx,
478     struct bootpc_ifcontext *ifctx)
479 {
480         unsigned char dhcpreplytype;
481         char *p;
482
483         /*
484          * Need timeout for fallback to less
485          * desirable alternative.
486          */
487
488         /* This call used for the side effect (badopt flag) */
489         (void) bootpc_tag(&gctx->tmptag, &gctx->reply,
490                           gctx->replylen,
491                           TAG_END);
492
493         /* If packet is invalid, ignore it */
494         if (gctx->tmptag.badopt != 0)
495                 return 0;
496
497         p = bootpc_tag(&gctx->tmptag, &gctx->reply,
498                        gctx->replylen, TAG_DHCP_MSGTYPE);
499         if (p != NULL)
500                 dhcpreplytype = *p;
501         else
502                 dhcpreplytype = DHCP_NOMSG;
503
504         switch (ifctx->dhcpquerytype) {
505         case DHCP_DISCOVER:
506                 if (dhcpreplytype != DHCP_OFFER         /* Normal DHCP offer */
507 #ifndef BOOTP_FORCE_DHCP
508                     && dhcpreplytype != DHCP_NOMSG      /* Fallback to BOOTP */
509 #endif
510                         )
511                         return 0;
512                 break;
513         case DHCP_REQUEST:
514                 if (dhcpreplytype != DHCP_ACK)
515                         return 0;
516         case DHCP_NOMSG:
517                 break;
518         }
519
520         /* Ignore packet unless it gives us a root tag we didn't have */
521
522         if ((ifctx->state == IF_BOOTP_RESOLVED ||
523              (ifctx->dhcpquerytype == DHCP_DISCOVER &&
524               (ifctx->state == IF_DHCP_OFFERED ||
525                ifctx->state == IF_DHCP_RESOLVED))) &&
526             (bootpc_tag(&gctx->tmptag, &ifctx->reply,
527                         ifctx->replylen,
528                         TAG_ROOT) != NULL ||
529              bootpc_tag(&gctx->tmptag, &gctx->reply,
530                         gctx->replylen,
531                         TAG_ROOT) == NULL))
532                 return 0;
533
534         bcopy(&gctx->reply, &ifctx->reply, gctx->replylen);
535         ifctx->replylen = gctx->replylen;
536
537         /* XXX: Only reset if 'perfect' response */
538         if (ifctx->state == IF_BOOTP_UNRESOLVED)
539                 ifctx->state = IF_BOOTP_RESOLVED;
540         else if (ifctx->state == IF_DHCP_UNRESOLVED &&
541                  ifctx->dhcpquerytype == DHCP_DISCOVER) {
542                 if (dhcpreplytype == DHCP_OFFER)
543                         ifctx->state = IF_DHCP_OFFERED;
544                 else
545                         ifctx->state = IF_BOOTP_RESOLVED;       /* Fallback */
546         } else if (ifctx->state == IF_DHCP_OFFERED &&
547                    ifctx->dhcpquerytype == DHCP_REQUEST)
548                 ifctx->state = IF_DHCP_RESOLVED;
549
550
551         if (ifctx->dhcpquerytype == DHCP_DISCOVER &&
552             ifctx->state != IF_BOOTP_RESOLVED) {
553                 p = bootpc_tag(&gctx->tmptag, &ifctx->reply,
554                                ifctx->replylen, TAG_DHCP_SERVERID);
555                 if (p != NULL && gctx->tmptag.taglen == 4) {
556                         memcpy(&ifctx->dhcpserver, p, 4);
557                         ifctx->gotdhcpserver = 1;
558                 } else
559                         ifctx->gotdhcpserver = 0;
560                 return 1;
561         }
562
563         ifctx->gotrootpath = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
564                                          ifctx->replylen,
565                                          TAG_ROOT) != NULL);
566         ifctx->gotgw = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
567                                    ifctx->replylen,
568                                    TAG_ROUTERS) != NULL);
569         ifctx->gotnetmask = (bootpc_tag(&gctx->tmptag, &ifctx->reply,
570                                         ifctx->replylen,
571                                         TAG_SUBNETMASK) != NULL);
572         return 1;
573 }
574
575 static int
576 bootpc_call(struct bootpc_globalcontext *gctx, struct thread *td)
577 {
578         struct socket *so;
579         struct sockaddr_in *sin, dst;
580         struct uio auio;
581         struct sockopt sopt;
582         struct iovec aio;
583         int error, on, rcvflg, timo, len;
584         time_t atimo;
585         time_t rtimo;
586         struct timeval tv;
587         struct bootpc_ifcontext *ifctx;
588         int outstanding;
589         int gotrootpath;
590         int retry;
591         const char *s;
592
593         /*
594          * Create socket and set its recieve timeout.
595          */
596         error = socreate(AF_INET, &so, SOCK_DGRAM, 0, td->td_ucred, td);
597         if (error != 0)
598                 goto out0;
599
600         tv.tv_sec = 1;
601         tv.tv_usec = 0;
602         bzero(&sopt, sizeof(sopt));
603         sopt.sopt_dir = SOPT_SET;
604         sopt.sopt_level = SOL_SOCKET;
605         sopt.sopt_name = SO_RCVTIMEO;
606         sopt.sopt_val = &tv;
607         sopt.sopt_valsize = sizeof tv;
608
609         error = sosetopt(so, &sopt);
610         if (error != 0)
611                 goto out;
612
613         /*
614          * Enable broadcast.
615          */
616         on = 1;
617         sopt.sopt_name = SO_BROADCAST;
618         sopt.sopt_val = &on;
619         sopt.sopt_valsize = sizeof on;
620
621         error = sosetopt(so, &sopt);
622         if (error != 0)
623                 goto out;
624
625         /*
626          * Disable routing.
627          */
628
629         on = 1;
630         sopt.sopt_name = SO_DONTROUTE;
631         sopt.sopt_val = &on;
632         sopt.sopt_valsize = sizeof on;
633
634         error = sosetopt(so, &sopt);
635         if (error != 0)
636                 goto out;
637
638         /*
639          * Bind the local endpoint to a bootp client port.
640          */
641         sin = &dst;
642         clear_sinaddr(sin);
643         sin->sin_port = htons(IPPORT_BOOTPC);
644         error = sobind(so, (struct sockaddr *)sin, td);
645         if (error != 0) {
646                 printf("bind failed\n");
647                 goto out;
648         }
649
650         /*
651          * Setup socket address for the server.
652          */
653         sin = &dst;
654         clear_sinaddr(sin);
655         sin->sin_addr.s_addr = INADDR_BROADCAST;
656         sin->sin_port = htons(IPPORT_BOOTPS);
657
658         /*
659          * Send it, repeatedly, until a reply is received,
660          * but delay each re-send by an increasing amount.
661          * If the delay hits the maximum, start complaining.
662          */
663         timo = 0;
664         rtimo = 0;
665         for (;;) {
666
667                 outstanding = 0;
668                 gotrootpath = 0;
669
670                 for (ifctx = gctx->interfaces;
671                      ifctx != NULL;
672                      ifctx = ifctx->next) {
673                         if (bootpc_ifctx_isresolved(ifctx) != 0 &&
674                             bootpc_tag(&gctx->tmptag, &ifctx->reply,
675                                        ifctx->replylen,
676                                        TAG_ROOT) != NULL)
677                                 gotrootpath = 1;
678                 }
679
680                 for (ifctx = gctx->interfaces;
681                      ifctx != NULL;
682                      ifctx = ifctx->next) {
683                         ifctx->outstanding = 0;
684                         if (bootpc_ifctx_isresolved(ifctx)  != 0 &&
685                             gotrootpath != 0) {
686                                 continue;
687                         }
688                         if (bootpc_ifctx_isfailed(ifctx) != 0)
689                                 continue;
690
691                         outstanding++;
692                         ifctx->outstanding = 1;
693
694                         /* Proceed to next step in DHCP negotiation */
695                         if ((ifctx->state == IF_DHCP_OFFERED &&
696                              ifctx->dhcpquerytype != DHCP_REQUEST) ||
697                             (ifctx->state == IF_DHCP_UNRESOLVED &&
698                              ifctx->dhcpquerytype != DHCP_DISCOVER) ||
699                             (ifctx->state == IF_BOOTP_UNRESOLVED &&
700                              ifctx->dhcpquerytype != DHCP_NOMSG)) {
701                                 ifctx->sentmsg = 0;
702                                 bootpc_compose_query(ifctx, gctx, td);
703                         }
704
705                         /* Send BOOTP request (or re-send). */
706
707                         if (ifctx->sentmsg == 0) {
708                                 switch(ifctx->dhcpquerytype) {
709                                 case DHCP_DISCOVER:
710                                         s = "DHCP Discover";
711                                         break;
712                                 case DHCP_REQUEST:
713                                         s = "DHCP Request";
714                                         break;
715                                 case DHCP_NOMSG:
716                                 default:
717                                         s = "BOOTP Query";
718                                         break;
719                                 }
720                                 printf("Sending %s packet from "
721                                        "interface %s (%*D)\n",
722                                        s,
723                                        ifctx->ireq.ifr_name,
724                                        ifctx->sdl->sdl_alen,
725                                        (unsigned char *) LLADDR(ifctx->sdl),
726                                        ":");
727                                 ifctx->sentmsg = 1;
728                         }
729
730                         aio.iov_base = (caddr_t) &ifctx->call;
731                         aio.iov_len = sizeof(ifctx->call);
732
733                         auio.uio_iov = &aio;
734                         auio.uio_iovcnt = 1;
735                         auio.uio_segflg = UIO_SYSSPACE;
736                         auio.uio_rw = UIO_WRITE;
737                         auio.uio_offset = 0;
738                         auio.uio_resid = sizeof(ifctx->call);
739                         auio.uio_td = td;
740
741                         /* Set netmask to 0.0.0.0 */
742
743                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
744                         clear_sinaddr(sin);
745                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
746                                         (caddr_t) &ifctx->ireq, td);
747                         if (error != 0)
748                                 panic("bootpc_call:"
749                                       "set if netmask, error=%d",
750                                       error);
751
752                         error = sosend(so, (struct sockaddr *) &dst,
753                                        &auio, NULL, NULL, 0, td);
754                         if (error != 0) {
755                                 printf("bootpc_call: sosend: %d state %08x\n",
756                                        error, (int) so->so_state);
757                         }
758
759                         /* XXX: Is this needed ? */
760                         pause("bootpw", hz/10);
761
762                         /* Set netmask to 255.0.0.0 */
763
764                         sin = (struct sockaddr_in *) &ifctx->ireq.ifr_addr;
765                         clear_sinaddr(sin);
766                         sin->sin_addr.s_addr = htonl(0xff000000u);
767                         error = ifioctl(ifctx->so, SIOCSIFNETMASK,
768                                         (caddr_t) &ifctx->ireq, td);
769                         if (error != 0)
770                                 panic("bootpc_call:"
771                                       "set if netmask, error=%d",
772                                       error);
773
774                 }
775
776                 if (outstanding == 0 &&
777                     (rtimo == 0 || time_second >= rtimo)) {
778                         error = 0;
779                         goto gotreply;
780                 }
781
782                 /* Determine new timeout. */
783                 if (timo < MAX_RESEND_DELAY)
784                         timo++;
785                 else {
786                         printf("DHCP/BOOTP timeout for server ");
787                         print_sin_addr(&dst);
788                         printf("\n");
789                 }
790
791                 /*
792                  * Wait for up to timo seconds for a reply.
793                  * The socket receive timeout was set to 1 second.
794                  */
795                 atimo = timo + time_second;
796                 while (time_second < atimo) {
797                         aio.iov_base = (caddr_t) &gctx->reply;
798                         aio.iov_len = sizeof(gctx->reply);
799
800                         auio.uio_iov = &aio;
801                         auio.uio_iovcnt = 1;
802                         auio.uio_segflg = UIO_SYSSPACE;
803                         auio.uio_rw = UIO_READ;
804                         auio.uio_offset = 0;
805                         auio.uio_resid = sizeof(gctx->reply);
806                         auio.uio_td = td;
807
808                         rcvflg = 0;
809                         error = soreceive(so, NULL, &auio,
810                                           NULL, NULL, &rcvflg);
811                         gctx->secs = time_second - gctx->starttime;
812                         for (ifctx = gctx->interfaces;
813                              ifctx != NULL;
814                              ifctx = ifctx->next) {
815                                 if (bootpc_ifctx_isresolved(ifctx) != 0 ||
816                                     bootpc_ifctx_isfailed(ifctx) != 0)
817                                         continue;
818
819                                 ifctx->call.secs = htons(gctx->secs);
820                         }
821                         if (error == EWOULDBLOCK)
822                                 continue;
823                         if (error != 0)
824                                 goto out;
825                         len = sizeof(gctx->reply) - auio.uio_resid;
826
827                         /* Do we have the required number of bytes ? */
828                         if (len < BOOTP_MIN_LEN)
829                                 continue;
830                         gctx->replylen = len;
831
832                         /* Is it a reply? */
833                         if (gctx->reply.op != BOOTP_REPLY)
834                                 continue;
835
836                         /* Is this an answer to our query */
837                         for (ifctx = gctx->interfaces;
838                              ifctx != NULL;
839                              ifctx = ifctx->next) {
840                                 if (gctx->reply.xid != ifctx->call.xid)
841                                         continue;
842
843                                 /* Same HW address size ? */
844                                 if (gctx->reply.hlen != ifctx->call.hlen)
845                                         continue;
846
847                                 /* Correct HW address ? */
848                                 if (bcmp(gctx->reply.chaddr,
849                                          ifctx->call.chaddr,
850                                          ifctx->call.hlen) != 0)
851                                         continue;
852
853                                 break;
854                         }
855
856                         if (ifctx != NULL) {
857                                 s =  bootpc_tag(&gctx->tmptag,
858                                                 &gctx->reply,
859                                                 gctx->replylen,
860                                                 TAG_DHCP_MSGTYPE);
861                                 if (s != NULL) {
862                                         switch (*s) {
863                                         case DHCP_OFFER:
864                                                 s = "DHCP Offer";
865                                                 break;
866                                         case DHCP_ACK:
867                                                 s = "DHCP Ack";
868                                                 break;
869                                         default:
870                                                 s = "DHCP (unexpected)";
871                                                 break;
872                                         }
873                                 } else
874                                         s = "BOOTP Reply";
875
876                                 printf("Received %s packet"
877                                        " on %s from ",
878                                        s,
879                                        ifctx->ireq.ifr_name);
880                                 print_in_addr(gctx->reply.siaddr);
881                                 if (gctx->reply.giaddr.s_addr !=
882                                     htonl(INADDR_ANY)) {
883                                         printf(" via ");
884                                         print_in_addr(gctx->reply.giaddr);
885                                 }
886                                 if (bootpc_received(gctx, ifctx) != 0) {
887                                         printf(" (accepted)");
888                                         if (ifctx->outstanding) {
889                                                 ifctx->outstanding = 0;
890                                                 outstanding--;
891                                         }
892                                         /* Network settle delay */
893                                         if (outstanding == 0)
894                                                 atimo = time_second +
895                                                         BOOTP_SETTLE_DELAY;
896                                 } else
897                                         printf(" (ignored)");
898                                 if (ifctx->gotrootpath) {
899                                         gotrootpath = 1;
900                                         rtimo = time_second +
901                                                 BOOTP_SETTLE_DELAY;
902                                         printf(" (got root path)");
903                                 } else
904                                         printf(" (no root path)");
905                                 printf("\n");
906                         }
907                 } /* while secs */
908 #ifdef BOOTP_TIMEOUT
909                 if (gctx->secs > BOOTP_TIMEOUT && BOOTP_TIMEOUT > 0)
910                         break;
911 #endif
912                 /* Force a retry if halfway in DHCP negotiation */
913                 retry = 0;
914                 for (ifctx = gctx->interfaces; ifctx != NULL;
915                      ifctx = ifctx->next) {
916                         if (ifctx->state == IF_DHCP_OFFERED) {
917                                 if (ifctx->dhcpquerytype == DHCP_DISCOVER)
918                                         retry = 1;
919                                 else
920                                         ifctx->state = IF_DHCP_UNRESOLVED;
921                         }
922                 }
923
924                 if (retry != 0)
925                         continue;
926
927                 if (gotrootpath != 0) {
928                         gctx->gotrootpath = gotrootpath;
929                         if (rtimo != 0 && time_second >= rtimo)
930                                 break;
931                 }
932         } /* forever send/receive */
933
934         /*
935          * XXX: These are errors of varying seriousness being silently
936          * ignored
937          */
938
939         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
940                 if (bootpc_ifctx_isresolved(ifctx) == 0) {
941                         printf("%s timeout for interface %s\n",
942                                ifctx->dhcpquerytype != DHCP_NOMSG ?
943                                "DHCP" : "BOOTP",
944                                ifctx->ireq.ifr_name);
945                 }
946         }
947         if (gctx->gotrootpath != 0) {
948 #if 0
949                 printf("Got a root path, ignoring remaining timeout\n");
950 #endif
951                 error = 0;
952                 goto out;
953         }
954 #ifndef BOOTP_NFSROOT
955         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
956                 if (bootpc_ifctx_isresolved(ifctx) != 0) {
957                         error = 0;
958                         goto out;
959                 }
960         }
961 #endif
962         error = ETIMEDOUT;
963         goto out;
964
965 gotreply:
966 out:
967         soclose(so);
968 out0:
969         return error;
970 }
971
972 static int
973 bootpc_fakeup_interface(struct bootpc_ifcontext *ifctx,
974     struct bootpc_globalcontext *gctx, struct thread *td)
975 {
976         struct sockaddr_in *sin;
977         int error;
978         struct ifreq *ireq;
979         struct socket *so;
980         struct ifaddr *ifa;
981         struct sockaddr_dl *sdl;
982
983         error = socreate(AF_INET, &ifctx->so, SOCK_DGRAM, 0, td->td_ucred, td);
984         if (error != 0)
985                 panic("nfs_boot: socreate, error=%d", error);
986
987         ireq = &ifctx->ireq;
988         so = ifctx->so;
989
990         /*
991          * Bring up the interface.
992          *
993          * Get the old interface flags and or IFF_UP into them; if
994          * IFF_UP set blindly, interface selection can be clobbered.
995          */
996         error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
997         if (error != 0)
998                 panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
999         ireq->ifr_flags |= IFF_UP;
1000         error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1001         if (error != 0)
1002                 panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
1003
1004         /*
1005          * Do enough of ifconfig(8) so that the chosen interface
1006          * can talk to the servers.  (just set the address)
1007          */
1008
1009         /* addr is 0.0.0.0 */
1010
1011         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1012         clear_sinaddr(sin);
1013         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1014         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1015                 panic("bootpc_fakeup_interface: "
1016                       "set if addr, error=%d", error);
1017
1018         /* netmask is 255.0.0.0 */
1019
1020         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1021         clear_sinaddr(sin);
1022         sin->sin_addr.s_addr = htonl(0xff000000u);
1023         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, td);
1024         if (error != 0)
1025                 panic("bootpc_fakeup_interface: set if netmask, error=%d",
1026                       error);
1027
1028         /* Broadcast is 255.255.255.255 */
1029
1030         sin = (struct sockaddr_in *)&ireq->ifr_addr;
1031         clear_sinaddr(sin);
1032         clear_sinaddr(&ifctx->broadcast);
1033         sin->sin_addr.s_addr = htonl(INADDR_BROADCAST);
1034         ifctx->broadcast.sin_addr.s_addr = sin->sin_addr.s_addr;
1035
1036         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, td);
1037         if (error != 0)
1038                 panic("bootpc_fakeup_interface: "
1039                       "set if broadcast addr, error=%d",
1040                       error);
1041
1042         /* Get HW address */
1043
1044         sdl = NULL;
1045         TAILQ_FOREACH(ifa, &ifctx->ifp->if_addrhead, ifa_link)
1046                 if (ifa->ifa_addr->sa_family == AF_LINK) {
1047                         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
1048                         if (sdl->sdl_type == IFT_ETHER)
1049                                 break;
1050                 }
1051
1052         if (sdl == NULL)
1053                 panic("bootpc: Unable to find HW address for %s",
1054                       ifctx->ireq.ifr_name);
1055         ifctx->sdl = sdl;
1056
1057         return error;
1058 }
1059
1060
1061 static int
1062 bootpc_adjust_interface(struct bootpc_ifcontext *ifctx,
1063     struct bootpc_globalcontext *gctx, struct thread *td)
1064 {
1065         int error;
1066         struct sockaddr_in defdst;
1067         struct sockaddr_in defmask;
1068         struct sockaddr_in *sin;
1069         struct ifreq *ireq;
1070         struct socket *so;
1071         struct sockaddr_in *myaddr;
1072         struct sockaddr_in *netmask;
1073         struct sockaddr_in *gw;
1074
1075         ireq = &ifctx->ireq;
1076         so = ifctx->so;
1077         myaddr = &ifctx->myaddr;
1078         netmask = &ifctx->netmask;
1079         gw = &ifctx->gw;
1080
1081         if (bootpc_ifctx_isresolved(ifctx) == 0) {
1082
1083                 /* Shutdown interfaces where BOOTP failed */
1084
1085                 printf("Shutdown interface %s\n", ifctx->ireq.ifr_name);
1086                 error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, td);
1087                 if (error != 0)
1088                         panic("bootpc_adjust_interface: "
1089                               "SIOCGIFFLAGS, error=%d", error);
1090                 ireq->ifr_flags &= ~IFF_UP;
1091                 error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, td);
1092                 if (error != 0)
1093                         panic("bootpc_adjust_interface: "
1094                               "SIOCSIFFLAGS, error=%d", error);
1095
1096                 sin = (struct sockaddr_in *) &ireq->ifr_addr;
1097                 clear_sinaddr(sin);
1098                 error = ifioctl(so, SIOCDIFADDR, (caddr_t) ireq, td);
1099                 if (error != 0 && (error != EEXIST ||
1100                                    ifctx == gctx->interfaces))
1101                         panic("bootpc_adjust_interface: "
1102                               "SIOCDIFADDR, error=%d", error);
1103
1104                 return 0;
1105         }
1106
1107         printf("Adjusted interface %s\n", ifctx->ireq.ifr_name);
1108         /*
1109          * Do enough of ifconfig(8) so that the chosen interface
1110          * can talk to the servers.  (just set the address)
1111          */
1112         bcopy(netmask, &ireq->ifr_addr, sizeof(*netmask));
1113         error = ifioctl(so, SIOCSIFNETMASK, (caddr_t) ireq, td);
1114         if (error != 0)
1115                 panic("bootpc_adjust_interface: "
1116                       "set if netmask, error=%d", error);
1117
1118         /* Broadcast is with host part of IP address all 1's */
1119
1120         sin = (struct sockaddr_in *) &ireq->ifr_addr;
1121         clear_sinaddr(sin);
1122         sin->sin_addr.s_addr = myaddr->sin_addr.s_addr |
1123                 ~ netmask->sin_addr.s_addr;
1124         error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t) ireq, td);
1125         if (error != 0)
1126                 panic("bootpc_adjust_interface: "
1127                       "set if broadcast addr, error=%d", error);
1128
1129         bcopy(myaddr, &ireq->ifr_addr, sizeof(*myaddr));
1130         error = ifioctl(so, SIOCSIFADDR, (caddr_t) ireq, td);
1131         if (error != 0 && (error != EEXIST || ifctx == gctx->interfaces))
1132                 panic("bootpc_adjust_interface: "
1133                       "set if addr, error=%d", error);
1134
1135         /* Add new default route */
1136
1137         if (ifctx->gotgw != 0 || gctx->gotgw == 0) {
1138                 clear_sinaddr(&defdst);
1139                 clear_sinaddr(&defmask);
1140                 /* XXX MRT just table 0 */
1141                 error = rtrequest_fib(RTM_ADD,
1142                                   (struct sockaddr *) &defdst,
1143                                   (struct sockaddr *) gw,
1144                                   (struct sockaddr *) &defmask,
1145                                   (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL, 0);
1146                 if (error != 0) {
1147                         printf("bootpc_adjust_interface: "
1148                                "add net route, error=%d\n", error);
1149                         return error;
1150                 }
1151         }
1152
1153         return 0;
1154 }
1155
1156 static int
1157 setfs(struct sockaddr_in *addr, char *path, char *p,
1158     const struct in_addr *siaddr)
1159 {
1160
1161         if (getip(&p, &addr->sin_addr) == 0) {
1162                 if (siaddr != NULL && *p == '/')
1163                         bcopy(siaddr, &addr->sin_addr, sizeof(struct in_addr));
1164                 else
1165                         return 0;
1166         } else {
1167                 if (*p != ':')
1168                         return 0;
1169                 p++;
1170         }
1171                 
1172         addr->sin_len = sizeof(struct sockaddr_in);
1173         addr->sin_family = AF_INET;
1174
1175         strlcpy(path, p, MNAMELEN);
1176         return 1;
1177 }
1178
1179 static int
1180 getip(char **ptr, struct in_addr *addr)
1181 {
1182         char *p;
1183         unsigned int ip;
1184         int val;
1185
1186         p = *ptr;
1187         ip = 0;
1188         if (((val = getdec(&p)) < 0) || (val > 255))
1189                 return 0;
1190         ip = val << 24;
1191         if (*p != '.')
1192                 return 0;
1193         p++;
1194         if (((val = getdec(&p)) < 0) || (val > 255))
1195                 return 0;
1196         ip |= (val << 16);
1197         if (*p != '.')
1198                 return 0;
1199         p++;
1200         if (((val = getdec(&p)) < 0) || (val > 255))
1201                 return 0;
1202         ip |= (val << 8);
1203         if (*p != '.')
1204                 return 0;
1205         p++;
1206         if (((val = getdec(&p)) < 0) || (val > 255))
1207                 return 0;
1208         ip |= val;
1209
1210         addr->s_addr = htonl(ip);
1211         *ptr = p;
1212         return 1;
1213 }
1214
1215 static int
1216 getdec(char **ptr)
1217 {
1218         char *p;
1219         int ret;
1220
1221         p = *ptr;
1222         ret = 0;
1223         if ((*p < '0') || (*p > '9'))
1224                 return -1;
1225         while ((*p >= '0') && (*p <= '9')) {
1226                 ret = ret * 10 + (*p - '0');
1227                 p++;
1228         }
1229         *ptr = p;
1230         return ret;
1231 }
1232
1233 static void
1234 mountopts(struct nfs_args *args, char *p)
1235 {
1236         args->version = NFS_ARGSVERSION;
1237         args->rsize = 8192;
1238         args->wsize = 8192;
1239         args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
1240         args->sotype = SOCK_DGRAM;
1241         if (p != NULL)
1242                 nfs_parse_options(p, args);
1243 }
1244
1245 static int
1246 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
1247 {
1248         struct mbuf *m;
1249         int alignedlen;
1250
1251         m = *mptr;
1252         alignedlen = ( len + 3 ) & ~3;
1253
1254         if (m->m_len < alignedlen) {
1255                 m = m_pullup(m, alignedlen);
1256                 if (m == NULL) {
1257                         *mptr = NULL;
1258                         return EBADRPC;
1259                 }
1260         }
1261         bcopy(mtod(m, u_char *), buf, len);
1262         m_adj(m, alignedlen);
1263         *mptr = m;
1264         return 0;
1265 }
1266
1267 static int
1268 xdr_int_decode(struct mbuf **mptr, int *iptr)
1269 {
1270         u_int32_t i;
1271
1272         if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
1273                 return EBADRPC;
1274         *iptr = fxdr_unsigned(u_int32_t, i);
1275         return 0;
1276 }
1277
1278 static void
1279 print_sin_addr(struct sockaddr_in *sin)
1280 {
1281
1282         print_in_addr(sin->sin_addr);
1283 }
1284
1285 static void
1286 print_in_addr(struct in_addr addr)
1287 {
1288         unsigned int ip;
1289
1290         ip = ntohl(addr.s_addr);
1291         printf("%d.%d.%d.%d",
1292                ip >> 24, (ip >> 16) & 255, (ip >> 8) & 255, ip & 255);
1293 }
1294
1295 static void
1296 bootpc_compose_query(struct bootpc_ifcontext *ifctx,
1297     struct bootpc_globalcontext *gctx, struct thread *td)
1298 {
1299         unsigned char *vendp;
1300         unsigned char vendor_client[64];
1301         uint32_t leasetime;
1302         uint8_t vendor_client_len;
1303
1304         ifctx->gotrootpath = 0;
1305
1306         bzero((caddr_t) &ifctx->call, sizeof(ifctx->call));
1307
1308         /* bootpc part */
1309         ifctx->call.op = BOOTP_REQUEST;         /* BOOTREQUEST */
1310         ifctx->call.htype = 1;                  /* 10mb ethernet */
1311         ifctx->call.hlen = ifctx->sdl->sdl_alen;/* Hardware address length */
1312         ifctx->call.hops = 0;
1313         if (bootpc_ifctx_isunresolved(ifctx) != 0)
1314                 ifctx->xid++;
1315         ifctx->call.xid = txdr_unsigned(ifctx->xid);
1316         bcopy(LLADDR(ifctx->sdl), &ifctx->call.chaddr, ifctx->sdl->sdl_alen);
1317
1318         vendp = ifctx->call.vend;
1319         *vendp++ = 99;          /* RFC1048 cookie */
1320         *vendp++ = 130;
1321         *vendp++ = 83;
1322         *vendp++ = 99;
1323         *vendp++ = TAG_MAXMSGSIZE;
1324         *vendp++ = 2;
1325         *vendp++ = (sizeof(struct bootp_packet) >> 8) & 255;
1326         *vendp++ = sizeof(struct bootp_packet) & 255;
1327
1328         snprintf(vendor_client, sizeof(vendor_client), "%s:%s:%s",
1329                 ostype, MACHINE, osrelease);
1330         vendor_client_len = strlen(vendor_client);
1331         *vendp++ = TAG_VENDOR_INDENTIFIER;
1332         *vendp++ = vendor_client_len;
1333         memcpy(vendp, vendor_client, vendor_client_len);
1334         vendp += vendor_client_len;;
1335         ifctx->dhcpquerytype = DHCP_NOMSG;
1336         switch (ifctx->state) {
1337         case IF_DHCP_UNRESOLVED:
1338                 *vendp++ = TAG_DHCP_MSGTYPE;
1339                 *vendp++ = 1;
1340                 *vendp++ = DHCP_DISCOVER;
1341                 ifctx->dhcpquerytype = DHCP_DISCOVER;
1342                 ifctx->gotdhcpserver = 0;
1343                 break;
1344         case IF_DHCP_OFFERED:
1345                 *vendp++ = TAG_DHCP_MSGTYPE;
1346                 *vendp++ = 1;
1347                 *vendp++ = DHCP_REQUEST;
1348                 ifctx->dhcpquerytype = DHCP_REQUEST;
1349                 *vendp++ = TAG_DHCP_REQ_ADDR;
1350                 *vendp++ = 4;
1351                 memcpy(vendp, &ifctx->reply.yiaddr, 4);
1352                 vendp += 4;
1353                 if (ifctx->gotdhcpserver != 0) {
1354                         *vendp++ = TAG_DHCP_SERVERID;
1355                         *vendp++ = 4;
1356                         memcpy(vendp, &ifctx->dhcpserver, 4);
1357                         vendp += 4;
1358                 }
1359                 *vendp++ = TAG_DHCP_LEASETIME;
1360                 *vendp++ = 4;
1361                 leasetime = htonl(300);
1362                 memcpy(vendp, &leasetime, 4);
1363                 vendp += 4;
1364                 break;
1365         default:
1366                 break;
1367         }
1368         *vendp = TAG_END;
1369
1370         ifctx->call.secs = 0;
1371         ifctx->call.flags = htons(0x8000); /* We need a broadcast answer */
1372 }
1373
1374 static int
1375 bootpc_hascookie(struct bootp_packet *bp)
1376 {
1377
1378         return (bp->vend[0] == 99 && bp->vend[1] == 130 &&
1379                 bp->vend[2] == 83 && bp->vend[3] == 99);
1380 }
1381
1382 static void
1383 bootpc_tag_helper(struct bootpc_tagcontext *tctx,
1384     unsigned char *start, int len, int tag)
1385 {
1386         unsigned char *j;
1387         unsigned char *ej;
1388         unsigned char code;
1389
1390         if (tctx->badtag != 0 || tctx->badopt != 0)
1391                 return;
1392
1393         j = start;
1394         ej = j + len;
1395
1396         while (j < ej) {
1397                 code = *j++;
1398                 if (code == TAG_PAD)
1399                         continue;
1400                 if (code == TAG_END)
1401                         return;
1402                 if (j >= ej || j + *j + 1 > ej) {
1403                         tctx->badopt = 1;
1404                         return;
1405                 }
1406                 len = *j++;
1407                 if (code == tag) {
1408                         if (tctx->taglen + len > TAG_MAXLEN) {
1409                                 tctx->badtag = 1;
1410                                 return;
1411                         }
1412                         tctx->foundopt = 1;
1413                         if (len > 0)
1414                                 memcpy(tctx->buf + tctx->taglen,
1415                                        j, len);
1416                         tctx->taglen += len;
1417                 }
1418                 if (code == TAG_OVERLOAD)
1419                         tctx->overload = *j;
1420
1421                 j += len;
1422         }
1423 }
1424
1425 static unsigned char *
1426 bootpc_tag(struct bootpc_tagcontext *tctx,
1427     struct bootp_packet *bp, int len, int tag)
1428 {
1429         tctx->overload = 0;
1430         tctx->badopt = 0;
1431         tctx->badtag = 0;
1432         tctx->foundopt = 0;
1433         tctx->taglen = 0;
1434
1435         if (bootpc_hascookie(bp) == 0)
1436                 return NULL;
1437
1438         bootpc_tag_helper(tctx, &bp->vend[4],
1439                           (unsigned char *) bp + len - &bp->vend[4], tag);
1440
1441         if ((tctx->overload & OVERLOAD_FILE) != 0)
1442                 bootpc_tag_helper(tctx,
1443                                   (unsigned char *) bp->file,
1444                                   sizeof(bp->file),
1445                                   tag);
1446         if ((tctx->overload & OVERLOAD_SNAME) != 0)
1447                 bootpc_tag_helper(tctx,
1448                                   (unsigned char *) bp->sname,
1449                                   sizeof(bp->sname),
1450                                   tag);
1451
1452         if (tctx->badopt != 0 || tctx->badtag != 0 || tctx->foundopt == 0)
1453                 return NULL;
1454         tctx->buf[tctx->taglen] = '\0';
1455         return tctx->buf;
1456 }
1457
1458 static void
1459 bootpc_decode_reply(struct nfsv3_diskless *nd, struct bootpc_ifcontext *ifctx,
1460     struct bootpc_globalcontext *gctx)
1461 {
1462         char *p;
1463         unsigned int ip;
1464
1465         ifctx->gotgw = 0;
1466         ifctx->gotnetmask = 0;
1467
1468         clear_sinaddr(&ifctx->myaddr);
1469         clear_sinaddr(&ifctx->netmask);
1470         clear_sinaddr(&ifctx->gw);
1471
1472         ifctx->myaddr.sin_addr = ifctx->reply.yiaddr;
1473
1474         ip = ntohl(ifctx->myaddr.sin_addr.s_addr);
1475
1476         printf("%s at ", ifctx->ireq.ifr_name);
1477         print_sin_addr(&ifctx->myaddr);
1478         printf(" server ");
1479         print_in_addr(ifctx->reply.siaddr);
1480
1481         ifctx->gw.sin_addr = ifctx->reply.giaddr;
1482         if (ifctx->reply.giaddr.s_addr != htonl(INADDR_ANY)) {
1483                 printf(" via gateway ");
1484                 print_in_addr(ifctx->reply.giaddr);
1485         }
1486
1487         /* This call used for the side effect (overload flag) */
1488         (void) bootpc_tag(&gctx->tmptag,
1489                           &ifctx->reply, ifctx->replylen, TAG_END);
1490
1491         if ((gctx->tmptag.overload & OVERLOAD_SNAME) == 0)
1492                 if (ifctx->reply.sname[0] != '\0')
1493                         printf(" server name %s", ifctx->reply.sname);
1494         if ((gctx->tmptag.overload & OVERLOAD_FILE) == 0)
1495                 if (ifctx->reply.file[0] != '\0')
1496                         printf(" boot file %s", ifctx->reply.file);
1497
1498         printf("\n");
1499
1500         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1501                        TAG_SUBNETMASK);
1502         if (p != NULL) {
1503                 if (gctx->tag.taglen != 4)
1504                         panic("bootpc: subnet mask len is %d",
1505                               gctx->tag.taglen);
1506                 bcopy(p, &ifctx->netmask.sin_addr, 4);
1507                 ifctx->gotnetmask = 1;
1508                 printf("subnet mask ");
1509                 print_sin_addr(&ifctx->netmask);
1510                 printf(" ");
1511         }
1512
1513         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1514                        TAG_ROUTERS);
1515         if (p != NULL) {
1516                 /* Routers */
1517                 if (gctx->tag.taglen % 4)
1518                         panic("bootpc: Router Len is %d", gctx->tag.taglen);
1519                 if (gctx->tag.taglen > 0) {
1520                         bcopy(p, &ifctx->gw.sin_addr, 4);
1521                         printf("router ");
1522                         print_sin_addr(&ifctx->gw);
1523                         printf(" ");
1524                         ifctx->gotgw = 1;
1525                         gctx->gotgw = 1;
1526                 }
1527         }
1528
1529         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1530                        TAG_ROOT);
1531         if (p != NULL) {
1532                 if (gctx->setrootfs != NULL) {
1533                         printf("rootfs %s (ignored) ", p);
1534                 } else  if (setfs(&nd->root_saddr,
1535                                   nd->root_hostnam, p, &ifctx->reply.siaddr)) {
1536                         if (*p == '/') {
1537                                 printf("root_server ");
1538                                 print_sin_addr(&nd->root_saddr);
1539                                 printf(" ");
1540                         }
1541                         printf("rootfs %s ", p);
1542                         gctx->gotrootpath = 1;
1543                         ifctx->gotrootpath = 1;
1544                         gctx->setrootfs = ifctx;
1545
1546                         p = bootpc_tag(&gctx->tag, &ifctx->reply,
1547                                        ifctx->replylen,
1548                                        TAG_ROOTOPTS);
1549                         if (p != NULL) {
1550                                 mountopts(&nd->root_args, p);
1551                                 printf("rootopts %s ", p);
1552                         }
1553                 } else
1554                         panic("Failed to set rootfs to %s", p);
1555         }
1556
1557         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1558                        TAG_HOSTNAME);
1559         if (p != NULL) {
1560                 if (gctx->tag.taglen >= MAXHOSTNAMELEN)
1561                         panic("bootpc: hostname >= %d bytes",
1562                               MAXHOSTNAMELEN);
1563                 if (gctx->sethostname != NULL) {
1564                         printf("hostname %s (ignored) ", p);
1565                 } else {
1566                         strcpy(nd->my_hostnam, p);
1567                         strcpy(hostname, p);
1568                         printf("hostname %s ", hostname);
1569                         gctx->sethostname = ifctx;
1570                 }
1571         }
1572         p = bootpc_tag(&gctx->tag, &ifctx->reply, ifctx->replylen,
1573                         TAG_COOKIE);
1574         if (p != NULL) {        /* store in a sysctl variable */
1575                 int i, l = sizeof(bootp_cookie) - 1;
1576                 for (i = 0; i < l && p[i] != '\0'; i++)
1577                         bootp_cookie[i] = p[i];
1578                 p[i] = '\0';
1579         }
1580
1581
1582         printf("\n");
1583
1584         if (ifctx->gotnetmask == 0) {
1585                 if (IN_CLASSA(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1586                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1587                 else if (IN_CLASSB(ntohl(ifctx->myaddr.sin_addr.s_addr)))
1588                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1589                 else
1590                         ifctx->netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1591         }
1592         if (ifctx->gotgw == 0) {
1593                 /* Use proxyarp */
1594                 ifctx->gw.sin_addr.s_addr = ifctx->myaddr.sin_addr.s_addr;
1595         }
1596 }
1597
1598 void
1599 bootpc_init(void)
1600 {
1601         struct bootpc_ifcontext *ifctx, *nctx;  /* Interface BOOTP contexts */
1602         struct bootpc_globalcontext *gctx;      /* Global BOOTP context */
1603         struct ifnet *ifp;
1604         int error;
1605 #ifndef BOOTP_WIRED_TO
1606         int ifcnt;
1607 #endif
1608         struct nfsv3_diskless *nd;
1609         struct thread *td;
1610
1611         nd = &nfsv3_diskless;
1612         td = curthread;
1613
1614         /*
1615          * If already filled in, don't touch it here
1616          */
1617         if (nfs_diskless_valid != 0)
1618                 return;
1619
1620         gctx = malloc(sizeof(*gctx), M_TEMP, M_WAITOK | M_ZERO);
1621         if (gctx == NULL)
1622                 panic("Failed to allocate bootp global context structure");
1623
1624         gctx->xid = ~0xFFFF;
1625         gctx->starttime = time_second;
1626
1627         /*
1628          * Find a network interface.
1629          */
1630 #ifdef BOOTP_WIRED_TO
1631         printf("bootpc_init: wired to interface '%s'\n",
1632                __XSTRING(BOOTP_WIRED_TO));
1633         allocifctx(gctx);
1634 #else
1635         /*
1636          * Preallocate interface context storage, if another interface
1637          * attaches and wins the race, it won't be eligible for bootp.
1638          */
1639         IFNET_RLOCK();
1640         for (ifp = TAILQ_FIRST(&ifnet), ifcnt = 0;
1641              ifp != NULL;
1642              ifp = TAILQ_NEXT(ifp, if_link)) {
1643                 if ((ifp->if_flags &
1644                      (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
1645                     IFF_BROADCAST)
1646                         continue;
1647                 ifcnt++;
1648         }
1649         IFNET_RUNLOCK();
1650         if (ifcnt == 0)
1651                 panic("bootpc_init: no eligible interfaces");
1652         for (; ifcnt > 0; ifcnt--)
1653                 allocifctx(gctx);
1654 #endif
1655
1656         IFNET_RLOCK();
1657         for (ifp = TAILQ_FIRST(&ifnet), ifctx = gctx->interfaces;
1658              ifp != NULL && ifctx != NULL;
1659              ifp = TAILQ_NEXT(ifp, if_link)) {
1660                 strlcpy(ifctx->ireq.ifr_name, ifp->if_xname,
1661                     sizeof(ifctx->ireq.ifr_name));
1662 #ifdef BOOTP_WIRED_TO
1663                 if (strcmp(ifctx->ireq.ifr_name,
1664                            __XSTRING(BOOTP_WIRED_TO)) != 0)
1665                         continue;
1666 #else
1667                 if ((ifp->if_flags &
1668                      (IFF_LOOPBACK | IFF_POINTOPOINT | IFF_BROADCAST)) !=
1669                     IFF_BROADCAST)
1670                         continue;
1671 #endif
1672                 ifctx->ifp = ifp;
1673                 ifctx = ifctx->next;
1674         }
1675         IFNET_RUNLOCK();
1676
1677         if (gctx->interfaces == NULL || gctx->interfaces->ifp == NULL) {
1678 #ifdef BOOTP_WIRED_TO
1679                 panic("bootpc_init: Could not find interface specified "
1680                       "by BOOTP_WIRED_TO: "
1681                       __XSTRING(BOOTP_WIRED_TO));
1682 #else
1683                 panic("bootpc_init: no suitable interface");
1684 #endif
1685         }
1686
1687         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1688                 bootpc_fakeup_interface(ifctx, gctx, td);
1689
1690         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1691                 bootpc_compose_query(ifctx, gctx, td);
1692
1693         error = bootpc_call(gctx, td);
1694
1695         if (error != 0) {
1696 #ifdef BOOTP_NFSROOT
1697                 panic("BOOTP call failed");
1698 #else
1699                 printf("BOOTP call failed\n");
1700 #endif
1701         }
1702
1703         rootdevnames[0] = "nfs:";
1704         mountopts(&nd->root_args, NULL);
1705
1706         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1707                 if (bootpc_ifctx_isresolved(ifctx) != 0)
1708                         bootpc_decode_reply(nd, ifctx, gctx);
1709
1710 #ifdef BOOTP_NFSROOT
1711         if (gctx->gotrootpath == 0)
1712                 panic("bootpc: No root path offered");
1713 #endif
1714
1715         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next) {
1716                 bootpc_adjust_interface(ifctx, gctx, td);
1717
1718                 soclose(ifctx->so);
1719         }
1720
1721         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = ifctx->next)
1722                 if (ifctx->gotrootpath != 0)
1723                         break;
1724         if (ifctx == NULL) {
1725                 for (ifctx = gctx->interfaces;
1726                      ifctx != NULL;
1727                      ifctx = ifctx->next)
1728                         if (bootpc_ifctx_isresolved(ifctx) != 0)
1729                                 break;
1730         }
1731         if (ifctx == NULL)
1732                 goto out;
1733
1734         if (gctx->gotrootpath != 0) {
1735
1736                 setenv("boot.netif.name", ifctx->ifp->if_xname);
1737
1738                 error = md_mount(&nd->root_saddr, nd->root_hostnam,
1739                                  nd->root_fh, &nd->root_fhsize,
1740                                  &nd->root_args, td);
1741                 if (error != 0)
1742                         panic("nfs_boot: mountd root, error=%d", error);
1743
1744                 nfs_diskless_valid = 3;
1745         }
1746
1747         strcpy(nd->myif.ifra_name, ifctx->ireq.ifr_name);
1748         bcopy(&ifctx->myaddr, &nd->myif.ifra_addr, sizeof(ifctx->myaddr));
1749         bcopy(&ifctx->myaddr, &nd->myif.ifra_broadaddr, sizeof(ifctx->myaddr));
1750         ((struct sockaddr_in *) &nd->myif.ifra_broadaddr)->sin_addr.s_addr =
1751                 ifctx->myaddr.sin_addr.s_addr |
1752                 ~ ifctx->netmask.sin_addr.s_addr;
1753         bcopy(&ifctx->netmask, &nd->myif.ifra_mask, sizeof(ifctx->netmask));
1754
1755 out:
1756         for (ifctx = gctx->interfaces; ifctx != NULL; ifctx = nctx) {
1757                 nctx = ifctx->next;
1758                 free(ifctx, M_TEMP);
1759         }
1760         free(gctx, M_TEMP);
1761 }
1762
1763 /*
1764  * RPC: mountd/mount
1765  * Given a server pathname, get an NFS file handle.
1766  * Also, sets sin->sin_port to the NFS service port.
1767  */
1768 static int
1769 md_mount(struct sockaddr_in *mdsin, char *path, u_char *fhp, int *fhsizep,
1770     struct nfs_args *args, struct thread *td)
1771 {
1772         struct mbuf *m;
1773         int error;
1774         int authunixok;
1775         int authcount;
1776         int authver;
1777
1778         /* XXX honor v2/v3 flags in args->flags? */
1779 #ifdef BOOTP_NFSV3
1780         /* First try NFS v3 */
1781         /* Get port number for MOUNTD. */
1782         error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1783                              &mdsin->sin_port, td);
1784         if (error == 0) {
1785                 m = xdr_string_encode(path, strlen(path));
1786
1787                 /* Do RPC to mountd. */
1788                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
1789                                   RPCMNT_MOUNT, &m, NULL, td);
1790         }
1791         if (error == 0) {
1792                 args->flags |= NFSMNT_NFSV3;
1793         } else {
1794 #endif
1795                 /* Fallback to NFS v2 */
1796
1797                 /* Get port number for MOUNTD. */
1798                 error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1799                                      &mdsin->sin_port, td);
1800                 if (error != 0)
1801                         return error;
1802
1803                 m = xdr_string_encode(path, strlen(path));
1804
1805                 /* Do RPC to mountd. */
1806                 error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
1807                                   RPCMNT_MOUNT, &m, NULL, td);
1808                 if (error != 0)
1809                         return error;   /* message already freed */
1810
1811 #ifdef BOOTP_NFSV3
1812         }
1813 #endif
1814
1815         if (xdr_int_decode(&m, &error) != 0 || error != 0)
1816                 goto bad;
1817
1818         if ((args->flags & NFSMNT_NFSV3) != 0) {
1819                 if (xdr_int_decode(&m, fhsizep) != 0 ||
1820                     *fhsizep > NFSX_V3FHMAX ||
1821                     *fhsizep <= 0)
1822                         goto bad;
1823         } else
1824                 *fhsizep = NFSX_V2FH;
1825
1826         if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
1827                 goto bad;
1828
1829         if (args->flags & NFSMNT_NFSV3) {
1830                 if (xdr_int_decode(&m, &authcount) != 0)
1831                         goto bad;
1832                 authunixok = 0;
1833                 if (authcount < 0 || authcount > 100)
1834                         goto bad;
1835                 while (authcount > 0) {
1836                         if (xdr_int_decode(&m, &authver) != 0)
1837                                 goto bad;
1838                         if (authver == RPCAUTH_UNIX)
1839                                 authunixok = 1;
1840                         authcount--;
1841                 }
1842                 if (authunixok == 0)
1843                         goto bad;
1844         }
1845
1846         /* Set port number for NFS use. */
1847         error = krpc_portmap(mdsin, NFS_PROG,
1848                              (args->flags &
1849                               NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
1850                              &mdsin->sin_port, td);
1851
1852         goto out;
1853
1854 bad:
1855         error = EBADRPC;
1856
1857 out:
1858         m_freem(m);
1859         return error;
1860 }
1861
1862 SYSINIT(bootp_rootconf, SI_SUB_ROOT_CONF, SI_ORDER_FIRST, bootpc_init, NULL);