source: rtems/cpukit/libnetworking/nfs/bootp_subr.c @ 39e6e65a

4.104.114.84.95
Last change on this file since 39e6e65a was 39e6e65a, checked in by Joel Sherrill <joel.sherrill@…>, on Aug 19, 1998 at 9:32:28 PM

Base files

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