summaryrefslogtreecommitdiffstats
path: root/pxeserver.tpl
blob: 1fcadcfbc048d908e33a522bcdf19013af945324 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
#!/bin/sh
#
# Copyright 2011, 2016, 2017  Eric Hameleers, Eindhoven, NL
# Copyright 2011  Patrick Volkerding, Sebeka, Minnesota USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is 
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# Code used from SeTpxe and SeTnet scripts, part of the Slackware installer.
# ---------------------------------------------------------------------------

# PXEserver works as follows:
# - It requires a wired network; wireless PXE boot is impossible.
# - The pxeserver script tries to find a wired interface; you can pass an
#   explicit interfacename as parameter to the script (optional).
# - If multiple wired interfaces are detected, a dialog asks the user to
#   select the right one.
# - A check is done for DHCP configuration of this wired interface;
#   * If DHCP configuration is found then pxeserver will not start its own
#     DHCP server and instead will rely on your LAN's DHCP server.
#   * If no DHCP config is found, the script will ask permission to start
#     its own internal DHCP server.
#     Additionally the user will be prompted to configure an IP address for the
#     network interface and IP range properties for the internal DHCP server.
# - The script will then start the PXE server, comprising of:
#   * dnsmasq providing DNS, DHCP and BOOTP;
#   * NFS and RPC daemons;
# - The script will detect if you have an outside network connection on
#   another interface and will enable IP forwarding if needed, so that the
#   PXE clients will also have network access.
# - The Live OS booted via pxelinux is configured with additional boot
#   parameters:
#   * nfsroot=${LOCAL_IPADDR}:/mnt/livemedia
#   * luksvol=
#   * nop
#   * hostname=@DISTRO@
#   * tz=$(cat /etc/timezone)
#   * locale=${SYSLANG:-"en_US.UTF-8"}
#   * kbd=${KBD:-"us"}
#   Which shows that the configuration of the Live OS where the PXE server
#   runs is largely determining the configuration of the PXE clients.
# - Note that when networkbooting, the hostname of the Live OS will be
#   suffixed with the machine's MAC address to make every network-booted
#   Live OS unique.

#
# Initialization:
#

DEBUG=${DEBUG:-0}
DIALOG=dialog

# Number of PXE clients we want to serve with our own DHCP server:
DEF_DHCP_RANGE=${DEF_DHCP_RANGE:-10}

# Optional argument to the script is the name of the interface on which
# the PXE server should run:
INTERFACE="$1"

# This variable will be used to determine if the network default gateway
# is reached through a second NIC in the computer, or not.
GLOBAL_GW_INT=""

# In the above case, the global and local gateways will not be equal.
GLOBAL_GATEWAY=""
LOCAL_GATEWAY=""

# The Slackware setup depends on english language settings because it
# parses program output like that of "fdisk -l". So, we need to override
# the Live user's local language settings here:
SYSLANG=$LANG
export LANG=C
export LC_ALL=C

# Warn the user if the Live Media is inaccessible (however unlikely):
if [ ! -d /mnt/livemedia/@LIVEMAIN@/system ]; then
  if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
  $DIALOG --title "LIVE MEDIA NOT ACCESSIBLE" --msgbox "\
\n\
Before you can install software, complete the following tasks:\n\
\n\
1. Mount your Live media partition on /mnt/livemedia." 16 68
  exit 1
fi

TMP=/var/log/setup/tmp
if [ ! -d $TMP ]; then
  mkdir -p $TMP
fi
rm -f $TMP/SeT* $TMP/pxe*
echo "on" > $TMP/SeTcolor # turn on color menus
PATH="$PATH:/usr/share/@LIVEMAIN@"
export PATH;
export COLOR=on

# Add some eye candy for PXE clients:
if [ -d /mnt/livemedia/boot/syslinux ]; then
  PXETXTSRC=/mnt/livemedia/boot/syslinux
elif [ -d /mnt/livemedia/boot/extlinux ]; then
  PXETXTSRC=/mnt/livemedia/boot/extlinux
else
  PXETXTSRC=""
fi
if [ -n "$PXETXTSRC" ]; then
  ln -s ${PXETXTSRC}/message.txt /var/lib/tftpboot/
  ln -s ${PXETXTSRC}/f2.txt /var/lib/tftpboot/
  ln -s ${PXETXTSRC}/f3.txt /var/lib/tftpboot/
  ln -s ${PXETXTSRC}/f4.txt /var/lib/tftpboot/
