source: rtems/cpukit/libnetworking/nfs/bootp_subr.c @ 5af0cf2f

4.104.114.84.95
Last change on this file since 5af0cf2f was 9b02fa65, checked in by Joel Sherrill <joel.sherrill@…>, on 03/27/02 at 14:44:55

2002-03-27 Thomas.Doerfler@…

  • PR144
  • nfs/bootp_subr.c bootpc_init(): Performs a write to memory address 0 when called for the first time. This is done when trying to clear the variable "dhcp_hostname".
  • Property mode set to 100644
File size: 29.2 KB
Line 
1/*      $Id$    */
2
3/*
4 * Copyright (c) 1995 Gordon Ross, Adam Glass
5 * Copyright (c) 1992 Regents of the University of California.
6 * All rights reserved.
7 *
8 * This software was developed by the Computer Systems Engineering group
9 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
10 * contributed to Berkeley.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 *    must display the following acknowledgement:
22 *      This product includes software developed by the University of
23 *      California, Lawrence Berkeley Laboratory and its contributors.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * based on:
41 *      nfs/krpc_subr.c
42 *      $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
43 */
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/conf.h>
49#include <sys/sockio.h>
50#include <sys/proc.h>
51#include <sys/mount.h>
52#include <sys/mbuf.h>
53#include <sys/reboot.h>
54#include <sys/socket.h>
55#include <sys/socketvar.h>
56
57#include <net/if.h>
58#include <net/route.h>
59
60#include <netinet/in.h>
61#include <net/if_types.h>
62#include <net/if_dl.h>
63#include <netinet/if_ether.h>
64
65#include <nfs/rpcv2.h>
66#include <nfs/nfsproto.h>
67#include <nfs/nfs.h>
68#include <nfs/nfsdiskless.h>
69#include <nfs/krpc.h>
70#include <nfs/xdr_subs.h>
71
72#include <sys/stat.h>
73#include <sys/types.h>
74#include <fcntl.h>
75#include <rtems/mkrootfs.h>
76
77#define BOOTP_MIN_LEN           300     /* Minimum size of bootp udp packet */
78
79/*
80 * What is the longest we will wait before re-sending a request?
81 * Note this is also the frequency of "RPC timeout" messages.
82 * The re-send loop count sup linearly to this maximum, so the
83 * first complaint will happen after (1+2+3+4+5)=15 seconds.
84 */
85#define MAX_RESEND_DELAY 5      /* seconds */
86
87/* Definitions from RFC951 */
88struct bootp_packet {
89  u_int8_t op;
90  u_int8_t htype;
91  u_int8_t hlen;
92  u_int8_t hops;
93  u_int32_t xid;
94  u_int16_t secs;
95  u_int16_t flags;
96  struct in_addr ciaddr;
97  struct in_addr yiaddr;
98  struct in_addr siaddr;
99  struct in_addr giaddr;
100  unsigned char chaddr[16];
101  char sname[64];
102  char file[128];
103  unsigned char vend[256];
104};
105
106#define IPPORT_BOOTPC 68
107#define IPPORT_BOOTPS 67
108
109extern int nfs_diskless_valid;
110extern struct nfsv3_diskless nfsv3_diskless;
111
112/* mountd RPC */
113#if !defined(__rtems__)
114static int md_mount __P((struct sockaddr_in *mdsin, char *path,
115        u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp));
116static int md_lookup_swap __P((struct sockaddr_in *mdsin,char *path,
117                               u_char *fhp, int *fhsizep,
118                               struct nfs_args *args,
119                               struct proc *procp));
120static int setfs __P((struct sockaddr_in *addr, char *path, char *p));
121static int getdec __P((char **ptr));
122#endif
123static char *substr __P((char *a,char *b));
124#if !defined(__rtems__)
125static void mountopts __P((struct nfs_args *args, char *p));
126static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf,
127                                  int len));
128static int xdr_int_decode __P((struct mbuf **ptr,int *iptr));
129#endif
130static void printip __P((char *prefix,struct in_addr addr));
131
132#ifdef BOOTP_DEBUG
133void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
134void bootpboot_p_ma(struct sockaddr *ma);
135void bootpboot_p_rtentry(struct rtentry *rt);
136void bootpboot_p_tree(struct radix_node *rn);
137void bootpboot_p_rtlist(void);
138void bootpboot_p_iflist(void);
139#endif
140
141int  bootpc_call(struct bootp_packet *call,
142                 struct bootp_packet *reply,
143                 struct proc *procp);
144
145int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
146                        struct proc *procp);
147
148int
149bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
150                        struct sockaddr_in *myaddr,
151                        struct sockaddr_in *netmask,
152                        struct sockaddr_in *gw,
153                        struct proc *procp);
154
155void bootpc_init(int update_files);
156
157#ifdef BOOTP_DEBUG
158void bootpboot_p_sa(sa,ma)
159     struct sockaddr *sa;
160     struct sockaddr *ma;
161{
162  if (!sa) {
163    printf("(sockaddr *) <null>");
164    return;
165  }
166  switch (sa->sa_family) {
167  case AF_INET:
168    {
169      struct sockaddr_in *sin = (struct sockaddr_in *) sa;
170      printf("inet %x",ntohl(sin->sin_addr.s_addr));
171      if (ma) {
172        struct sockaddr_in *sin = (struct sockaddr_in *) ma;
173        printf(" mask %x",ntohl(sin->sin_addr.s_addr));
174      }
175    }
176  break;
177  case AF_LINK:
178    {
179      struct sockaddr_dl *sli = (struct sockaddr_dl *) sa;
180      int i;
181      printf("link %.*s ",sli->sdl_nlen,sli->sdl_data);
182      for (i=0;i<sli->sdl_alen;i++) {
183        if (i>0)
184          printf(":");
185        printf("%x",(unsigned char) sli->sdl_data[i+sli->sdl_nlen]);
186      }
187    }
188  break;
189  default:
190    printf("af%d",sa->sa_family);
191  }
192}
193
194void bootpboot_p_ma(ma)
195     struct sockaddr *ma;
196{
197  if (!ma) {
198    printf("<null>");
199    return;
200  }
201  printf("%x",*(int*)ma);
202}
203
204void bootpboot_p_rtentry(rt)
205     struct rtentry *rt;
206{
207  bootpboot_p_sa(rt_key(rt),rt_mask(rt));
208  printf(" ");
209  bootpboot_p_ma(rt->rt_genmask);
210  printf(" ");
211  bootpboot_p_sa(rt->rt_gateway,NULL);
212  printf(" ");
213  printf("flags %x",(unsigned short) rt->rt_flags);
214  printf(" %d",rt->rt_rmx.rmx_expire);
215  printf(" %s%d\n",rt->rt_ifp->if_name,rt->rt_ifp->if_unit);
216}
217void  bootpboot_p_tree(rn)
218     struct radix_node *rn;
219{
220  while (rn) {
221    if (rn->rn_b < 0) {
222      if (rn->rn_flags & RNF_ROOT) {
223      } else {
224        bootpboot_p_rtentry((struct rtentry *) rn);
225      }
226      rn = rn->rn_dupedkey;
227    } else {
228      bootpboot_p_tree(rn->rn_l);
229      bootpboot_p_tree(rn->rn_r);
230      return;
231    }
232   
233  }
234}
235
236void bootpboot_p_rtlist(void)
237{
238  printf("Routing table:\n");
239  bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
240}
241
242void bootpboot_p_iflist(void)
243{
244  struct ifnet *ifp;
245  struct ifaddr *ifa;
246  printf("Interface list:\n");
247  for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link))
248    {
249      for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa;
250           ifa=TAILQ_NEXT(ifa,ifa_link))
251        if (ifa->ifa_addr->sa_family == AF_INET ) {
252          printf("%s%d flags %x, addr %x, bcast %x, net %x\n",
253                 ifp->if_name,ifp->if_unit,
254                 (unsigned short) ifp->if_flags,
255                 ntohl(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr),
256                 ntohl(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr.s_addr),
257                 ntohl(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr)
258                 );
259        }
260    }
261}
262#endif
263
264/*
265 * - determine space needed to store src string
266 * - allocate or reallocate dst, so that string fits in
267 * - copy string from src to dest
268 */
269void *bootp_strdup_realloc(char *dst,const char *src)
270{
271  size_t len;
272  void *realloc(void * __r, size_t __size);
273
274  if (dst == NULL) {
275    /* first allocation, simply use strdup */
276    dst = strdup(src);
277  }
278  else {
279    /* already allocated, so use realloc/strcpy */
280    len = strlen(src) + 1; 
281    dst = realloc(dst,len);
282    if (dst != NULL) {
283      strcpy(dst,src);
284    }
285  }
286  return dst;
287}
288
289int
290bootpc_call(call,reply,procp)
291     struct bootp_packet *call;
292     struct bootp_packet *reply;        /* output */
293     struct proc *procp;
294{
295        struct socket *so;
296        struct sockaddr_in *sin;
297        struct mbuf *m, *nam;
298        struct uio auio;
299        struct iovec aio;
300        int error, rcvflg, timo, secs, len;
301
302        /* Free at end if not null. */
303        nam = NULL;
304
305        /*
306         * Create socket and set its recieve timeout.
307         */
308        if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)))
309                goto out;
310
311        m = m_get(M_WAIT, MT_SOOPTS);
312        if (m == NULL) {
313                error = ENOBUFS;
314                goto out;
315        } else {
316                struct timeval *tv;
317                tv = mtod(m, struct timeval *);
318                m->m_len = sizeof(*tv);
319                tv->tv_sec = 1;
320                tv->tv_usec = 0;
321                if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
322                        goto out;
323        }
324
325        /*
326         * Enable broadcast.
327         */
328        {
329                int *on;
330                m = m_get(M_WAIT, MT_SOOPTS);
331                if (m == NULL) {
332                        error = ENOBUFS;
333                        goto out;
334                }
335                on = mtod(m, int *);
336                m->m_len = sizeof(*on);
337                *on = 1;
338                if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
339                        goto out;
340        }
341
342        /*
343         * Bind the local endpoint to a bootp client port.
344         */
345        m = m_getclr(M_WAIT, MT_SONAME);
346        sin = mtod(m, struct sockaddr_in *);
347        sin->sin_len = m->m_len = sizeof(*sin);
348        sin->sin_family = AF_INET;
349        sin->sin_addr.s_addr = INADDR_ANY;
350        sin->sin_port = htons(IPPORT_BOOTPC);
351        error = sobind(so, m);
352        m_freem(m);
353        if (error) {
354                printf("bind failed\n");
355                goto out;
356        }
357
358        /*
359         * Setup socket address for the server.
360         */
361        nam = m_get(M_WAIT, MT_SONAME);
362        if (nam == NULL) {
363                error = ENOBUFS;
364                goto out;
365        }
366        sin = mtod(nam, struct sockaddr_in *);
367        sin-> sin_len = sizeof(*sin);
368        sin-> sin_family = AF_INET;
369        sin->sin_addr.s_addr = INADDR_BROADCAST;
370        sin->sin_port = htons(IPPORT_BOOTPS);
371
372        nam->m_len = sizeof(*sin);
373
374        /*
375         * Send it, repeatedly, until a reply is received,
376         * but delay each re-send by an increasing amount.
377         * If the delay hits the maximum, start complaining.
378         */
379        timo = 0;
380        for (;;) {
381                /* Send BOOTP request (or re-send). */
382               
383                aio.iov_base = (caddr_t) call;
384                aio.iov_len = sizeof(*call);
385               
386                auio.uio_iov = &aio;
387                auio.uio_iovcnt = 1;
388                auio.uio_segflg = UIO_SYSSPACE;
389                auio.uio_rw = UIO_WRITE;
390                auio.uio_offset = 0;
391                auio.uio_resid = sizeof(*call);
392                auio.uio_procp = procp;
393
394                error = sosend(so, nam, &auio, NULL, NULL, 0);
395                if (error) {
396                        printf("bootpc_call: sosend: %d\n", error);
397                        goto out;
398                }
399
400                /* Determine new timeout. */
401                if (timo < MAX_RESEND_DELAY)
402                        timo++;
403                else
404                        printf("BOOTP timeout for server 0x%x\n",
405                               (int)ntohl(sin->sin_addr.s_addr));
406
407                /*
408                 * Wait for up to timo seconds for a reply.
409                 * The socket receive timeout was set to 1 second.
410                 */
411                secs = timo;
412                while (secs > 0) {
413                        aio.iov_base = (caddr_t) reply;
414                        aio.iov_len = sizeof(*reply);
415
416                        auio.uio_iov = &aio;
417                        auio.uio_iovcnt = 1;
418                        auio.uio_segflg = UIO_SYSSPACE;
419                        auio.uio_rw = UIO_READ;
420                        auio.uio_offset = 0;
421                        auio.uio_resid = sizeof(*reply);
422                        auio.uio_procp = procp;
423                       
424                        rcvflg = 0;
425                        error = soreceive(so, NULL, &auio, NULL, NULL, &rcvflg);
426                        if (error == EWOULDBLOCK) {
427                                secs--;
428                                call->secs=htons(ntohs(call->secs)+1);
429                                continue;
430                        }
431                        if (error)
432                                goto out;
433                        len = sizeof(*reply) - auio.uio_resid;
434
435                        /* Do we have the required number of bytes ? */
436                        if (len < BOOTP_MIN_LEN)
437                                continue;
438
439                        /* Is it the right reply? */
440                        if (reply->op != 2)
441                          continue;
442
443                        if (reply->xid != call->xid)
444                                continue;
445
446                        if (reply->hlen != call->hlen)
447                          continue;
448
449                        if (bcmp(reply->chaddr,call->chaddr,call->hlen))
450                          continue;
451
452                        goto gotreply;  /* break two levels */
453
454                } /* while secs */
455        } /* forever send/receive */
456
457        error = ETIMEDOUT;
458        goto out;
459
460 gotreply:
461 out:
462        if (nam) m_freem(nam);
463        soclose(so);
464        return error;
465}
466
467int
468bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
469                        struct proc *procp)
470{
471  struct sockaddr_in *sin;
472  int error;
473  struct sockaddr_in dst;
474  struct sockaddr_in gw;
475  struct sockaddr_in mask;
476
477  /*
478   * Bring up the interface.
479   *
480   * Get the old interface flags and or IFF_UP into them; if
481   * IFF_UP set blindly, interface selection can be clobbered.
482   */
483  error = ifioctl(so, SIOCGIFFLAGS, (caddr_t)ireq, procp);
484  if (error)
485    panic("bootpc_fakeup_interface: GIFFLAGS, error=%d", error);
486  ireq->ifr_flags |= IFF_UP;
487  error = ifioctl(so, SIOCSIFFLAGS, (caddr_t)ireq, procp);
488  if (error)
489    panic("bootpc_fakeup_interface: SIFFLAGS, error=%d", error);
490
491  /*
492   * Do enough of ifconfig(8) so that the chosen interface
493   * can talk to the servers.  (just set the address)
494   */
495 
496  /* addr is 0.0.0.0 */
497 
498  sin = (struct sockaddr_in *)&ireq->ifr_addr;
499  bzero((caddr_t)sin, sizeof(*sin));
500  sin->sin_len = sizeof(*sin);
501  sin->sin_family = AF_INET;
502  sin->sin_addr.s_addr = INADDR_ANY;
503  error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp);
504  if (error)
505    panic("bootpc_fakeup_interface: set if addr, error=%d", error);
506 
507  /* netmask is 0.0.0.0 */
508 
509  sin = (struct sockaddr_in *)&ireq->ifr_addr;
510  bzero((caddr_t)sin, sizeof(*sin));
511  sin->sin_len = sizeof(*sin);
512  sin->sin_family = AF_INET;
513  sin->sin_addr.s_addr = INADDR_ANY;
514  error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp);
515  if (error)
516    panic("bootpc_fakeup_interface: set if net addr, error=%d", error);
517 
518  /* Broadcast is 255.255.255.255 */
519 
520  sin = (struct sockaddr_in *)&ireq->ifr_addr;
521  bzero((caddr_t)sin, sizeof(*sin));
522  sin->sin_len = sizeof(*sin);
523  sin->sin_family = AF_INET;
524  sin->sin_addr.s_addr = INADDR_BROADCAST;
525  error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp);
526  if (error)
527    panic("bootpc_fakeup_interface: set if broadcast addr, error=%d", error);
528 
529  /* Add default route to 0.0.0.0 so we can send data */
530 
531  bzero((caddr_t) &dst, sizeof(dst));
532  dst.sin_len=sizeof(dst);
533  dst.sin_family=AF_INET;
534  dst.sin_addr.s_addr = htonl(0);
535 
536  bzero((caddr_t) &gw, sizeof(gw));
537  gw.sin_len=sizeof(gw);
538  gw.sin_family=AF_INET;
539  gw.sin_addr.s_addr = htonl(0x0);
540 
541  bzero((caddr_t) &mask, sizeof(mask));
542  mask.sin_len=sizeof(mask);
543  mask.sin_family=AF_INET;
544  mask.sin_addr.s_addr = htonl(0);
545 
546  error = rtrequest(RTM_ADD,
547                    (struct sockaddr *) &dst,
548                    (struct sockaddr *) &gw,
549                    (struct sockaddr *) &mask,
550                    RTF_UP | RTF_STATIC
551                    , NULL);
552  if (error)
553    printf("bootpc_fakeup_interface: add default route, error=%d\n", error);
554  return error;
555}
556
557int
558bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
559                        struct sockaddr_in *myaddr,
560                        struct sockaddr_in *netmask,
561                        struct sockaddr_in *gw,
562                        struct proc *procp)
563{
564  int error;
565  struct sockaddr_in oldgw;
566  struct sockaddr_in olddst;
567  struct sockaddr_in oldmask;
568  struct sockaddr_in *sin;
569
570  /* Remove old default route to 0.0.0.0 */
571 
572  bzero((caddr_t) &olddst, sizeof(olddst));
573  olddst.sin_len=sizeof(olddst);
574  olddst.sin_family=AF_INET;
575  olddst.sin_addr.s_addr = INADDR_ANY;
576 
577  bzero((caddr_t) &oldgw, sizeof(oldgw));
578  oldgw.sin_len=sizeof(oldgw);
579  oldgw.sin_family=AF_INET;
580  oldgw.sin_addr.s_addr = INADDR_ANY;
581 
582  bzero((caddr_t) &oldmask, sizeof(oldmask));
583  oldmask.sin_len=sizeof(oldmask);
584  oldmask.sin_family=AF_INET;
585  oldmask.sin_addr.s_addr = INADDR_ANY;
586 
587  error = rtrequest(RTM_DELETE,
588                    (struct sockaddr *) &olddst,
589                    (struct sockaddr *) &oldgw,
590                    (struct sockaddr *) &oldmask,
591                    (RTF_UP | RTF_STATIC), NULL);
592  if (error) {
593    printf("nfs_boot: del default route, error=%d\n", error);
594    return error;
595  }
596
597  /*
598   * Do enough of ifconfig(8) so that the chosen interface
599   * can talk to the servers.  (just set the address)
600   */
601  bcopy(netmask,&ireq->ifr_addr,sizeof(*netmask));
602  error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ireq, procp);
603  if (error)
604    panic("nfs_boot: set if netmask, error=%d", error);
605
606  /* Broadcast is with host part of IP address all 1's */
607 
608  sin = (struct sockaddr_in *)&ireq->ifr_addr;
609  bzero((caddr_t)sin, sizeof(*sin));
610  sin->sin_len = sizeof(*sin);
611  sin->sin_family = AF_INET;
612  sin->sin_addr.s_addr = myaddr->sin_addr.s_addr | ~ netmask->sin_addr.s_addr;
613  error = ifioctl(so, SIOCSIFBRDADDR, (caddr_t)ireq, procp);
614  if (error)
615    panic("bootpc_call: set if broadcast addr, error=%d", error);
616 
617  bcopy(myaddr,&ireq->ifr_addr,sizeof(*myaddr));
618  error = ifioctl(so, SIOCSIFADDR, (caddr_t)ireq, procp);
619  if (error)
620    panic("nfs_boot: set if addr, error=%d", error);
621
622  /* Add new default route */
623
624  error = rtrequest(RTM_ADD,
625                    (struct sockaddr *) &olddst,
626                    (struct sockaddr *) gw,
627                    (struct sockaddr *) &oldmask,
628                    (RTF_UP | RTF_GATEWAY | RTF_STATIC), NULL);
629  if (error) {
630    printf("nfs_boot: add net route, error=%d\n", error);
631    return error;
632  }
633
634  return 0;
635}
636
637#if !defined(__rtems__)
638static int setfs(addr, path, p)
639        struct sockaddr_in *addr;
640        char *path;
641        char *p;
642{
643        unsigned ip = 0;
644        int val;
645
646        if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
647        ip = val << 24;
648        if (*p != '.') return(0);
649        p++;
650        if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
651        ip |= (val << 16);
652        if (*p != '.') return(0);
653        p++;
654        if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
655        ip |= (val << 8);
656        if (*p != '.') return(0);
657        p++;
658        if (((val = getdec(&p)) < 0) || (val > 255)) return(0);
659        ip |= val;
660        if (*p != ':') return(0);
661        p++;
662
663        addr->sin_addr.s_addr = htonl(ip);
664        addr->sin_len = sizeof(struct sockaddr_in);
665        addr->sin_family = AF_INET;
666
667        strncpy(path,p,MNAMELEN-1);
668        return(1);
669}
670#endif
671
672static int getdec(ptr)
673        char **ptr;
674{
675        char *p = *ptr;
676        int ret=0;
677        if ((*p < '0') || (*p > '9')) return(-1);
678        while ((*p >= '0') && (*p <= '9')) {
679                ret = ret*10 + (*p - '0');
680                p++;
681        }
682        *ptr = p;
683        return(ret);
684}
685
686static char *substr(a,b)
687        char *a,*b;
688{
689        char *loc1;
690        char *loc2;
691
692        while (*a != '\0') {
693                loc1 = a;
694                loc2 = b;
695                while (*loc1 == *loc2++) {
696                        if (*loc1 == '\0') return (0);
697                        loc1++;
698                        if (*loc2 == '\0') return (loc1);
699                }
700        a++;
701        }
702        return (0);
703}
704
705static void printip(char *prefix,struct in_addr addr)
706{
707  unsigned int ip;
708
709  ip = ntohl(addr.s_addr);
710
711  printf("%s is %d.%d.%d.%d\n",prefix,
712         ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 );
713}
714
715static int dhcpOptionOverload = 0;
716static char dhcp_gotgw = 0;
717static char dhcp_gotnetmask = 0;
718static char dhcp_gotserver = 0;
719static char dhcp_gotlogserver = 0;
720static struct sockaddr_in dhcp_netmask;
721static struct sockaddr_in dhcp_gw;
722static char *dhcp_hostname = NULL;
723
724static void
725processOptions (unsigned char *optbuf, int optbufSize)
726{
727  int j = 0;
728  int len;
729  int code, ncode;
730  char *p;
731
732  ncode = optbuf[0];
733  while (j < optbufSize) {
734    code = optbuf[j] = ncode;
735    if (code == 255)
736      return;
737    if (code == 0) {
738      j++;
739      continue;
740    }
741    len = optbuf[j+1];
742    j += 2;
743    if ((len + j) >= optbufSize) {
744      printf ("Truncated field for code %d", code);
745      return;
746    }
747    ncode = optbuf[j+len];
748    optbuf[j+len] = '\0';
749    p = &optbuf[j];
750    j += len;
751
752    /*
753     * Process the option
754     */
755    switch (code) {
756    case 1:
757      /* Subnet mask */
758      if (len!=4)
759        panic("bootpc: subnet mask len is %d",len);
760      bcopy (p, &dhcp_netmask.sin_addr, 4);
761      dhcp_gotnetmask = 1;
762      break;
763
764    case 2:
765      /* Time offset */
766      if (len!=4)
767        panic("bootpc: time offset len is %d",len);
768      bcopy (p, &rtems_bsdnet_timeoffset, 4);
769      rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
770      break;
771
772    case 3:
773      /* Routers */
774      if (len % 4)
775        panic ("bootpc: Router Len is %d", len);
776      if (len > 0) {
777        bcopy(p, &dhcp_gw.sin_addr, 4);
778        dhcp_gotgw = 1;
779      }
780      break;
781
782    case 42:
783      /* NTP servers */
784      if (len % 4)
785        panic ("bootpc: time server Len is %d", len);
786      {
787      int tlen = 0;
788      while ((tlen < len) &&
789             (rtems_bsdnet_ntpserver_count < sizeof rtems_bsdnet_config.ntp_server /
790             sizeof rtems_bsdnet_config.ntp_server[0])) {
791        bcopy (p+tlen,
792                &rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
793                4);
794        printip("Time Server",
795          rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count]);
796        rtems_bsdnet_ntpserver_count++;
797        tlen += 4;
798      }
799      }
800      break;
801
802    case 6:
803      /* Domain Name servers */
804      if (len % 4)
805        panic ("bootpc: DNS Len is %d", len);
806      {
807      int dlen = 0;
808      while ((dlen < len) &&
809             (rtems_bsdnet_nameserver_count < sizeof rtems_bsdnet_config.name_server /
810        sizeof rtems_bsdnet_config.name_server[0])) {
811        bcopy (p+dlen,
812        &rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count],
813        4);
814        printip("Domain Name Server",
815          rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count]);
816        rtems_bsdnet_nameserver_count++;
817        dlen += 4;
818      }
819      }
820      break;
821
822    case 12:
823      /* Host name */
824      if (len>=MAXHOSTNAMELEN)
825        panic ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN);
826      if (sethostname (p, len) < 0)
827        panic("Can't set host name");
828      printf("Hostname is %s\n", p);
829      dhcp_hostname = bootp_strdup_realloc(dhcp_hostname,p);
830      break;
831
832    case 7:
833      /* Log servers */
834      if (len % 4)
835        panic ("bootpc: Log server Len is %d", len);
836      if (len > 0) {
837        bcopy(p, &rtems_bsdnet_log_host_address, 4);
838        dhcp_gotlogserver = 1;
839      }
840      break;
841
842    case 15:
843      /* Domain name */
844      if (p[0]) {
845        rtems_bsdnet_domain_name =
846          bootp_strdup_realloc(rtems_bsdnet_domain_name,p);
847        printf("Domain name is %s\n", rtems_bsdnet_domain_name);
848      }
849      break;
850
851    case 16:  /* Swap server IP address. unused */
852      break;
853
854    case 52:
855      /* DHCP option override */
856      if (len != 1)
857        panic ("bootpc: DHCP option overload len is %d", len);
858      dhcpOptionOverload = p[0];
859      break;
860
861    case 128: /* Site-specific option for DHCP servers that
862               *   a) don't supply tag 54
863               * and
864               *   b) don't supply the server address in siaddr
865               * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
866               *    Bootsrv s Site,128,IP,1,1
867               * and use that symbol in the macro that defines the client:
868               *    Bootsrv=<tftp-server-ip-address>
869               */
870    case 54:
871      /* DHCP server */
872      if (len != 4)
873        panic ("bootpc: DHCP server len is %d", len);
874      bcopy(p, &rtems_bsdnet_bootp_server_address, 4);
875      dhcp_gotserver = 1;
876      break;
877
878    case 66:
879      /* DHCP server name option */
880      if (p[0])
881        rtems_bsdnet_bootp_server_name =
882          bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,p);
883      break;
884
885    case 67:
886      /* DHCP bootfile option */
887      if (p[0])
888        rtems_bsdnet_bootp_boot_file_name =
889          bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,p);
890      break;
891
892    default:
893      printf ("Ignoring BOOTP/DHCP option code %d\n", code);
894      break;
895    }
896  }
897}
898
899#define EALEN 6
900
901void
902bootpc_init(int update_files)
903{
904  struct bootp_packet call;
905  struct bootp_packet reply;
906  static u_int32_t xid = ~0xFF;
907 
908  struct ifreq ireq;
909  struct ifnet *ifp;
910  struct socket *so;
911  int j;
912  int error;
913  struct sockaddr_in myaddr;
914  struct ifaddr *ifa;
915  struct sockaddr_dl *sdl = NULL;
916  char *delim;
917  struct proc *procp = NULL;
918
919  /*
920   * If already filled in, don't touch it here
921   */
922  if (nfs_diskless_valid)
923    return;
924
925  /*
926   * If we are to update the files create the root
927   * file structure.
928   */
929  if (update_files)
930    if (rtems_create_root_fs () < 0) {
931      printf("Error creating the root filesystem.\nFile not created.\n");
932      update_files = 0;
933    }
934
935  dhcp_hostname = NULL;
936
937  /*
938   * Find a network interface.
939   */
940  for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
941    if ((ifp->if_flags &
942      (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
943        break;
944  if (ifp == NULL)
945    panic("bootpc_init: no suitable interface");
946  bzero(&ireq,sizeof(ireq));
947  sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit);
948  printf("bootpc_init: using network interface '%s'\n",
949         ireq.ifr_name);
950
951  if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0)
952    panic("nfs_boot: socreate, error=%d", error);
953         
954  bootpc_fakeup_interface(&ireq,so,procp);
955
956  printf("Bootpc testing starting\n");
957 
958  /* Get HW address */
959
960  for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next)
961    if (ifa->ifa_addr->sa_family == AF_LINK &&
962        (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
963        sdl->sdl_type == IFT_ETHER)
964      break;
965 
966  if (!sdl)
967    panic("bootpc: Unable to find HW address");
968  if (sdl->sdl_alen != EALEN )
969    panic("bootpc: HW address len is %d, expected value is %d",
970          sdl->sdl_alen,EALEN);
971
972  printf("bootpc hw address is ");
973  delim="";
974  for (j=0;j<sdl->sdl_alen;j++) {
975    printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]);
976    delim=":";
977  }
978  printf("\n");
979
980#if 0
981  bootpboot_p_iflist();
982  bootpboot_p_rtlist();
983#endif
984 
985  bzero((caddr_t) &call, sizeof(call));
986
987  /* bootpc part */
988  call.op = 1;                  /* BOOTREQUEST */
989  call.htype= 1;                /* 10mb ethernet */
990  call.hlen=sdl->sdl_alen;      /* Hardware address length */
991  call.hops=0; 
992  xid++;
993  call.xid = txdr_unsigned(xid);
994  bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
995 
996  call.vend[0]=99;
997  call.vend[1]=130;
998  call.vend[2]=83;
999  call.vend[3]=99;
1000  call.vend[4]=255;
1001 
1002  call.secs = 0;
1003  call.flags = htons(0x8000); /* We need an broadcast answer */
1004 
1005  error = bootpc_call(&call,&reply,procp);
1006 
1007  if (error)
1008    panic("BOOTP call failed -- error %d", error);
1009 
1010  /*
1011   * Initialize network address structures
1012   */
1013  bzero(&myaddr,sizeof(myaddr));
1014  bzero(&dhcp_netmask,sizeof(dhcp_netmask));
1015  bzero(&dhcp_gw,sizeof(dhcp_gw));
1016  myaddr.sin_len = sizeof(myaddr);
1017  myaddr.sin_family = AF_INET;
1018  dhcp_netmask.sin_len = sizeof(dhcp_netmask);
1019  dhcp_netmask.sin_family = AF_INET;
1020  dhcp_gw.sin_len = sizeof(dhcp_gw);
1021  dhcp_gw.sin_family= AF_INET;
1022
1023  /*
1024   * Set our address
1025   */
1026  myaddr.sin_addr = reply.yiaddr;
1027  printip("My ip address",myaddr.sin_addr);
1028
1029  /*
1030   * Process BOOTP/DHCP options
1031   */
1032  if (reply.vend[0]==99 && reply.vend[1]==130 &&
1033      reply.vend[2]==83 && reply.vend[3]==99) {
1034    processOptions (&reply.vend[4], sizeof(reply.vend) - 4);
1035  }
1036  if (dhcpOptionOverload & 1) {
1037    processOptions (reply.file, sizeof reply.file);
1038  }
1039  else {
1040    if (reply.file[0])
1041      rtems_bsdnet_bootp_boot_file_name =
1042        bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,reply.file);
1043  }
1044  if (dhcpOptionOverload & 2) {
1045    processOptions (reply.sname, sizeof reply.sname);
1046  }
1047  else {
1048    if (reply.sname[0])
1049      rtems_bsdnet_bootp_server_name =
1050        bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,reply.sname);
1051  }
1052  if (rtems_bsdnet_bootp_server_name)
1053    printf ("Server name is %s\n", rtems_bsdnet_bootp_server_name);
1054  if (rtems_bsdnet_bootp_boot_file_name)
1055    printf ("Boot file is %s\n", rtems_bsdnet_bootp_boot_file_name);
1056
1057  /*
1058   * Use defaults if values were not supplied by BOOTP/DHCP options
1059   */
1060  if (!dhcp_gotnetmask) {
1061    if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr)))
1062      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1063    else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr)))
1064      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1065    else
1066      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1067  }
1068  printip ("Subnet mask", dhcp_netmask.sin_addr);
1069  if (!dhcp_gotserver)
1070   rtems_bsdnet_bootp_server_address = reply.siaddr;
1071  printip ("Server ip address" ,rtems_bsdnet_bootp_server_address);
1072  if (!dhcp_gotgw)
1073    dhcp_gw.sin_addr = reply.giaddr;
1074  printip ("Gateway ip address", dhcp_gw.sin_addr);
1075  if (!dhcp_gotlogserver)
1076    rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
1077  printip ("Log server ip address", rtems_bsdnet_log_host_address);
1078
1079  /*
1080   * Update the files if we are asked too.
1081   */
1082  if (update_files) {
1083    char *dn = rtems_bsdnet_domain_name;
1084    char *hn = dhcp_hostname;
1085    if (!dn)
1086      dn = "mydomain";
1087    if (!hn)
1088      hn = "me";
1089    rtems_rootfs_append_host_rec(*((unsigned long*) &myaddr.sin_addr), hn, dn);
1090
1091    /*
1092     * Should the given domainname be used here ?
1093     */
1094    if (dhcp_gotserver) {
1095      if (rtems_bsdnet_bootp_server_name)
1096        hn = rtems_bsdnet_bootp_server_name;
1097      else
1098        hn = "bootps";
1099      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_bootp_server_address),
1100                                   hn, dn);
1101    }
1102
1103    if (dhcp_gotlogserver) {
1104      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_log_host_address),
1105                                   "logs", dn);
1106    }
1107
1108    /*
1109     * Setup the DNS configuration file /etc/resolv.conf.
1110     */
1111    if (rtems_bsdnet_nameserver_count) {
1112      int        i;
1113      char       buf[64];
1114      const char *bufl[1];
1115
1116      bufl[0] = buf;
1117     
1118#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
1119     
1120      if (rtems_bsdnet_domain_name &&
1121          (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) {
1122        strcpy(buf, "search ");
1123        strcat(buf, rtems_bsdnet_domain_name);
1124        strcat(buf, "\n");
1125        rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl);
1126      }
1127
1128      for (i = 0; i < rtems_bsdnet_nameserver_count; i++) {
1129        strcpy(buf, "nameserver ");
1130        strcat(buf, inet_ntoa(rtems_bsdnet_ntpserver[i]));
1131        strcat(buf, "\n");
1132        if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl))
1133          break;
1134      }
1135    }
1136  }
1137
1138  /*
1139   * Configure the interface with the new settings
1140   */
1141  error = bootpc_adjust_interface(&ireq,so,
1142                                  &myaddr,&dhcp_netmask,&dhcp_gw,procp);
1143  soclose(so);
1144}
Note: See TracBrowser for help on using the repository browser.