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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [rtems/] [c/] [src/] [libnetworking/] [nfs/] [bootp_subr.c] - Blame information for rev 173

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 30 unneback
/*      $Id: bootp_subr.c,v 1.2 2001-09-27 12:01:56 chris 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
#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 */
83
struct 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
 
104
extern int nfs_diskless_valid;
105
extern struct nfsv3_diskless nfsv3_diskless;
106
 
107
/* mountd RPC */
108
#if !defined(__rtems__)
109
static int md_mount __P((struct sockaddr_in *mdsin, char *path,
110
        u_char *fhp, int *fhsizep, struct nfs_args *args,struct proc *procp));
111
static 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));
115
static int setfs __P((struct sockaddr_in *addr, char *path, char *p));
116
static int getdec __P((char **ptr));
117
#endif
118
static char *substr __P((char *a,char *b));
119
#if !defined(__rtems__)
120
static void mountopts __P((struct nfs_args *args, char *p));
121
static int xdr_opaque_decode __P((struct mbuf **ptr,u_char *buf,
122
                                  int len));
123
static int xdr_int_decode __P((struct mbuf **ptr,int *iptr));
124
#endif
125
static void printip __P((char *prefix,struct in_addr addr));
126
 
127
#ifdef BOOTP_DEBUG
128
void bootpboot_p_sa(struct sockaddr *sa,struct sockaddr *ma);
129
void bootpboot_p_ma(struct sockaddr *ma);
130
void bootpboot_p_rtentry(struct rtentry *rt);
131
void bootpboot_p_tree(struct radix_node *rn);
132
void bootpboot_p_rtlist(void);
133
void bootpboot_p_iflist(void);
134
#endif
135
 
136
int  bootpc_call(struct bootp_packet *call,
137
                 struct bootp_packet *reply,
138
                 struct proc *procp);
139
 
140
int bootpc_fakeup_interface(struct ifreq *ireq,struct socket *so,
141
                        struct proc *procp);
142
 
143
int
144
bootpc_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
 
150
void bootpc_init(void);
151
 
152
#ifdef BOOTP_DEBUG
153
void 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
 
189
void 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
 
199
void 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
}
212
void  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
 
231
void bootpboot_p_rtlist(void)
232
{
233
  printf("Routing table:\n");
234
  bootpboot_p_tree(rt_tables[AF_INET]->rnh_treetop);
235
}
236
 
237
void 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
 
259
int
260
bootpc_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
 
437
int
438
bootpc_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
 
527
int
528
bootpc_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__)
608
static 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
 
642
static 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
 
656
static 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
 
675
static 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
 
685
static int dhcpOptionOverload = 0;
686
static char dhcp_gotgw = 0;
687
static char dhcp_gotnetmask = 0;
688
static char dhcp_gotserver = 0;
689
static char dhcp_gotlogserver = 0;
690
static struct sockaddr_in dhcp_netmask;
691
static struct sockaddr_in dhcp_gw;
692
 
693
static void
694
processOptions (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:
734
      /* Time offset */
735
      if (len!=4)
736
        panic("bootpc: time offset len is %d",len);
737
      bcopy (p, &rtems_bsdnet_timeoffset, 4);
738
      rtems_bsdnet_timeoffset = ntohl (rtems_bsdnet_timeoffset);
739
      break;
740
 
741
    case 3:
742
      /* Routers */
743
      if (len % 4)
744
        panic ("bootpc: Router Len is %d", len);
745
      if (len > 0) {
746
        bcopy(p, &dhcp_gw.sin_addr, 4);
747
        dhcp_gotgw = 1;
748
      }
749
      break;
750
 
751
    case 42:
752
      /* NTP servers */
753
      if (len % 4)
754
        panic ("bootpc: time server Len is %d", len);
755
      {
756
      int tlen = 0;
757
      while ((tlen < len) &&
758
             (rtems_bsdnet_ntpserver_count < sizeof rtems_bsdnet_config.ntp_server /
759
             sizeof rtems_bsdnet_config.ntp_server[0])) {
760
        bcopy (p+tlen,
761
                &rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count],
762
                4);
763
        printip("Time Server",
764
          rtems_bsdnet_ntpserver[rtems_bsdnet_ntpserver_count]);
765
        rtems_bsdnet_ntpserver_count++;
766
        tlen += 4;
767
      }
768
      }
769
      break;
770
 
771
    case 6:
772
      /* Domain Name servers */
773
      if (len % 4)
774
        panic ("bootpc: DNS Len is %d", len);
775
      {
776
      int dlen = 0;
777
      while ((dlen < len) &&
778
             (rtems_bsdnet_nameserver_count < sizeof rtems_bsdnet_config.name_server /
779
        sizeof rtems_bsdnet_config.name_server[0])) {
780
        bcopy (p+dlen,
781
        &rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count],
782
        4);
783
        printip("Domain Name Server",
784
          rtems_bsdnet_nameserver[rtems_bsdnet_nameserver_count]);
785
        rtems_bsdnet_nameserver_count++;
786
        dlen += 4;
787
      }
