|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: #if NEXT
26: /*
27: * Copyright (c) 1988, by NeXT Inc.
28: *
29: **********************************************************************
30: * HISTORY
31: * Tue Mar 18 11:49:14 PST 1997 Dieter Siegmund (dieter) at NeXT
32: * Ported from 4.3 to 4.4Lite (Teflon)
33: *
34: * Mon Jan 10 15:13:33 PST 1994 Matt Watson (mwatson) at NeXT
35: * Allow "Sexy Net Init"(tm) while netbooting
36: * Function prototype cleanup
37: *
38: * 09-Apr-90 Bradley Taylor (btaylor) at NeXT
39: * Changes because of new network API (netbuf and netif)
40: *
41: * 25-May-89 Peter King (king) at NeXT
42: * Added support for "Sexy Net Init" -- NeXT vendor protocol 1.
43: *
44: * 15-Aug-88 Peter King (king) at NeXT, Inc.
45: * Created.
46: **********************************************************************
47: */
48:
49: #if m68k
50: #else
51:
52: #import <machine/spl.h>
53: #import <machine/label_t.h>
54: #import <sys/param.h>
55: #import <sys/types.h>
56: #import <mach/boolean.h>
57: #import <sys/kernel.h>
58: #import <sys/errno.h>
59: #import <sys/file.h>
60: #import <sys/uio.h>
61: #import <sys/ioctl.h>
62: #import <sys/time.h>
63: #import <sys/mbuf.h>
64: #import <sys/vnode.h>
65: #import <sys/socket.h>
66: #import <sys/socketvar.h>
67: #import <net/if.h>
68: #import <net/route.h>
69: #import <netinet/in.h>
70: #import <netinet/in_systm.h>
71: //#import <netinet/in_pcb.h>
72: #import <netinet/if_ether.h>
73: #import <netinet/ip.h>
74: #import <netinet/ip_var.h>
75: #import <netinet/udp.h>
76: #import <netinet/udp_var.h>
77: #import <netinet/ip_icmp.h>
78: #import <netinet/bootp.h>
79: #import <dev/kmreg_com.h>
80:
81: #define CONSOLE "/dev/console"
82:
83: #define BOOTP_DEBUG 0
84: #if BOOTP_DEBUG
85: #define dprintf(x) printf x;
86: #else BOOTP_DEBUG
87: #define dprintf(x)
88: #endif BOOTP_DEBUG
89:
90: static int in_bootp_initnet(volatile struct ifnet *ifp, struct ifreq *ifr,
91: struct socket **sop);
92:
93: static struct bootp_packet * in_bootp_buildpacket(volatile struct ifnet *ifp,
94: struct sockaddr_in *sin, u_char my_enaddr[6]);
95:
96: struct mbuf * in_bootp_bptombuf(struct bootp_packet *bp);
97:
98: static void in_bootp_timeout(struct socket **socketflag);
99:
100: static int in_bootp_promisctimeout(boolean_t *ignoreflag);
101:
102: static int in_bootp_getpacket(struct socket *so, caddr_t pp, int psize);
103:
104: static int in_bootp_sendrequest(volatile struct ifnet *ifp,
105: struct socket *so, struct bootp_packet *bp_s, struct bootp *bp_r,
106: u_char my_enaddr[6], struct vnode **console_vpp);
107:
108: static int in_bootp_openconsole(struct vnode **vpp);
109:
110: static void in_bootp_closeconsole(struct vnode *vp);
111:
112: static int in_bootp_processreply(struct vnode *vp, struct bootp_packet *bp_s,
113: struct bootp *bp_r);
114:
115: static int in_bootp_setaddress(volatile struct ifnet *ifp, struct ifreq *ifr,
116: struct socket *so, struct in_addr *addr);
117:
118: static struct ifreq in_bootp_makeifreq(volatile struct ifnet *ifp,
119: struct sockaddr_in *sin);
120:
121: static void kmgets(char *cp, char *lp, boolean_t silent);
122:
123: static boolean_t alertShowing = FALSE;
124:
125: /*
126: * Routine: in_bootp
127: * Function:
128: * Use the BOOTP protocol to resolve what our IP address should be
129: * on a particular interface.
130: * Note:
131: * The ifreq structure returns the newly configured address. If there
132: * is an error, it can be full of bogus information.
133: *
134: * This is called from driver level ioctl routines to assure that
135: * the interface is a 10Meg Ethernet.
136: */
137: int
138: in_bootp(
139: volatile struct ifnet *ifp,
140: struct sockaddr_in *sin,
141: u_char my_enaddr[6]
142: )
143: {
144: struct mbuf *m;
145: struct socket *so;
146: register int error;
147: struct bootp_packet *bp_s = NULL;
148: struct bootp *bp_r = NULL;
149: struct vnode *vp = NULL;
150: struct nextvend *nv_s;
151: struct nextvend *nv_r;
152: struct ifreq ifr;
153: struct proc * procp = current_proc(); /* XXX */
154:
155: dprintf(("in_bootp() entered\n"));
156:
157: ifr = in_bootp_makeifreq(ifp, sin);
158: if (error = in_bootp_initnet(ifp, &ifr, &so)) {
159: if (error == -1) {
160: /*
161: * This means the interface was already
162: * autoconfigured. Reset the address to make
163: * sure the netmask is right.
164: */
165: error = ifioctl(so, SIOCSIFADDR, (caddr_t)&ifr,
166: procp);
167: if (error == 0) {
168: bcopy(&ifr.ifr_addr, sin, sizeof(*sin));
169: }
170: soclose(so);
171: return (error);
172: }
173: dprintf(("in_bootp() in_bootp_initnet failed: %d\n", error));
174: goto errout;
175: }
176:
177: /* Build a packet */
178: bp_s = in_bootp_buildpacket(ifp,
179: sin,
180: my_enaddr);
181: nv_s = (struct nextvend *)&bp_s->bp_bootp.bp_vend;
182:
183: /* Set up place to receive BOOTP response */
184: bp_r = (struct bootp *)kalloc(sizeof (*bp_r));
185: nv_r = (struct nextvend *)&bp_r->bp_vend;
186:
187: while (TRUE) {
188: /* Send the request */
189: dprintf(("in_bootp() trying to send request\n"));
190: if (error = in_bootp_sendrequest(ifp, so, bp_s, bp_r,
191: my_enaddr, &vp)) {
192: goto errout;
193: }
194: if (nv_r->nv_opcode == BPOP_OK) {
195: break;
196: }
197: dprintf(("in_bootp() trying to open console\n"));
198: if (vp == NULL && (error = in_bootp_openconsole(&vp))) {
199: goto errout;
200: }
201: dprintf(("in_bootp() trying to process reply\n"));
202: if (error = in_bootp_processreply(vp, bp_s, bp_r)) {
203: goto errout;
204: }
205: }
206:
207: /* It's for us. */
208: dprintf(("in_bootp() got a response!\n"));
209: if (vp) {
210: (void) in_bootp_closeconsole(vp);
211: vp = NULL;
212: }
213:
214: error = in_bootp_setaddress(ifp, &ifr, so,
215: (struct in_addr *)&bp_r->bp_yiaddr);
216: if (error == 0) {
217: bcopy(&ifr.ifr_addr, sin, sizeof(*sin));
218: }
219:
220: errout:
221: if (error && so) {
222: /* Make sure the interface is shut down */
223: (void) ifioctl(so, SIOCDIFADDR, (caddr_t) &ifr, procp);
224: ifr.ifr_flags = ifp->if_flags & ~(IFF_UP);
225: (void) ifioctl(so, SIOCSIFFLAGS, (caddr_t) &ifr, procp);
226: }
227: ifp->if_eflags &= ~(IFEF_AUTOCONF);
228: if (so) {
229: soclose(so);
230: }
231: if (bp_s) {
232: kfree((caddr_t)bp_s, sizeof (*bp_s));
233: }
234: if (bp_r) {
235: kfree((caddr_t)bp_r, sizeof (*bp_r));
236: }
237: if (!error) {
238: (void) in_bootp_closeconsole(vp);
239: }
240: dprintf(("in_bootp() returning: %d\n", error));
241:
242: return (error);
243: }
244:
245: /*
246: * Routine: in_bootp_initnet
247: * Function:
248: * Set up the interface to handle BOOTP packets. Return the interface
249: * address in ifr.
250: * Returns:
251: * -1: interface previously autoconfigured
252: * 0: success
253: * >0: unix error
254: */
255: int
256: in_bootp_initnet(ifp, ifr, sop)
257: register volatile struct ifnet *ifp;
258: register struct ifreq *ifr;
259: struct socket **sop;
260: {
261: struct sockaddr_in lsin;
262: struct sockaddr_in *sin;
263: struct mbuf *m;
264: int error;
265: struct proc * procp = current_proc(); /* XXX */
266:
267: dprintf((" in_bootp_initnet() entered\n"));
268:
269: /*
270: * Get a socket (wouldn't it be nice to make system calls from
271: * within the kernel?)
272: */
273: dprintf((" in_bootp_initnet() socreate..."));
274: if (error = socreate(AF_INET, sop, SOCK_DGRAM, 0)) {
275: *sop = NULL;
276: dprintf(("failed: %d\n", error));
277: return (error);
278: }
279: dprintf(("ok\n"));
280:
281: /*
282: * Bring the interface up if neccessary.
283: */
284: if ((ifp->if_flags & IFF_UP) == 0) {
285: /* Turn off trailers here, otherwise the server ARP reply
286: will cause the booting client the issue its own ARP
287: reply enabling trailers.
288: */
289: ifr->ifr_flags = ifp->if_flags | IFF_UP | IFF_NOTRAILERS;
290: dprintf((" in_bootp_initnet() SIOCSIFFLAGS..."));
291: if (error = ifioctl(*sop, SIOCSIFFLAGS, (caddr_t)ifr, procp)) {
292: dprintf(("failed: %d\n", error));
293: return (error);
294: }
295: dprintf(("ok\n"));
296: }
297: else {
298: if (ifp->if_eflags & IFEF_AUTOCONF_DONE) {
299: /* If the interface was previously autoconfigured, return */
300: dprintf((" in_bootp_initnet() already done:"));
301: if ((error = ifioctl(*sop, SIOCGIFADDR,
302: (caddr_t)ifr, procp))) {
303: dprintf((" %d\n", error));
304: return (error);
305: }
306: ifp->if_eflags &= ~(IFEF_AUTOCONF);
307: dprintf((" -1\n"));
308: return(-1);
309: }
310: }
311:
312: /*
313: * Assign the all-zeroes address to the interface.
314: */
315: bzero((caddr_t)&lsin, sizeof(lsin));
316: lsin.sin_family = AF_INET;
317: ifr->ifr_addr = *(struct sockaddr *)&lsin;
318:
319: dprintf((" in_bootp_initnet() SIOCSIFADDR..."));
320: if (error = ifioctl(*sop, SIOCSIFADDR, (caddr_t)ifr, procp)) {
321: dprintf(("failed: %d\n",
322: error));
323: return (error);
324: }
325: dprintf(("ok\n"));
326:
327: /*
328: * Now set up the socket to receive the BOOTP response, i.e. bind
329: * a name to it.
330: */
331: dprintf((" in_bootp_initnet() m_get..."));
332: m = m_get(M_WAIT, MT_SONAME);
333: if (m == NULL) {
334: error = ENOBUFS;
335: dprintf(("failed: %d\n", error));
336: return (error);
337: }
338: dprintf(("ok\n"));
339:
340: m->m_len = sizeof (struct sockaddr_in);
341: sin = mtod(m, struct sockaddr_in *);
342: sin->sin_family = AF_INET;
343: sin->sin_port = htons(IPPORT_BOOTPC);
344: sin->sin_addr.s_addr = INADDR_ANY;
345:
346: dprintf((" in_bootp_initnet() sobind..."));
347: error = sobind(*sop, m);
348: m_freem(m);
349: if (error) {
350: dprintf(("failed: %d\n", error));
351: return (error);
352: }
353: dprintf(("ok\n"));
354:
355: /* We will be doing non-blocking IO on this socket */
356: (*sop)->so_state |= SS_NBIO;
357:
358: dprintf((" in_bootp_initnet() exiting normally\n"));
359: return (0);
360: }
361:
362: /*
363: * Routine: in_bootp_buildpacket
364: * Function:
365: * Put together a BOOTP request packet. RFC951.
366: */
367: struct bootp_packet *
368: in_bootp_buildpacket(
369: volatile struct ifnet *ifp, /* Interface */
370: struct sockaddr_in *sin, /* Local IP address */
371: u_char my_enaddr[6] /* Local EN address */
372: )
373: {
374: struct bootp_packet *bp_s;
375: struct nextvend *nv;
376:
377: dprintf((" in_bootp_buildpacket() entered\n"));
378:
379: bp_s = (struct bootp_packet *)kalloc(sizeof (*bp_s));
380: nv = (struct nextvend *)&bp_s->bp_bootp.bp_vend;
381:
382: bzero(bp_s, sizeof (*bp_s));
383: bp_s->bp_ip.ip_v = IPVERSION;
384: bp_s->bp_ip.ip_hl = sizeof (struct ip) >> 2;
385: bp_s->bp_ip.ip_id = htons(ip_id++);
386: bp_s->bp_ip.ip_ttl = MAXTTL;
387: bp_s->bp_ip.ip_p = IPPROTO_UDP;
388: bp_s->bp_ip.ip_src.s_addr = sin->sin_addr.s_addr;
389: bp_s->bp_ip.ip_dst.s_addr = INADDR_BROADCAST;
390: bp_s->bp_udp.uh_sport = htons(IPPORT_BOOTPC);
391: bp_s->bp_udp.uh_dport = htons(IPPORT_BOOTPS);
392: bp_s->bp_udp.uh_sum = 0;
393: bp_s->bp_bootp.bp_op = BOOTREQUEST;
394: bp_s->bp_bootp.bp_htype = ARPHRD_ETHER;
395: bp_s->bp_bootp.bp_hlen = 6;
396: bp_s->bp_bootp.bp_ciaddr.s_addr = 0;
397: bcopy((caddr_t)my_enaddr, bp_s->bp_bootp.bp_chaddr, 6);
398: bcopy(VM_NEXT, &nv->nv_magic, 4);
399:
400: nv->nv_version = 1;
401: nv->nv_opcode = BPOP_OK;
402: bp_s->bp_udp.uh_ulen = htons(sizeof (bp_s->bp_udp) +
403: sizeof (bp_s->bp_bootp));
404: bp_s->bp_ip.ip_len = htons(sizeof (struct ip) +
405: ntohs(bp_s->bp_udp.uh_ulen));
406: bp_s->bp_ip.ip_sum = 0;
407:
408: dprintf((" in_bootp_buildpacket() exiting\n"));
409:
410: return (bp_s);
411: }
412:
413: /*
414: * Routine: in_bootp_bptombuf
415: * Function:
416: * Put the outgoing BOOTP packet into an mbuf chain.
417: */
418: struct mbuf *
419: in_bootp_bptombuf(bp)
420: struct bootp_packet *bp;
421: {
422: register struct ip *ip;
423: struct mbuf *m;
424: int resid = sizeof (*bp);
425: caddr_t cp = (caddr_t) bp;
426:
427: m = (struct mbuf *)m_devget(bp, sizeof(*bp), 0, 0, 0);
428:
429: if (m == 0) {
430: printf("in_bootp_bptombuf: m_devget failed\n");
431: return 0;
432: }
433: m->m_flags |= M_BCAST;
434:
435: /* Compute the checksum */
436: ip = mtod(m, struct ip *);
437: ip->ip_sum = 0;
438: ip->ip_sum = in_cksum(m, sizeof (struct ip));
439: return (m);
440: }
441:
442: /*
443: * Routine: in_bootp_timeout
444: * Function:
445: * Wakeup the process waiting to receive something on a socket.
446: * Boy wouldn't it be nice if we could do system calls from the
447: * kernel. Then I could do a select!
448: */
449: void
450: in_bootp_timeout(socketflag)
451: struct socket **socketflag;
452: {
453: struct socket *so = *socketflag;
454:
455: dprintf(("\n---->in_bootp_timeout()\n"));
456:
457: *socketflag = NULL;
458: sowakeup(so, &so->so_rcv);
459: }
460:
461: /*
462: * Routine: in_bootp_promisctimeout
463: * Function:
464: * Flag that it is ok to accept a response from a promiscuous BOOTP
465: * server.
466: */
467: int
468: in_bootp_promisctimeout(ignoreflag)
469: boolean_t *ignoreflag;
470: {
471: dprintf(("\n---->in_bootp_promisctimeout()\n"));
472:
473: *ignoreflag = FALSE;
474: return 0;
475: }
476:
477: /*
478: * Routine: in_bootp_getpacket
479: * Function:
480: * Wait for an incoming packet on the socket.
481: */
482: int
483: in_bootp_getpacket(so, pp, psize)
484: struct socket *so;
485: caddr_t pp;
486: int psize;
487: {
488: struct iovec aiov;
489: struct uio auio;
490: int rcvflg;
491:
492: aiov.iov_base = pp;
493: aiov.iov_len = psize;
494: auio.uio_iov = &aiov;
495: auio.uio_iovcnt = 1;
496: auio.uio_segflg = UIO_SYSSPACE;
497: auio.uio_offset = 0;
498: auio.uio_resid = psize;
499: auio.uio_rw = UIO_READ;
500: rcvflg = MSG_WAITALL;
501:
502: return (soreceive(so, 0, &auio, 0, 0, &rcvflg));
503: }
504:
505: #define INITIAL_DEADLINE 5
506: /*
507: * Routine: in_bootp_sendrequest
508: * Function:
509: * Do the actual work of sending a BOOTP request and getting the
510: * response.
511: */
512: int
513: in_bootp_sendrequest(
514: volatile struct ifnet *ifp,
515: struct socket *so,
516: struct bootp_packet *bp_s,
517: struct bootp *bp_r,
518: u_char my_enaddr[6],
519: struct vnode **console_vpp
520: ) {
521: struct mbuf *m;
522: register int error;
523: int xid;
524: struct timeval tv;
525: int timeo;
526: int timecount;
527: unsigned long totaltime;
528: unsigned long deadline;
529: struct socket *timeflag;
530: label_t jmpbuf;
531: struct sockaddr_in lsin;
532: struct nextvend *nv_s =
533: (struct nextvend *) &bp_s->bp_bootp.bp_vend;
534: struct nextvend *nv_r = (struct nextvend *)&bp_r->bp_vend;
535: boolean_t promisc_rcvd = FALSE;
536: boolean_t promisc_ignore;
537:
538: dprintf((" in_bootp_sendrequest() entered\n"));
539:
540: /* Create a transaction ID */
541: microtime(&tv);
542: xid = my_enaddr[5] ^ tv.tv_sec;
543: bp_s->bp_bootp.bp_xid = xid;
544:
545: /* Address to send to */
546: lsin.sin_family = AF_INET;
547: lsin.sin_port = htons(IPPORT_BOOTPS);
548: lsin.sin_addr.s_addr = INADDR_BROADCAST;
549:
550: /*
551: * timeout/retry policy:
552: * Before a server has responded we retransmit at a random time
553: * in a binary window which is doubled each transmission. This
554: * avoids flooding the net after, say, a power failure when all
555: * machines are trying to reboot simultaneously.
556: */
557: timeo = 1;
558: timecount = 0;
559: totaltime = 0;
560: deadline = INITIAL_DEADLINE;
561:
562: while (TRUE) {
563: if (timecount == 0) {
564: /* Put the outgoing packet in an mbuf */
565: m = in_bootp_bptombuf(bp_s);
566: dprintf((" in_bootp_sendrequest() if_output "));
567: if (error = (*ifp->if_output)(ifp, m,
568: (struct sockaddr *)&lsin, 0)) {
569: dprintf(("failed: %d\n", error));
570: goto errout;
571: }
572: dprintf(("ok\n"));
573: }
574:
575: /*
576: * Sleep for a second and then check for the abort
577: * character again.
578: */
579: timeflag = so;
580: timeout(in_bootp_timeout, &timeflag, hz);
581: keepwaiting:
582: dprintf((" in_bootp_sendrequest(): in_bootp_getpacket..."));
583: while (((error = in_bootp_getpacket(so, (caddr_t)bp_r, sizeof (*bp_r)))
584: == EWOULDBLOCK) && (timeflag == so)) {
585: /* dprintf(("waiting (spl = 0x%x)...", curspl())); */
586: sbwait(&so->so_rcv);
587: }
588: if (error && (error != EWOULDBLOCK)) {
589: dprintf(("failed: %d\n", error));
590: untimeout(in_bootp_timeout, &timeflag);
591: goto errout;
592: }
593: if (timeflag == NULL) {
594: dprintf((" in_bootp_sendrequest(): "
595: "in_bootp_getpacket...timed out\n"));
596: if ((deadline > INITIAL_DEADLINE) && (timecount & 1))
597: printf(".");
598: timecount++;
599: totaltime++;
600: if (timecount == timeo) {
601: if (timeo < 64) {
602: timeo <<= 1;
603: }
604: timecount = 0;
605: }
606: if (totaltime == deadline) {
607: register c = 0;
608:
609: if (error=in_bootp_openconsole(console_vpp)) {
610: goto errout;
611: }
612: printf("\nServer %snot responding.\n"
613: "Continue without network? (y/n) ",
614: (deadline == INITIAL_DEADLINE) ? "is " : "still ");
615: while (1) {
616: c = kmgetc_silent(0) & 0177;
617: if (c == 'y' || c == 'Y') {
618: printf("%c\n", c);
619: psignal(current_proc(), SIGINT);
620: error = EINTR;
621: in_bootp_closeconsole(*console_vpp);
622: goto errout;
623: }
624: else if (c == 'n' || c == 'N') {
625: break;
626: }
627: }
628: printf("%c\nWaiting for response.", c);
629: deadline += 30;
630: }
631:
632: continue;
633: }
634:
635: dprintf(("received packet!\n"));
636:
637: /* We have a packet. Check it out. */
638: if (bp_r->bp_xid != xid ||
639: bp_r->bp_op != BOOTREPLY ||
640: bcmp(bp_r->bp_chaddr, my_enaddr, 6) != 0) {
641: dprintf((" in_bootp_sendrequest() not for us\n"));
642: goto keepwaiting;
643: }
644:
645: /*
646: * It's for us. If it is not an authoritative answer,
647: * wait for a while (10 secs) to see if there is an
648: * authoritative server out there.
649: */
650: if (nv_s->nv_opcode == BPOP_OK && nv_r->nv_opcode != BPOP_OK) {
651: if (!promisc_rcvd) {
652: promisc_rcvd = TRUE;
653: promisc_ignore = TRUE;
654: timeout(in_bootp_promisctimeout,
655: &promisc_ignore, 10 * hz);
656: dprintf((" in_bootp_sendrequest() "
657: "ignoring 1st promisc response\n"));
658: goto keepwaiting;
659: }
660: if (promisc_ignore == TRUE) {
661: dprintf((" in_bootp_sendrequest() "
662: "ignoring promisc response\n"));
663: goto keepwaiting;
664: }
665: }
666:
667:
668: /* OK, it's for us */
669: dprintf((" in_bootp_sendrequest() it's for us!\n"));
670:
671: untimeout(in_bootp_timeout, &timeflag);
672:
673: if (alertShowing) {
674: printf("Network responded!\n");
675: }
676: error = 0;
677: goto errout;
678: }
679:
680: /* We aborted. Return appropriate error */
681: error = ETIMEDOUT;
682:
683: errout:
684: dprintf((" in_bootp_sendrequest() returning %d\n", error));
685:
686: untimeout(in_bootp_promisctimeout, &promisc_ignore);
687: return (error);
688: }
689:
690: /*
691: * Routine: in_bootp_openconsole
692: * Function:
693: * Pop up a console window so that we can do some user I/O to
694: * answer the server's questions.
695: */
696: int
697: in_bootp_openconsole(vpp)
698: struct vnode **vpp;
699: {
700: int ret = 0;
701: struct proc * procp = current_proc(); /* XXX */
702:
703: if (alertShowing == FALSE) {
704: ret = alert(60, 8, "Configuring Network", "%L", 0, 0, 0, 0, 0, 0, 0);
705: alertShowing = TRUE;
706: }
707: dprintf(("in_bootp_openconsole() returning: %d\n", ret));
708: return(ret);
709: }
710:
711: /*
712: * Routine: in_bootp_closeconsole
713: * Function:
714: * Restore and close and the console window.
715: */
716: void
717: in_bootp_closeconsole(vp)
718: struct vnode *vp;
719: {
720: if (alertShowing)
721: alert_done();
722: alertShowing = FALSE;
723: }
724:
725: /*
726: * Routine: in_bootp_processreply
727: * Function:
728: * The heart of "Sexy Net Init". This routine handles requests from
729: * the BOOTP server to interact with the user.
730: */
731: int
732: in_bootp_processreply(vp, bp_s, bp_r)
733: struct vnode *vp;
734: struct bootp_packet *bp_s;
735: struct bootp *bp_r;
736: {
737: struct nextvend *nv_s =
738: (struct nextvend *) &bp_s->bp_bootp.bp_vend;
739: struct nextvend *nv_r = (struct nextvend *)&bp_r->bp_vend;
740: int resid;
741: int error;
742: int flush = FREAD;
743: boolean_t noecho = FALSE;
744: char *cp;
745:
746: /* Truncate text if needed */
747: if (strlen(nv_r->nv_text) > NVMAXTEXT) {
748: nv_r->nv_null = '\0';
749: }
750:
751: /* Write out the server message */
752: printf("%s", nv_r->nv_text);
753:
754: if (error = kmioctl(0, TIOCFLUSH, &flush, 0)) {
755: goto errout;
756: }
757: switch (nv_r->nv_opcode) {
758: case BPOP_QUERY_NE:
759: noecho = TRUE;
760: /* Fall through */
761:
762: case BPOP_QUERY:
763: error = 0;
764: /* Read in the user response */
765: kmgets(nv_s->nv_text, nv_s->nv_text, noecho);
766:
767: /* If we are not echoing, move the cursor to the next line */
768: if (noecho) {
769: printf("\n");
770: }
771:
772: /* Get rid of the CR or LF if either exists. */
773: for (cp = (char *)nv_s->nv_text; *cp; cp++) {
774: if (*cp == '\n' || *cp == '\r') {
775: *cp = '\0';
776: break;
777: }
778: }
779:
780: /* Set the destination, opcode and xid */
781: bp_s->bp_ip.ip_dst = *(struct in_addr *)&bp_r->bp_siaddr;
782: nv_s->nv_opcode = nv_r->nv_opcode;
783: nv_s->nv_xid = nv_r->nv_xid;
784: break;
785:
786: case BPOP_ERROR:
787: /* Reset the destination, opcode and xid */
788: bp_s->bp_ip.ip_dst.s_addr = INADDR_BROADCAST;
789: nv_s->nv_opcode = BPOP_OK;
790: nv_s->nv_xid = 0;
791: break;
792: }
793: errout:
794: return (error);
795: }
796:
797: /*
798: * Routine: in_bootp_setaddress
799: * Function:
800: * Set the address of the interface. Leave the new address in ifr
801: * to be returned to the user.
802: */
803: int
804: in_bootp_setaddress(ifp, ifr, so, addr)
805: register volatile struct ifnet *ifp;
806: register struct ifreq *ifr;
807: struct socket *so;
808: struct in_addr *addr;
809: {
810: struct sockaddr_in *sin;
811: int error;
812: struct proc * procp = current_proc(); /* XXX */
813:
814: dprintf((" in_bootp_setaddress() entered\n"));
815:
816: ifr->ifr_flags = ifp->if_flags & ~(IFF_UP);
817: if (error = ifioctl(so, SIOCSIFFLAGS, (caddr_t) ifr, procp)) {
818: dprintf((" in_bootp_setaddress() SIOCSIFFLAGS failed: %d\n",
819: error));
820: return (error);
821: }
822:
823: /* Clear the netmask first */
824: sin = (struct sockaddr_in *)&(ifr->ifr_addr);
825: bzero((caddr_t)sin, sizeof(struct sockaddr_in));
826: sin->sin_len = sizeof(*sin);
827: sin->sin_family = AF_INET;
828: if (error = ifioctl(so, SIOCSIFNETMASK, (caddr_t)ifr, procp)) {
829: dprintf((" in_bootp_setaddress() SIOCSIFNETMASK failed: %d\n",
830: error));
831: return (error);
832: }
833:
834: /* Now set the new address */
835: sin->sin_addr.s_addr = addr->s_addr;
836: if (error = ifioctl(so, SIOCSIFADDR, (caddr_t)ifr, procp)) {
837: dprintf((" in_bootp_setaddress() SIOCSIFADDR failed: %d\n",
838: error));
839: return (error);
840: }
841:
842: /* Flag that we have autoconfigured */
843: ifp->if_eflags |= IFEF_AUTOCONF_DONE;
844:
845: dprintf((" in_bootp_setaddress() exiting\n"));
846:
847: return (0);
848: }
849:
850: /*
851: * Routine: in_bootp_makeifreq
852: * Function:
853: * Make a valid ifreq struct from interface pointer and an address
854: */
855: struct ifreq
856: in_bootp_makeifreq(
857: volatile struct ifnet *ifp,
858: struct sockaddr_in *sin
859: )
860: {
861: struct ifreq ifr;
862: char *p;
863:
864: strcpy(ifr.ifr_name, ifp->if_name);
865: for (p = ifr.ifr_name; *p; p++) {
866: }
867: *p++ = ifp->if_unit + '0';
868: *p = 0;
869: bcopy(sin, &ifr.ifr_addr, sizeof(*sin));
870: return (ifr);
871: }
872:
873: /*
874: * Routine: kmgets (mostly stolen from swapgeneric.{c,m}
875: * Function:
876: * Allows printing echoed or non-echoed text.
877: */
878: void
879: kmgets(cp, lp, silent)
880: char *cp, *lp;
881: boolean_t silent;
882: {
883: register c = 0;
884:
885: for (;;) {
886: if (silent) {
887: c = kmgetc_silent(0) & 0177;
888: } else {
889: c = kmgetc(0) & 0177;
890: }
891: switch (c) {
892: case '\n':
893: case '\r':
894: *lp++ = '\0';
895: return;
896: case '\177':
897: if (lp == cp) {
898: cnputc('\b');
899: continue;
900: }
901: cnputc('\b');
902: cnputc('\b');
903: /* fall into ... */
904: case '\b':
905: if (lp == cp) {
906: cnputc('\b');
907: continue;
908: }
909: cnputc(' ');
910: cnputc('\b');
911: lp--;
912: continue;
913: case '@':
914: case 'u'&037:
915: lp = cp;
916: cnputc('\n');
917: continue;
918: default:
919: *lp++ = c;
920: }
921: }
922: }
923:
924: #endif
925: #endif NEXT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.