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

4.104.115
Last change on this file since a9fa9b7 was a9fa9b7, checked in by Chris Johns <chrisj@…>, on 02/18/10 at 00:24:25

2010-02-18 Chris Johns <chrisj@…>

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