788
      }
789
      break;
790
 
791
    case 12:
792
      /* Host name */
793
      if (len>=MAXHOSTNAMELEN)
794
        panic ("bootpc: hostname >=%d bytes", MAXHOSTNAMELEN);
795
      if (sethostname (p, len) < 0)
796
        panic("Can't set host name");
797
      printf("Hostname is %s\n", p);
798
      break;
799
 
800
    case 7:
801
      /* Log servers */
802
      if (len % 4)
803
        panic ("bootpc: Log server Len is %d", len);
804
      if (len > 0) {
805
        bcopy(p, &rtems_bsdnet_log_host_address, 4);
806
        dhcp_gotlogserver = 1;
807
      }
808
      break;
809
 
810
    case 15:
811
      /* Domain name */
812
      if (p[0]) {
813
        rtems_bsdnet_domain_name = strdup (p);
814
        printf("Domain name is %s\n", rtems_bsdnet_domain_name);
815
      }
816
      break;
817
 
818
    case 16:  /* Swap server IP address. unused */
819
      break;
820
 
821
    case 52:
822
      /* DHCP option override */
823
      if (len != 1)
824
        panic ("bootpc: DHCP option overload len is %d", len);
825
      dhcpOptionOverload = p[0];
826
      break;
827
 
828
    case 128: /* Site-specific option for DHCP servers that
829
               *   a) don't supply tag 54
830
               * and
831
               *   b) don't supply the server address in siaddr
832
               * For example, on Solaris 2.6 in.dhcpd, include in the dhcptab:
833
               *    Bootsrv s Site,128,IP,1,1
834
               * and use that symbol in the macro that defines the client:
835
               *    Bootsrv=<tftp-server-ip-address>
836
               */
837
    case 54:
838
      /* DHCP server */
839
      if (len != 4)
840
        panic ("bootpc: DHCP server len is %d", len);
841
      bcopy(p, &rtems_bsdnet_bootp_server_address, 4);
842
      dhcp_gotserver = 1;
843
      break;
844
 
845
    case 66:
846
      /* DHCP server name option */
847
      if (p[0])
848
        rtems_bsdnet_bootp_server_name = strdup (p);
849
      break;
850
 
851
    case 67:
852
      /* DHCP bootfile option */
853
      if (p[0])
854
        rtems_bsdnet_bootp_boot_file_name = strdup (p);
855
      break;
856
 
857
    default:
858
      printf ("Ignoring BOOTP/DHCP option code %d\n", code);
859
      break;
860
    }
861
  }
862
}
863
 
864
#define EALEN 6
865
 
866
void
867
bootpc_init(void)
868
{
869
  struct bootp_packet call;
870
  struct bootp_packet reply;
871
  static u_int32_t xid = ~0xFF;
872
 
873
  struct ifreq ireq;
874
  struct ifnet *ifp;
875
  struct socket *so;
876
  int j;
877
  int error;
878
  struct sockaddr_in myaddr;
879
  struct ifaddr *ifa;
880
  struct sockaddr_dl *sdl = NULL;
881
  char *delim;
882
  struct proc *procp = NULL;
883
 
884
  /*
885
   * If already filled in, don't touch it here
886
   */
887
  if (nfs_diskless_valid)
888
    return;
889
 
890
  /*
891
   * Find a network interface.
892
   */
893
  for (ifp = ifnet; ifp != 0; ifp = ifp->if_next)
894
    if ((ifp->if_flags &
895
      (IFF_LOOPBACK|IFF_POINTOPOINT)) == 0)
896
        break;
897
  if (ifp == NULL)
898
    panic("bootpc_init: no suitable interface");
899
  bzero(&ireq,sizeof(ireq));
900
  sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit);
901
  printf("bootpc_init: using network interface '%s'\n",
902
         ireq.ifr_name);
903
 
904
  if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0)
905
    panic("nfs_boot: socreate, error=%d", error);
906
 
907
  bootpc_fakeup_interface(&ireq,so,procp);
908
 
909
  printf("Bootpc testing starting\n");
910
 
911
  /* Get HW address */
912
 
913
  for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next)
