source: rtems/cpukit/libnetworking/nfs/bootp_subr.c @ 65c6425

4.115
Last change on this file since 65c6425 was 65c6425, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 17:24:46

Remove CVS Id Strings (manual edits after script)

These modifications were required by hand after running the script.
In some cases, the file names did not match patterns. In others,
the format of the file did not match any common patterns.

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