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

4.104.114.84.9
Last change on this file since 7440440 was 7440440, checked in by Ralf Corsepius <ralf.corsepius@…>, on Apr 17, 2005 at 7:34:11 AM

Reflect having introduced nfsclient/.

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