914
    if (ifa->ifa_addr->sa_family == AF_LINK &&
915
        (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
916
        sdl->sdl_type == IFT_ETHER)
917
      break;
918
 
919
  if (!sdl)
920
    panic("bootpc: Unable to find HW address");
921
  if (sdl->sdl_alen != EALEN )
922
    panic("bootpc: HW address len is %d, expected value is %d",
923
          sdl->sdl_alen,EALEN);
924
 
925
  printf("bootpc hw address is ");
926
  delim="";
927
  for (j=0;j<sdl->sdl_alen;j++) {
928
    printf("%s%x",delim,((unsigned char *)LLADDR(sdl))[j]);
929
    delim=":";
930
  }
931
  printf("\n");
932
 
933
#if 0
934
  bootpboot_p_iflist();
935
  bootpboot_p_rtlist();
936
#endif
937
 
938
  bzero((caddr_t) &call, sizeof(call));
939
 
940
  /* bootpc part */
941
  call.op = 1;                  /* BOOTREQUEST */
942
  call.htype= 1;                /* 10mb ethernet */
943
  call.hlen=sdl->sdl_alen;      /* Hardware address length */
944
  call.hops=0;
945
  xid++;
946
  call.xid = txdr_unsigned(xid);
947
  bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
948
 
949
  call.vend[0]=99;
950
  call.vend[1]=130;
951
  call.vend[2]=83;
952
  call.vend[3]=99;
953
  call.vend[4]=255;
954
 
955
  call.secs = 0;
956
  call.flags = htons(0x8000); /* We need an broadcast answer */
957
 
958
  error = bootpc_call(&call,&reply,procp);
959
 
960
  if (error)
961
    panic("BOOTP call failed -- error %d", error);
962
 
963
  /*
964
   * Initialize network address structures
965
   */
966
  bzero(&myaddr,sizeof(myaddr));
967
  bzero(&dhcp_netmask,sizeof(dhcp_netmask));
968
  bzero(&dhcp_gw,sizeof(dhcp_gw));
969
  myaddr.sin_len = sizeof(myaddr);
970
  myaddr.sin_family = AF_INET;
971
  dhcp_netmask.sin_len = sizeof(dhcp_netmask);
972
  dhcp_netmask.sin_family = AF_INET;
973
  dhcp_gw.sin_len = sizeof(dhcp_gw);
974
  dhcp_gw.sin_family= AF_INET;
975
 
976
  /*
977
   * Set our address
978
   */
979
  myaddr.sin_addr = reply.yiaddr;
980
  printip("My ip address",myaddr.sin_addr);
981
 
982
  /*
983
   * Process BOOTP/DHCP options
984
   */
985
  if (reply.vend[0]==99 && reply.vend[1]==130 &&
986
      reply.vend[2]==83 && reply.vend[3]==99) {
987
    processOptions (&reply.vend[4], sizeof(reply.vend) - 4);
988
  }
989
  if (dhcpOptionOverload & 1) {
990
    processOptions (reply.file, sizeof reply.file);
991
  }
992
  else {
993
    if (reply.file[0])
994
      rtems_bsdnet_bootp_boot_file_name = strdup (reply.file);
995
  }
996
  if (dhcpOptionOverload & 2) {
997
    processOptions (reply.sname, sizeof reply.sname);
998
  }
999
  else {
1000
    if (reply.sname[0])
1001
      rtems_bsdnet_bootp_server_name = strdup (reply.sname);
1002
  }
1003
  if (rtems_bsdnet_bootp_server_name)
1004
    printf ("Server name is %s\n", rtems_bsdnet_bootp_server_name);
1005
  if (rtems_bsdnet_bootp_boot_file_name)
1006
    printf ("Boot file is %s\n", rtems_bsdnet_bootp_boot_file_name);
1007
 
1008
  /*
1009
   * Use defaults if values were not supplied by BOOTP/DHCP options
1010
   */
1011
  if (!dhcp_gotnetmask) {
1012
    if (IN_CLASSA(ntohl(myaddr.sin_addr.s_addr)))
1013
      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSA_NET);
1014
    else if (IN_CLASSB(ntohl(myaddr.sin_addr.s_addr)))
1015
      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSB_NET);
1016
    else
1017
      dhcp_netmask.sin_addr.s_addr = htonl(IN_CLASSC_NET);
1018
  }
1019
  printip ("Subnet mask", dhcp_netmask.sin_addr);
1020
  if (!dhcp_gotserver)
1021
   rtems_bsdnet_bootp_server_address = reply.siaddr;
1022
  printip ("Server ip address" ,rtems_bsdnet_bootp_server_address);
1023
  if (!dhcp_gotgw)
1024
    dhcp_gw.sin_addr = reply.giaddr;
1025
  printip ("Gateway ip address", dhcp_gw.sin_addr);
1026
  if (!dhcp_gotlogserver)
1027
    rtems_bsdnet_log_host_address = rtems_bsdnet_bootp_server_address;
1028
  printip ("Log server ip address", rtems_bsdnet_log_host_address);
1029
 
1030
  /*
1031
   * Configure the interface with the new settings
1032
   */
1033
  error = bootpc_adjust_interface(&ireq,so,
1034
                                  &myaddr,&dhcp_netmask,&dhcp_gw,procp);
1035
  soclose(so);
1036
}

powered by: WebSVN 2.1.0

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