source: rtems/cpukit/libnetworking/nfs/bootp_subr.c @ bc100edf

4.104.114.84.9
Last change on this file since bc100edf was bc100edf, checked in by Ralf Corsepius <ralf.corsepius@…>, on Sep 16, 2005 at 6:17:00 AM

Remove superfluous includes.

  • Property mode set to 100644
File size: 29.8 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/mount.h>
51#include <sys/mbuf.h>
52#include <sys/proc.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/nfsproto.h>
66#include <nfsclient/nfsargs.h>
67#include <nfsclient/nfsdiskless.h>
68#include <nfs/xdr_subs.h>
69
70#include <fcntl.h>
71#include <rtems/mkrootfs.h>
72#include <rtems/rtems_bsdnet.h>
73#include <rtems/bsdnet/servers.h>
74
75#define BOOTP_MIN_LEN           300     /* Minimum size of bootp udp packet */
76
77/*
78 * What is the longest we will wait before re-sending a request?
79 * Note this is also the frequency of "RPC timeout" messages.
80 * The re-send loop count sup linearly to this maximum, so the
81 * first complaint will happen after (1+2+3+4+5)=15 seconds.
82 */
83#define MAX_RESEND_DELAY 5      /* seconds */
84
85/* Definitions from RFC951 */
86struct bootp_packet {
87  u_int8_t op;
88  u_int8_t htype;
89  u_int8_t hlen;
90  u_int8_t hops;
91  u_int32_t xid;
92  u_int16_t secs;
93  u_int16_t flags;
94  struct in_addr ciaddr;
95  struct in_addr yiaddr;
96  struct in_addr siaddr;
97  struct in_addr giaddr;
98  unsigned char chaddr[16];
99  char sname[64];
100  char file[128];
101  unsigned char vend[256];
102};
103
104#define IPPORT_BOOTPC 68
105#define IPPORT_BOOTPS 67
106
107extern int nfs_diskless_valid;
108extern struct nfsv3_diskless nfsv3_diskless;
109
110/* mountd RPC */
111#if !defined(__rtems__)
112static int md_mount __P((struct sockaddr_in *mdsin, char *path,
113        u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp));
114static int md_lookup_swap __P((struct sockaddr_in *mdsin,char *path,
115                               u_char *fhp, int *fhsizep, 
116                               struct nfs_args *args,
117                               struct proc *procp));
118static int setfs __P((struct sockaddr_in *addr, char *path, char *p));
119static int getdec __P((char **ptr));
120#endif
121#if !defined(__rtems__)
122static char *substr __P((char *a,char *b));
123static void mountopts __P((struct nfs_args *args, char *p)); 
124static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf,
125                                  int len));
126static int xdr_int_decode __P((struct mbuf **ptr,int *iptr));
127#endif
128static void printip __P((char *prefix,struct in_addr addr));
129
130#ifdef BOOTP_DEBUG
131void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
132void bootpboot_p_ma(struct sockaddr *ma);
133void bootpboot_p_rtentry(struct rtentry *rt);
134void bootpboot_p_tree(struct radix_node *rn);
135void bootpboot_p_rtlist(void);
136void bootpboot_p_iflist(void);
137#endif
138
139int  bootpc_call(struct bootp_packet *call,
140                 struct bootp_packet *reply,
141                 struct proc *procp);
142
143int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
144                        struct proc *procp);
145
146int 
147bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
148                        struct sockaddr_in *myaddr,
149                        struct sockaddr_in *netmask,
150                        struct sockaddr_in *gw,
151                        struct proc *procp);
152
153void bootpc_init(int update_files);
154
155#ifdef BOOTP_DEBUG
156void bootpboot_p_sa(sa,ma)
157     struct sockaddr *sa;
158     struct sockaddr *ma;
159{
160  if (!sa) {
161    printf("(sockaddr *) <null>");
162    return;
163  }
164  switch (sa->sa_family) {
165  case AF_INET:
166    {
167      struct sockaddr_in *sin = (struct sockaddr_in *) sa;
168      printf("inet %x",ntohl(sin->sin_addr.s_addr));
169      if (ma) {
170        struct sockaddr_in *sin = (struct sockaddr_in *) ma;
171        printf(" mask %x",ntohl(sin->sin_addr.s_addr));
172      }
173    }
174  break;
175  case AF_LINK:
176    {
177      struct sockaddr_dl *sli = (struct sockaddr_dl *) sa;
178      int i;
179      printf("link %.*s ",sli->sdl_nlen,sli->sdl_data);
180      for (i=0;i<sli->sdl_alen;i++) {
181        if (i>0)
182          printf(":");
183        printf("%x",(unsigned char) sli->sdl_data[i+sli->sdl_nlen]);
184      }
185    }
186  break;
187  default:
188    printf("af%d",sa->sa_family);
189  }
190}
191
192void bootpboot_p_ma(ma)
193     struct sockaddr *ma;
194{
195  if (!ma) {
196    printf("<null>");
197    return;
198  }
199  printf("%x",*(int*)ma);
200}
201
202void bootpboot_p_rtentry(rt)
203     struct rtentry *rt;
204{
205  bootpboot_p_sa(rt_key(rt),rt_mask(rt));
206  printf(" ");
207  bootpboot_p_ma(rt->rt_genmask);
208  printf(" ");
209  bootpboot_p_sa(rt->rt_gateway,NULL);
210  printf(" ");
211  printf("flags %x",(unsigned short) rt->rt_flags);
212  printf(" %d",rt->rt_rmx.rmx_expire);
213  printf(" %s%d\n",rt->rt_ifp->if_name,rt->rt_ifp->if_unit);
214}
215void  bootpboot_p_tree(rn)
216     struct radix_node *rn;
217{
218  while (rn) {
219    if (rn->rn_b < 0) {
220      if (rn->rn_flags & RNF_ROOT) {
221      } else {
222        bootpboot_p_rtentry((struct rtentry *) rn);
223      }
224      rn = rn->rn_dupedkey;
225    } else {
226      bootpboot_p_tree(rn->rn_l);
227      bootpboot_p_tree(rn->rn_r);
228      return;
229    }
230   
231  }
232}
233
234void bootpboot_p_rtlist(void)
235{
236  printf("Routing table:\n");
237  bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
238}
239
240void bootpboot_p_iflist(void)
241{
242  struct ifnet *ifp;
243  struct ifaddr *ifa;
244  printf("Interface list:\n");
245  for (ifp = TAILQ_FIRST(&ifnet); ifp != 0; ifp = TAILQ_NEXT(ifp,if_link))
246    {
247      for (ifa = TAILQ_FIRST(&ifp->if_addrhead) ;ifa; 
248           ifa=TAILQ_NEXT(ifa,ifa_link))
249        if (ifa->ifa_addr->sa_family == AF_INET ) {
250          printf("%s%d flags %x, addr %x, bcast %x, net %x\n",
251                 ifp->if_name,ifp->if_unit,
252                 (unsigned short) ifp->if_flags,
253                 ntohl(((struct sockaddr_in *) ifa->ifa_addr)->sin_addr.s_addr),
254                 ntohl(((struct sockaddr_in *) ifa->ifa_dstaddr)->sin_addr.s_addr),
255                 ntohl(((struct sockaddr_in *) ifa->ifa_netmask)->sin_addr.s_addr)
256                 );
257        }
258    }
259}
260#endif
261
262/*
263 * - determine space needed to store src string
264 * - allocate or reallocate dst, so that string fits in
265 * - copy string from src to dest
266 */
267void *bootp_strdup_realloc(char *dst,const char *src)
268{
269  size_t len;
270  void *realloc(void * __r, size_t __size);
271
272  if (dst == NULL) {
273    /* first allocation, simply use strdup */
274        if (src)
275        dst = strdup(src);
276  }
277  else {
278    /* already allocated, so use realloc/strcpy */
279    len = src ? strlen(src) + 1 : 0; 
280        /* src == NULL tells us to effectively free dst */
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
672#if !defined(__rtems__)
673static int getdec(ptr)
674        char **ptr;
675{
676        char *p = *ptr;
677        int ret=0;
678        if ((*p < '0') || (*p > '9')) return(-1);
679        while ((*p >= '0') && (*p <= '9')) {
680                ret = ret*10 + (*p - '0');
681                p++;
682        }
683        *ptr = p;
684        return(ret);
685}
686#endif
687
688#if !defined(__rtems__)
689static char *substr(a,b)
690        char *a,*b;
691{
692        char *loc1;
693        char *loc2;
694
695        while (*a != '\0') {
696                loc1 = a;
697                loc2 = b;
698                while (*loc1 == *loc2++) {
699                        if (*loc1 == '\0') return (0);
700                        loc1++;
701                        if (*loc2 == '\0') return (loc1);
702                }
703        a++;
704        }
705        return (0);
706}
707#endif
708
709static void printip(char *prefix,struct in_addr addr)
710{
711  unsigned int ip;
712
713  ip = ntohl(addr.s_addr);
714
715  printf("%s is %d.%d.%d.%d\n",prefix,
716         ip >> 24, (ip >> 16) & 255 ,(ip >> 8) & 255 ,ip & 255 );
717}
718
719static int dhcpOptionOverload = 0;
720static char dhcp_gotgw = 0;
721static char dhcp_gotnetmask = 0;
722static char dhcp_gotserver = 0;
723static char dhcp_gotlogserver = 0;
724static struct sockaddr_in dhcp_netmask;
725static struct sockaddr_in dhcp_gw;
726static char *dhcp_hostname = NULL;
727
728static void
729processOptions (unsigned char *optbuf, int optbufSize)
730{
731  int j = 0;
732  int len;
733  int code, ncode;
734  unsigned char *p;
735
736  ncode = optbuf[0];
737  while (j < optbufSize) {
738    code = optbuf[j] = ncode;
739    if (code == 255)
740      return;
741    if (code == 0) {
742      j++;
743      continue;
744    }
745    len = optbuf[j+1];
746    j += 2;
747    if ((len + j) >= optbufSize) {
748      printf ("Truncated field for code %d", code);
749      return;
750    }
751    ncode = optbuf[j+len];
752    optbuf[j+len] = '\0';
753    p = &optbuf[j];
754    j += len;
755
756    /*
757     * Process the option
758     */
759    switch (code) {
760    case 1:
761      /* Subnet mask */
762      if (len!=4) 
763        panic("bootpc: subnet mask len is %d",len);
764      bcopy (p, &dhcp_netmask.sin_addr, 4);
765      dhcp_gotnetmask = 1;
766      break;
767
768    case 2:
769      /* Time offset */
770      if (len!=4) 
771        panic("bootpc: time offset len is %d",len);
772      bcopy (p, &rtems_bsdnet_timeoffset, 4);
773      rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
774      break;
775
776    case 3:
777      /* Routers */
778      if (len % 4) 
779        panic ("bootpc: Router Len is %d", len);
780      if (len > 0) {
781        bcopy(p, &dhcp_gw.sin_addr, 4);
782        dhcp_gotgw = 1;
783      }
784      break;
785
786    case 42:
787      /* NTP servers */
788      if (len % 4) 
789        panic ("bootpc: time server Len is %d", len);
790      {
791      int tlen = 0;
792      while ((tlen < len) &&
793             (rtems_bsdnet_ntpserver_count < sizeof rtems_bsdnet_config.ntp_server /
794             sizeof rtems_bsdnet_config.ntp_server[0])) {
795        bcopy (p+tlen,
796                &rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
797                4);
798        printip("Time Server",
799          rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count]);
800        rtems_bsdnet_ntpserver_count++;
801        tlen += 4;
802      }
803      }
804      break;
805
806    case 6:
807      /* Domain Name servers */
808      if (len % 4) 
809        panic ("bootpc: DNS Len is %d", len);
810      {
811      int dlen = 0;
812      while ((dlen < len) &&
813             (rtems_bsdnet_nameserver_count < sizeof rtems_bsdnet_config.name_server /
814        sizeof rtems_bsdnet_config.name_server[0])) {
815        bcopy (p+dlen,
816        &rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count],
817        4);
818        printip("Domain Name Server",
819          rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count]);
820        rtems_bsdnet_nameserver_count++;
821        dlen += 4;
822      }
823      }
824      break;
825
826    case 12:
827      /* Host name */
828      if (len>=MAXHOSTNAMELEN)
829        panic ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN);
830      if (sethostname ((char *)p, len) < 0)
831        panic("Can't set host name");
832      printf("Hostname is %s\n", p);
833      dhcp_hostname = bootp_strdup_realloc(dhcp_hostname,(char *)p);
834      break;
835
836    case 7:
837      /* Log servers */
838      if (len % 4) 
839        panic ("bootpc: Log server Len is %d", len);
840      if (len > 0) {
841        bcopy(p, &rtems_bsdnet_log_host_address, 4);
842        dhcp_gotlogserver = 1;
843      }
844      break;
845
846    case 15:
847      /* Domain name */
848      if (p[0]) {
849        rtems_bsdnet_domain_name = 
850          bootp_strdup_realloc(rtems_bsdnet_domain_name,(char *)p);
851        printf("Domain name is %s\n", rtems_bsdnet_domain_name);
852      }
853      break;
854
855    case 16:  /* Swap server IP address. unused */
856      break;
857
858    case 52:
859      /* DHCP option override */
860      if (len != 1) 
861        panic ("bootpc: DHCP option overload len is %d", len);
862      dhcpOptionOverload = p[0];
863      break;
864
865    case 128: /* Site-specific option for DHCP servers that
866               *   a) don't supply tag 54
867               * and
868               *   b) don't supply the server address in siaddr
869               * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
870               *    Bootsrv s Site,128,IP,1,1
871               * and use that symbol in the macro that defines the client:
872               *    Bootsrv=<tftp-server-ip-address>
873               */
874    case 54:
875      /* DHCP server */
876      if (len != 4) 
877        panic ("bootpc: DHCP server len is %d", len);
878      bcopy(p, &rtems_bsdnet_bootp_server_address, 4);
879      dhcp_gotserver = 1;
880      break;
881
882    case 66:
883      /* DHCP server name option */
884      if (p[0])
885        rtems_bsdnet_bootp_server_name = 
886          bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,(char *)p);
887      break;
888
889    case 67:
890      /* DHCP bootfile option */
891      if (p[0])
892        rtems_bsdnet_bootp_boot_file_name = 
893          bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,(char *)p);
894      break;
895
896        case 129:
897          /* Site specific option; we use this to get
898           * a 'command line string'
899           */
900          if (p[0])
901                rtems_bsdnet_bootp_cmdline = strdup((char *)p);
902          break;
903
904    default:
905      printf ("Ignoring BOOTP/DHCP option code %d\n", code);
906      break;
907    }
908  }
909}
910
911#define EALEN 6
912
913void
914bootpc_init(int update_files)
915{
916  struct bootp_packet call;
917  struct bootp_packet reply;
918  static u_int32_t xid = ~0xFF;
919 
920  struct ifreq ireq;
921  struct ifnet *ifp;
922  struct socket *so;
923  int j;
924  int error;
925  struct sockaddr_in myaddr;
926  struct ifaddr *ifa;
927  struct sockaddr_dl *sdl = NULL;
928  char *delim;
929  struct proc *procp = NULL;
930
931  /*
932   * If already filled in, don't touch it here
933   */
934  if (nfs_diskless_valid)
935    return;
936
937  /*
938   * If we are to update the files create the root
939   * file structure.
940   */
941  if (update_files)
942    if (rtems_create_root_fs () < 0) {
943      printf("Error creating the root filesystem.\nFile not created.\n");
944      update_files = 0;
945    }
946
947  if (dhcp_hostname != NULL) {
948        /* free it */
949    dhcp_hostname=bootp_strdup_realloc(dhcp_hostname,0);
950  }
951
952  /*
953   * Find a network interface.
954   */
955  for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
956    if ((ifp->if_flags &
957      (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
958        break;
959  if (ifp == NULL)
960    panic("bootpc_init: no suitable interface");
961  bzero(&ireq,sizeof(ireq));
962  sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit);
963  printf("bootpc_init: using network interface '%s'\n",
964         ireq.ifr_name);
965
966  if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0)
967    panic("nfs_boot: socreate, error=%d", error);
968         
969  bootpc_fakeup_interface(&ireq,so,procp);
970
971  printf("Bootpc testing starting\n");
972 
973  /* Get HW address */
974
975  for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next)
976    if (ifa->ifa_addr->sa_family == AF_LINK &&
977        (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
978        sdl->sdl_type == IFT_ETHER)
979      break;
980 
981  if (!sdl)
982    panic("bootpc: Unable to find HW address");
983  if (sdl->sdl_alen != EALEN ) 
984    panic("bootpc: HW address len is %d, expected value is %d",
985          sdl->sdl_alen,EALEN);
986
987  printf("bootpc hw address is ");
988  delim="";
989  for (j=0;j<sdl->sdl_alen;j++) {
990    printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]);
991    delim=":";
992  }
993  printf("\n");
994
995#if 0
996  bootpboot_p_iflist();
997  bootpboot_p_rtlist();
998#endif
999 
1000  bzero((caddr_t) &call, sizeof(call));
1001
1002  /* bootpc part */
1003  call.op = 1;                  /* BOOTREQUEST */
1004  call.htype= 1;                /* 10mb ethernet */
1005  call.hlen=sdl->sdl_alen;      /* Hardware address length */
1006  call.hops=0; 
1007  xid++;
1008  call.xid = txdr_unsigned(xid);
1009  bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
1010 
1011  call.vend[0]=99;
1012  call.vend[1]=130;
1013  call.vend[2]=83;
1014  call.vend[3]=99;
1015  call.vend[4]=255;
1016 
1017  call.secs = 0;
1018  call.flags = htons(0x8000); /* We need an broadcast answer */
1019 
1020  error = bootpc_call(&call,&reply,procp);
1021 
1022  if (error)
1023    panic("BOOTP call failed -- error %d", error);
1024 
1025  /*
1026   * Initialize network address structures
1027   */
1028  bzero(&myaddr,sizeof(myaddr));
1029  bzero(&dhcp_netmask,sizeof(dhcp_netmask));
1030  bzero(&dhcp_gw,sizeof(dhcp_gw));
1031  myaddr.sin_len = sizeof(myaddr);
1032  myaddr.sin_family = AF_INET;
1033  dhcp_netmask.sin_len = sizeof(dhcp_netmask);
1034  dhcp_netmask.sin_family = AF_INET;
1035  dhcp_gw.sin_len = sizeof(dhcp_gw);
1036  dhcp_gw.sin_family= AF_INET;
1037
1038  /*
1039   * Set our address
1040   */
1041  myaddr.sin_addr = reply.yiaddr;
1042  printip("My ip address",myaddr.sin_addr);
1043
1044  /*
1045   * Process BOOTP/DHCP options
1046   */
1047  if (reply.vend[0]==99 && reply.vend[1]==130 &&
1048      reply.vend[2]==83 && reply.vend[3]==99) {
1049    processOptions (&reply.vend[4], sizeof(reply.vend) - 4);
1050  }
1051  if (dhcpOptionOverload & 1) {
1052    processOptions ((unsigned char *)reply.file, sizeof reply.file);
1053  }
1054  else {
1055    if (reply.file[0])
1056      rtems_bsdnet_bootp_boot_file_name = 
1057        bootp_strdup_realloc(rtems_bsdnet_bootp_boot_file_name,reply.file);
1058  }
1059  if (dhcpOptionOverload & 2) {
1060    processOptions ((unsigned char *)reply.sname, sizeof reply.sname);
1061  }
1062  else {
1063    if (reply.sname[0])
1064      rtems_bsdnet_bootp_server_name = 
1065        bootp_strdup_realloc(rtems_bsdnet_bootp_server_name,reply.sname);
1066  }
1067  if (rtems_bsdnet_bootp_server_name)
1068    printf ("Server name is %s\n", rtems_bsdnet_bootp_server_name);
1069  if (rtems_bsdnet_bootp_boot_file_name)
1070    printf ("Boot file is %s\n", rtems_bsdnet_bootp_boot_file_name);
1071  if (rtems_bsdnet_bootp_cmdline)
1072    printf ("Command line is %s\n", rtems_bsdnet_bootp_cmdline);
1073
1074  /*
1075   * Use defaults if values were not supplied by BOOTP/DHCP options
1076   */
1077  if (!dhcp_gotnetmask) {
1078    if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr)))
1079      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1080    else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr)))
1081      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1082    else 
1083      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1084  }
1085  printip ("Subnet mask", dhcp_netmask.sin_addr);
1086  if (!dhcp_gotserver)
1087   rtems_bsdnet_bootp_server_address = reply.siaddr;
1088  printip ("Server ip address" ,rtems_bsdnet_bootp_server_address);
1089  if (!dhcp_gotgw)
1090    dhcp_gw.sin_addr = reply.giaddr;
1091  printip ("Gateway ip address", dhcp_gw.sin_addr);
1092  if (!dhcp_gotlogserver)
1093    rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
1094  printip ("Log server ip address", rtems_bsdnet_log_host_address);
1095
1096  /*
1097   * Update the files if we are asked too.
1098   */
1099  if (update_files) {
1100    char *dn = rtems_bsdnet_domain_name;
1101    char *hn = dhcp_hostname;
1102    if (!dn)
1103      dn = "mydomain";
1104    if (!hn)
1105      hn = "me";
1106    rtems_rootfs_append_host_rec(*((unsigned long*) &myaddr.sin_addr), hn, dn);
1107
1108    /*
1109     * Should the given domainname be used here ?
1110     */
1111    if (dhcp_gotserver) {
1112      if (rtems_bsdnet_bootp_server_name)
1113        hn = rtems_bsdnet_bootp_server_name;
1114      else
1115        hn = "bootps";
1116      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_bootp_server_address),
1117                                   hn, dn);
1118    }
1119
1120    if (dhcp_gotlogserver) {
1121      rtems_rootfs_append_host_rec(*((unsigned long *) &rtems_bsdnet_log_host_address),
1122                                   "logs", dn);
1123    }
1124
1125    /*
1126     * Setup the DNS configuration file /etc/resolv.conf.
1127     */
1128    if (rtems_bsdnet_nameserver_count) {
1129      int        i;
1130      char       buf[64];
1131      const char *bufl[1];
1132
1133      bufl[0] = buf;
1134     
1135#define MKFILE_MODE (S_IRUSR | S_IWUSR | S_IWGRP | S_IRGRP | S_IROTH)
1136     
1137      if (rtems_bsdnet_domain_name &&
1138          (strlen(rtems_bsdnet_domain_name) < (sizeof(buf) - 1))) {
1139        strcpy(buf, "search ");
1140        strcat(buf, rtems_bsdnet_domain_name);
1141        strcat(buf, "\n");
1142        rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl);
1143      }
1144
1145      for (i = 0; i < rtems_bsdnet_nameserver_count; i++) {
1146        strcpy(buf, "nameserver ");
1147        strcat(buf, inet_ntoa(rtems_bsdnet_nameserver[i]));
1148        strcat(buf, "\n");
1149        if (rtems_rootfs_file_append ("/etc/resolv.conf", MKFILE_MODE, 1, bufl))
1150          break;
1151      }
1152    }
1153  }
1154
1155  /*
1156   * Configure the interface with the new settings
1157   */
1158  error = bootpc_adjust_interface(&ireq,so,
1159                                  &myaddr,&dhcp_netmask,&dhcp_gw,procp);
1160  soclose(so);
1161}
Note: See TracBrowser for help on using the repository browser.