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

4.104.114.84.95
Last change on this file since dcefab6 was dcefab6, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/28/07 at 02:42:47

Eliminate P().

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