OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [cpukit/] [libnetworking/] [nfs/] [bootp_subr.c] - Blame information for rev 1779

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.