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

5
Last change on this file since e744c36 was e744c36, checked in by Sebastian Huber <sebastian.huber@…>, on 06/07/17 at 05:36:59

network: Use inet_ntoa_r()

Update #2833.

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