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

4.104.115
Last change on this file since e8a837d was e8a837d, checked in by Ralf Corsepius <ralf.corsepius@…>, on 02/04/09 at 12:54:28

#include <sys/ucred.h>.

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