source: rtems/cpukit/libnetworking/nfs/bootp_subr.c @ 847375f

4.104.114.84.95
Last change on this file since 847375f was 847375f, checked in by Joel Sherrill <joel.sherrill@…>, on Nov 19, 1998 at 5:35:49 PM

Patch from Eric Norum <eric@…>:

1) Socket timeout field changed from short' to long'. This makes longer

timeouts possible. With a 1 kHz system clock the old system allowed
timeouts only up to a little over 30 seconds! This change is a
slightly cleaned-up version of the patch proposed by Ian Lance Taylor.

2) Major changes to BOOTP/DHCP reply handling. Now supports much of

RFC2132. These changes were done at the request of, and with the
assistance of, Erik Ivanenko.

If you're making changes, you might want to change the network
supplement Essentially just do a global search and replace of BOOTP
with BOOTP/DHCP.

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