fi

#
# Function definitions:
#

# Function to convert the netmask from CIDR format to dot notation.
cidr_cvt() {
  # Number of args to shift, 255..255, first non-255 byte, zeroes
  set -- $(( 5 - ($1 / 8) )) 255 255 255 255 $(( (255 << (8 - ($1 % 8))) & 255 )) 0 0 0
  [ $1 -gt 1 ] && shift $1 || shift
  echo ${1-0}.${2-0}.${3-0}.${4-0}
}

# Function to convert the netmask from dot notation to CIDR format.
mask_cvt ()
{
  # Assumes there's no "255." after a non-255 byte in the mask
  local x=${1##*255.}
  set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#x})*2 )) ${x%%.*}
  x=${1%%$3*}
  echo $(( $2 + (${#x}/4) ))
}

# IP Address to integer conversion:
ip_to_int() {
  IFS=.
  set -f
  set -- $1
  echo $(($1 << 24 | $2 << 16 | $3 << 8 | $4))
}

# Integer to IP Address conversion:
int_to_ip() {
  echo $(($1>>24)).$(($1>>16&0xff)).$(($1>>8&0xff)).$(($1&0xff))
}

# The network interface IP configuration routine.
# Will be called if the interface was not configured by DHCP.
# It ends with a configured network interface:
devconfig() {
  # Function accepts a parameter; if not given, use the global INTERFACE:
  MYIF=${1:-"$INTERFACE"}

  # Determine a LAN range we are going to be using for the internal DHCP
  # range that does not conflict with existing IP configuration:
  if ! ip -f inet -o addr show |grep -v " lo " |grep -qw 192.168 ; then
    MYIP="192.168.10.10"
  elif ! ip -f inet -o addr show |grep -v " lo " |grep -qw 172.16 ; then
    MYIP="172.16.10.10"
  else
    MYIP="10.10.10.10"
  fi

  # Main loop IP configuration:
  while [ 0 ]; do

    cat << EOF > $TMP/tempmsg

You will need to enter the IP address you wish to
assign to interface ${MYIF}. Example: ${MYIP}

What is your IP address?
EOF
    if [ "x$LOCAL_IPADDR" = "x" ]; then # assign default
      LOCAL_IPADDR=${MYIP}
    fi
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "ASSIGN IP ADDRESS" --inputbox "$(cat $TMP/tempmsg)" 12 \
      65 $LOCAL_IPADDR 2> $TMP/local
    if [ ! $? = 0 ]; then
      rm -f $TMP/tempmsg $TMP/local
      return
    fi
    LOCAL_IPADDR="$(cat $TMP/local)"
    rm -f $TMP/local
    clear
    cat << EOF > $TMP/tempmsg

Now we need to know your netmask.
Typically this will be 255.255.255.0
but this can be different depending on
your local setup.

What is your netmask?
EOF
    if [ "x$LOCAL_NETMASK" = "x" ]; then # assign default
      LOCAL_NETMASK=${NETMASK:-255.255.255.0}
    fi
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "ASSIGN NETMASK" --inputbox "$(cat $TMP/tempmsg)" 14 \
      65 $LOCAL_NETMASK 2> $TMP/mask
    if [ ! $? = 0 ]; then
      rm -f $TMP/tempmsg $TMP/mask
      return
    fi
    clear
    LOCAL_NETMASK="$(cat $TMP/mask)"
    rm $TMP/mask

    # GLOBAL_GATEWAY was determined right before calling this function:
    if [ "x$GLOBAL_GATEWAY" = "x" ]; then
      if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
      $DIALOG --yesno "Do you have a gateway?" 5 30
      HAVE_GATEWAY=$?
      clear
      if [ $HAVE_GATEWAY -eq 0 ]; then
        LOCAL_GATEWAY="$(echo $LOCAL_IPADDR | cut -f1-3 -d '.')."
        if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
        $DIALOG --title "ASSIGN GATEWAY ADDRESS" --inputbox \
          "\nWhat is the IP address for your gateway?" 9 65 \
          $LOCAL_GATEWAY 2> $TMP/gw
        if [ ! $? = 0 ]; then
          rm -f $TMP/tempmsg $TMP/gw
          LOCAL_GATEWAY=""
        else
          LOCAL_GATEWAY="$(cat $TMP/gw)"
          rm -f $TMP/gw
        fi
      fi
      unset HAVE_GATEWAY
      clear
    elif [ "$GLOBAL_GW_INT" = "$MYIF" ]; then
      LOCAL_GATEWAY=$GLOBAL_GATEWAY
    fi

    cat << EOF > $TMP/tempmsg

This is the proposed network configuration for $MYIF -
If this is OK, then select 'Yes'.
If this is not OK and you want to configure again, select 'No'.

* IP Address: $LOCAL_IPADDR 
* Netmask:    $LOCAL_NETMASK
* Gateway:    ${LOCAL_GATEWAY:-"$GLOBAL_GATEWAY (via $GLOBAL_GW_INT)"}
EOF
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --no-collapse --title "NETWORK CONFIGURATION" \
      --yesno "$(cat $TMP/tempmsg)" 14 68
    if [ $? -eq 1 ]; then
      continue # New round of questions
    fi

    #echo "Configuring ethernet card..."
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "INITIALIZING NETWORK" --infobox \
      "\nConfiguring your network interface $MYIF ..." 5 56

    # We don't need this anymore:
    dhcpcd -k $MYIF 1>/dev/null 2>&1
    rm -f /run/dhcpcd/dhcpcd-${MYIF}.pid

    # Broadcast and network are derived from IP and netmask:
    LOCAL_BROADCAST=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR | cut -f 1 -d ' ')
    LOCAL_NETWORK=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR | cut -f 2 -d ' ')
    if [ -x /etc/rc.d/rc.networkmanager 2>/dev/null ]; then
      # Use nmcli to reconfigure NetworkManager:
      nmcli con add con-name pxe-${MYIF} ifname ${MYIF} type ethernet ip4 $LOCAL_IPADDR/$(mask_cvt $LOCAL_NETMASK)
      if [ "x$GLOBAL_GATEWAY" = "x" -a "x$LOCAL_GATEWAY" != "x" ]; then
        nmcli con mod pxe-${MYIF} ipv4.gateway $LOCAL_GATEWAY
      fi
      nmcli dev connect ${MYIF}
    else
      # Use ifconfig and route commands:
      ifconfig $MYIF $LOCAL_IPADDR netmask $LOCAL_NETMASK broadcast $LOCAL_BROADCAST
      if [ "x$GLOBAL_GATEWAY" = "x" -a "x$LOCAL_GATEWAY" != "x" ]; then
        #echo "Configuring your gateway..."
        route add default gw $LOCAL_GATEWAY metric 1
      fi
    fi
    echo $LOCAL_IPADDR > $TMP/SeTIP
    echo $LOCAL_NETMASK > $TMP/SeTnetmask
    echo $LOCAL_GATEWAY > $TMP/SeTgateway
    clear
    break

  done # end main loop IP configuration

} # end devconfig()

# The PXE Server configuration routine:
pxeconfig() {

  # This function accepts a parameter (network interface to configure).
  # If no name was passed, we will do our best to find out ourselves.

  # Create empty PXE configuration file:
  echo "" > $TMP/SeTpxe

  # Find out what interface we should be using.
  # Did we get one passed as a parameter?
  if [ "x$1" = "x" ]; then
    # No parameter or it was empty; find out if we have a wired interface:
    WIRED_INT=""
    IINT=0
    for WINT in $(ls --indicator-style=none /sys/class/net |grep -v ^lo); do
      if ! grep -q $WINT /proc/net/wireless ; then
        WIRED_INT="$WIRED_INT $WINT"
        IINT=$(( $IINT + 1 ))
      fi
    done
    if [ $IINT -eq 0 ]; then
      # Zero wired interfaces found - exit.
      cat <<EOF > $TMP/tempmsg

Could not find a wired network interface. \n\
A PXE Server needs a configured network interface to work.\n\

EOF
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "MISSING NETWORK DEVICE" --msgbox "$(cat $TMP/tempmsg)"
8 68
      rm -f $TMP/tempmsg
      exit 1
    elif [ $IINT -eq 1 ]; then
      # Exactly one wired interfaces found - use it.
      INTERFACE=$(echo $WIRED_INT) # get rid of the space
    else
      # Multiple wired interfaces found - let the user select one:
      rm -f $TMP/iflist
      for WINT in $WIRED_INT ; do
        DRIVERTXT="IP=$(ip -f inet -o addr show ${WINT} |tr -s ' ' |head -1 |cut - f4 -d' ' |cut -f1 -d/)"
        if cat /sys/class/net/$WINT/device/uevent 1>/dev/null 2>/dev/null ; then
          DRIVERTXT="$DRIVERTXT driver=$(grep "DRIVER=" /sys/class/net/$WINT/device/uevent |cut -f2 -d=)"
        fi
        echo "$WINT \"network interface ($DRIVERTXT)\"" >> $TMP/iflist
      done
      if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
      $DIALOG --title "SELECT NETWORK INTERFACE" \
        --menu \
"Select an option below using the UP/DOWN keys and SPACE or ENTER.\n\
Alternate keys may also be used: '+', '-', and TAB." 13 72 9 \
        --file $TMP/iflist \
        2> $TMP/intset
      INTERFACE="$(cat $TMP/intset)"
      rm $TMP/intset $TMP/iflist
    fi
  fi # End undefined INTERFACE

  #
  # We now know what network interface to use.
  #

  # If dhcpcd is running, it likely has a lease from a LAN DHCP server,
  # so we should not activate another DHCP server ourselves now:
  if [ -s /run/dhcpcd/dhcpcd-${INTERFACE}.pid -a -n "$(ps -q $(cat /run/dhcpcd/dhcpcd-${INTERFACE}.pid) -o comm=)" ]; then
    OWNDHCP="no"
  else
    # Assume nothing... we will ask the user for confirmation later!
    OWNDHCP="yes"
  fi

  # If $INTERFACE != $GLOBAL_GW_INT then we are dealing with a dual-nic setup
  # and later on we can suggest configuring (NAT) routing:
  GLOBAL_GW_INT=$(ip -f inet -o route show default |grep -v linkdown |head -1 |tr -s ' ' |cut -f5 -d' ')
  GLOBAL_GATEWAY=$(ip -f inet -o route show default |grep -v linkdown |head -1 |tr -s ' ' |cut -f3 -d' ')

  #
  # Start the interactive part:
  #

  if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
  $DIALOG --backtitle "@CDISTRO@ Linux Live PXE Server." \
   --title "WELCOME TO PXE CONFIGURATION" --msgbox "\
We will be asking you a few questions now.\n\
The answers will be used to start a PXE service on this computer \
which does not interfere with other services in your network.\
\n\
The only assumption is, that there is NO PXE service already \
running on your local network at this moment.
\n\
If in doubt, stick with the defaults." 0 0

  if [ "$OWNDHCP" = "yes" ]; then
    # Be extra safe. Do not start a DHCP server if the user denies it:
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "ENABLE DHCP SERVER" --yesno " \
Network interface ${INTERFACE} did not get an IP address from a DHCP server. \
Slackware's PXE server starting on ${INTERFACE} needs a working DHCP server.\n\
Do you want this computer to start its own DHCP server on ${INTERFACE} \
(you can control what IP addresses are used by the DHCP server)?\n\
Say 'YES' if you are certain your network interface ${INTERFACE} is
not in reach of any DHCP server." 13 68
    if [ $? = 0 ]; then
      OWNDHCP="yes" 
    else
      OWNDHCP="no" 
    fi
  fi

  # Assemble the network parameters:
  LOCAL_IPADDR=$(ip -f inet -o addr show ${INTERFACE} |tr -s ' ' |head -1 |cut -f4 -d' ' |cut -f1 -d/)
  if [ "x$LOCAL_IPADDR" = "x" ]; then # no IP Address was configured?!?
    cat <<EOF > $TMP/tempmsg

Next step is to define an IP address for network interface ${INTERFACE}. \n\
A PXE Server needs a configured network interface to work.\n\

EOF
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --title "UNCONFIGURED NETWORK DEVICE" --msgbox "$(cat $TMP/tempmsg)" 9 68
    rm -f $TMP/tempmsg
    # Run the static IP configuration routine for $INTERFACE:
    devconfig ${INTERFACE}
  else
    # DHCP configured interface, we assume that the default gaeway is here.
    LOCAL_GATEWAY=$GLOBAL_GATEWAY
  fi

  # OK we have an IP Address, let's continue.
  LOCAL_NETMASK=$(ip -f inet -o addr show ${INTERFACE} |tr -s ' ' |head -1 |cut -f4 -d' ' |cut -f2 -d/)
  LOCAL_NETMASK=$(cidr_cvt $LOCAL_NETMASK)
  LOCAL_BROADCAST=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR |cut -f 1 -d ' ')
  LOCAL_NETWORK=$(ipmask $LOCAL_NETMASK $LOCAL_IPADDR |cut -f 2 -d ' ')

  if [ "$OWNDHCP" = "yes" ]; then
    # Find out a suitable IP address range for the DHCP server. Involves magic:
    I_LOCAL_IPADDR=$(ip_to_int "$LOCAL_IPADDR")
    I_LOCAL_NETMASK=$(ip_to_int "$LOCAL_NETMASK")
    I_MINLEASE_IP=$(( ($I_LOCAL_IPADDR & $I_LOCAL_NETMASK) + 1 ))
    I_MAXLEASE_IP=$(( ($I_LOCAL_IPADDR | ${I_LOCAL_NETMASK}^0xffffffff) - 1 ))
    if [ $(( $I_MAXLEASE_IP - $I_LOCAL_IPADDR )) -ge $DEF_DHCP_RANGE ]; then
      # Use $DEF_DHCP_RANGE IP addresses in the top of the address range:
      I_MINLEASE_IP=$(( $I_MAXLEASE_IP - $(($DEF_DHCP_RANGE - 1)) ))
    elif [ $(($I_LOCAL_IPADDR - $I_MINLEASE_IP)) -ge $DEF_DHCP_RANGE ]; then
      # Use $DEF_DHCP_RANGE IP addresses in the bottom of the address range:
      I_MAXLEASE_IP=$(( $I_MINLEASE_IP + $(($DEF_DHCP_RANGE - 1)) ))
    else
      # Smaller range available than we wanted, use what we can get:
      I_MINLEASE_IP=$(( $I_LOCAL_IPADDR + 1 ))
    fi

    MINLEASE_IP=$(int_to_ip "$I_MINLEASE_IP")
    MAXLEASE_IP=$(int_to_ip "$I_MAXLEASE_IP")

    while [ 0 ]; do
      if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
      ( $DIALOG --stdout --backtitle "@CDISTRO@ Linux Live PXE Server." \
          --title "DHCP SERVER CONFIGURATION" \
          --cancel-label Restart \
          --form "\
The PXE Service is going to run on $INTERFACE with these values \
(the defaults should be OK). \n\
You can change the range of IP addresses used by the DHCP server, if \
IP addresses in the proposed range are used by computers in your LAN. \
For instance, your default gateway if you have one. \n\
\n\
Also note that we will not validate any changes you make:" \
    18 68 0 \
    "IP Address:"                  1 1 "$LOCAL_IPADDR"   1 30   0 0 \
    "Netmask:"                     2 1 "$LOCAL_NETMASK"  2 30   0 0 \
    "Gateway:"                     3 1 "$LOCAL_GATEWAY"  3 30   0 0 \
    "Lowest DHCP Client Address:"  4 1 "$MINLEASE_IP"    4 30  15 0 \
    "Highest DHCP Client Address:" 5 1 "$MAXLEASE_IP"    5 30  15 0 \
      ) > $TMP/tempopts

      if [ $? = 0 ]; then
        # Remember... busybox ash is no good with arrays :/
        local i=0
        rm -f $TMP/tempkeys
        cat $TMP/tempopts | while read VALUE ; do
          if   [ $i = 0 ]; then echo "MINLEASE_IP=\"$VALUE\"" >> $TMP/tempkeys
          elif [ $i = 1 ]; then echo "MAXLEASE_IP=\"$VALUE\"" >> $TMP/tempkeys
          fi
          i=$(expr $i + 1)
        done
        eval $(cat $TMP/tempkeys)
        rm $TMP/tempopts
        break
      fi
    done
  else
    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --backtitle "@CDISTRO@ Linux Live PXE Server." \
      --title "DHCP SERVER CONFIGURATION" --msgbox "\
\n\
PXE server has been configured to use a DHCP server in your network.\n\
\n\
Press ENTER to continue." 14 68
  fi # [ "$OWNDHCP" = "yes" ]

  echo "DHCP=${OWNDHCP}" >> $TMP/SeTpxe
  echo "GLOBAL_GATEWAY=${GLOBAL_GATEWAY}" >> $TMP/SeTpxe
  echo "GLOBAL_GW_INT=${GLOBAL_GW_INT}" >> $TMP/SeTpxe
  echo "LOCAL_IPADDR=${LOCAL_IPADDR}" >> $TMP/SeTpxe
  echo "LOCAL_NETMASK=${LOCAL_NETMASK}" >> $TMP/SeTpxe
  echo "LOCAL_GATEWAY=${LOCAL_GATEWAY}" >> $TMP/SeTpxe
  echo "LOCAL_BROADCAST=${LOCAL_BROADCAST}" >> $TMP/SeTpxe
  echo "LOCAL_NETWORK=${LOCAL_NETWORK}" >> $TMP/SeTpxe
  echo "MINLEASE_IP=${MINLEASE_IP}" >> $TMP/SeTpxe
  echo "MAXLEASE_IP=${MAXLEASE_IP}" >> $TMP/SeTpxe

  # Write out a suitable dnsmasq configuration:
  cat <<EOF > ${TMP}/pxe_dnsmasq.conf
# Only listen at our designated interface:
listen-address=$LOCAL_IPADDR

# Write the pid file:
pid-file=${TMP}/pxe_dnsmasq.pid

# Start a TFTP server:
enable-tftp

# Set the root directory for files available via FTP:
tftp-root=/var/lib/tftpboot

# The boot filename:
dhcp-boot=/pxelinux.0

# Disable re-use of the DHCP servername and filename fields as extra
# option space. That's to avoid confusing some old or broken DHCP clients.
dhcp-no-override

# Log connections so that we can display them on the console:
log-facility=/var/log/pxe_dnsmasq.log
log-dhcp

# Custom path for the leases file:
dhcp-leasefile=$TMP/pxe_dnsmasq.leases

# Craft a nice PXE menu:
pxe-prompt="Press F8 for boot menu", 3

# The known types are x86PC, PC98, IA64_EFI, Alpha, Arc_x86,
# Intel_Lean_Client, IA32_EFI, BC_EFI, Xscale_EFI and X86-64_EFI
pxe-service=X86PC, "Boot from network", /var/lib/tftpboot/pxelinux

# A boot service type of 0 is special, and will abort the
# net boot procedure and continue booting from local media.
pxe-service=X86PC, "Boot from local hard disk", 0                               

EOF

  if [ -n "$LOCAL_GATEWAY" -a "$INTERFACE" = "$GLOBAL_GW_INT"  ]; then
    # The default gw can be reached through our $INTERFACE.
    cat <<EOF >> ${TMP}/pxe_dnsmasq.conf
# Override the default route supplied by dnsmasq, which assumes the
# router is the same machine as the one running dnsmasq.
#dhcp-option=option:router,${LOCAL_GATEWAY}
dhcp-option=3,${LOCAL_GATEWAY}

EOF
  else
    # The default gw is reached through a second interface on the computer.
    # We need to build a router, a bridge or a NAT firewall between the two.
    cat <<EOF >> ${TMP}/pxe_dnsmasq.conf
# Apply the default route supplied by dnsmasq, which assumes the
# router is the same machine as the one running dnsmasq.
# And we want to let our PXE clients use $INTERFACE as the default gw.
#dhcp-option=option:router,${LOCAL_IPADDR}

EOF
  fi

  if [ "$OWNDHCP" = "yes" ]; then
    cat <<EOF >> ${TMP}/pxe_dnsmasq.conf
# dnsmasq functions as a normal DHCP server, providing IP leases.
dhcp-range=${MINLEASE_IP},${MAXLEASE_IP},${LOCAL_NETMASK},1h

EOF
  else
    cat <<EOF >> ${TMP}/pxe_dnsmasq.conf
# There is an existing DHCP server on this LAN, so dnsmasq functions
# as a proxy DHCP server providing boot information but no IP leases.
# Any ip in the subnet will do, so you may just put your server NIC ip here.
dhcp-range=${LOCAL_IPADDR},proxy

EOF
  fi

  # Create the pxelinux configuration file:
  KBD=$(sed -n "s%^ */usr/bin/loadkeys *%%p" /etc/rc.d/rc.keymap 2>/dev/null)
  cat <<EOF > /var/lib/tftpboot/pxelinux.cfg/default
default pxelive
prompt 1
timeout 300
display message.txt
F1 message.txt
F2 f2.txt
F3 f3.txt
F4 f4.txt
label pxelive
  kernel /generic
  append initrd=/initrd.img load_ramdisk=1 prompt_ramdisk=0 rw printk.time=0 nfsroot=${LOCAL_IPADDR}:/mnt/livemedia luksvol= nop hostname=@DISTRO@ tz=$(cat /etc/timezone) locale=${SYSLANG:-"en_US.UTF-8"} kbd=${KBD:-"us"}
EOF

} # end of pxeconfig()

# -------------------------------------------------------- #
# Above was just initialization and function definitions.  #
# Let's make use of all that.                              #
# ---------------------------------------------------------#

# Main loop:
while [ 0 ]; do

  if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
  $DIALOG --title "@CDISTRO@ Linux Live PXE Server (version current)" \
    --menu \
"Welcome to @CDISTRO@ Linux Live PXE Server.\n\
Select an option below using the UP/DOWN keys and SPACE or ENTER.\n\
Alternate keys may also be used: '+', '-', and TAB." 13 72 9 \
"NETWORK" "Configure your network parameters" \
"ACTIVATE" "Activate the @CDISTRO@ PXE Server" \
"EXIT" "Exit @CDISTRO@ PXE Setup" 2> $TMP/hdset
  if [ ! $? = 0 ]; then
    rm -f $TMP/hdset $TMP/SeT*
    exit
  fi
  MAINSELECT="`cat $TMP/hdset`"
  rm $TMP/hdset

  # Start checking what to do. Some modules may reset MAINSELECT to run the
  # next item in line.

  if [ "$MAINSELECT" = "NETWORK" ]; then
    # Set up our network. We may not know anything yet in which case
    # the variable $INTERFACE will be empty.
    pxeconfig $INTERFACE
    if [ -r $TMP/SeTpxe ]; then
      MAINSELECT="ACTIVATE"
    fi
  fi
 
  if [ "$MAINSELECT" = "ACTIVATE" ]; then
    if [ ! -r $TMP/SeTpxe ]; then
      if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
      $DIALOG --title "CANNOT START PXE SERVER YET" --msgbox "\
\n\
Before you can start the PXE Server, complete the following task:\n\
\n\
(*) Set up your computer's network parameters.\n\
\n\
Press ENTER to return to the main menu." 14 68
      continue
    else
      if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
      $DIALOG --title "READY TO START PXE SERVER" --msgbox "\
\n\
Ready to start the PXE Server!\n\
The PXE server log will be displayed in the next screen.
\n\
Press ENTER to start." 14 68
    fi

    # Time to start the BOOTP/TFTP/NFS servers:
    echo > /var/log/pxe_dnsmasq.log
    dnsmasq -C ${TMP}/pxe_dnsmasq.conf -z -i ${INTERFACE}
    if ! grep -q "^/mnt/livemedia" /etc/exports ; then
      # Without 'fsid' nfsd refuses to export the filesystem if it RAM based;
      # the number '14' could be any unique low-range number:
      cat <<EOT >> /etc/exports
/mnt/livemedia  ${LOCAL_NETWORK}/${LOCAL_NETMASK}(ro,sync,insecure,no_subtree_check,root_squash,fsid=14)
EOT
    fi
    sh /etc/rc.d/rc.nfsd restart
    if [ "$INTERFACE" != "$GLOBAL_GW_INT" ]; then
      # The default gateway for this computer is on another interface;
      # we need to enable forwarding:
      OLDROUTING=$(cat /proc/sys/net/ipv4/ip_forward)
      echo 1 > /proc/sys/net/ipv4/ip_forward
      # also start the route daemon:
      if [ -z "$(pidof routed)" ]; then
        /usr/sbin/routed -g -s
      fi
    else
      OLDROUTING=""
    fi

    if [ $DEBUG -ne 0 ]; then read -p "Press ENTER to continue: " JUNK ; fi
    $DIALOG --backtitle "Slackware PXE Server." \
      --title "PXE Client activity log" \
      --ok-label "EXIT" \
      --tailbox /var/log/pxe_dnsmasq.log 20 68

    # Time to kill the BOOTP/TFTP/NFS servers:
    [ -n "$OLDROUTING" ] && echo $OLDROUTING > /proc/sys/net/ipv4/ip_forward
    kill -TERM $(cat ${TMP}/pxe_dnsmasq.pid)
    sh /etc/rc.d/rc.nfsd stop
    sed -i -e "s%^/mnt/livemedia.*%#&%" /etc/exports
  fi

  if [ "$MAINSELECT" = "EXIT" ]; then
    clear
    break
  fi

done # end of main loop

# end @CDISTRO@ Linux Live PXE Server script