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

4.104.114.84.9
Last change on this file since a605cec was a605cec, checked in by Ralf Corsepius <ralf.corsepius@…>, on Aug 6, 2005 at 3:28:49 AM

2005-08-06 Ralf Corsepius <ralf.corsepius@…>

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