1#!/bin/bash
2# Copyright 2021 Google LLC
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#      http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# A list of functions which get executed for each bound DHCP lease.
17# These are configured by the files included below.
18# Shellcheck does not understand how this gets referenced
19# shellcheck disable=SC2034
20GBMC_BR_DHCP_HOOKS=()
21
22# A dict of outstanding items that should prevent DHCP completion
23declare -A GBMC_BR_DHCP_OUTSTANDING=()
24
25# SC can't find this path during repotest
26# shellcheck disable=SC1091
27source /usr/share/network/lib.sh || exit
28# SC can't find this path during repotest
29# shellcheck disable=SC1091
30source /usr/share/gbmc-br-lib.sh || exit
31
32# Load configurations from a known location in the filesystem to populate
33# hooks that are executed after each event.
34gbmc_br_source_dir /usr/share/gbmc-br-dhcp || exit
35
36# We don't want to allow 2 simultaneous sessions. Check for a pidfile
37PID_FILE=/run/gbmc-br-dhcp.pid
38exec {PID_FD}<>$PID_FILE
39# If we can't acquire the lock we already have a successful DHCP process in the works
40flock -xn $PID_FD || exit 0
41
42# Write out the current PID and cleanup when complete
43trap 'rm -f $PID_FILE' EXIT
44echo "$$" >&$PID_FD
45
46if [ "$1" = bound ]; then
47  # Variable is from the environment via udhcpc6
48  # shellcheck disable=SC2154
49  echo "DHCPv6(gbmcbr): $ipv6/128" >&2
50
51  update-dhcp-status 'ONGOING' "Received dhcp response ${ipv6}"
52  pfx_bytes=()
53  ip_to_bytes pfx_bytes "$ipv6"
54  # Ensure we are a BMC and have a suffix nibble, the 0th index is reserved
55  # Alternatively, we may also have received a /64 for the OOB address
56  if (( pfx_bytes[8] != 0xfd || (pfx_bytes[9] & 0xf) == 0 )) &&
57     (( pfx_bytes[8] != 0 || pfx_bytes[9] != 0 )); then
58    echo "Invalid address prefix ${ipv6}" >&2
59    update-dhcp-status 'ONGOING' "Invalid address prefix ${ipv6}"
60    exit 1
61  fi
62  # Ensure we don't have more than a /80 address
63  for (( i = 10; i < 16; ++i )); do
64    if (( pfx_bytes[i] != 0 )); then
65      echo "Invalid address ${ipv6}" >&2
66      update-dhcp-status 'ONGOING' "Invalid address ${ipv6}"
67      exit 1
68    fi
69  done
70
71  update-dhcp-status 'ONGOING' "Setting hostname ${fqdn} and ip ${ipv6}"
72
73  pfx="$(ip_bytes_to_str pfx_bytes)"
74  gbmc_br_set_ip "$pfx" || exit
75
76  if [ -n "${fqdn-}" ]; then
77    echo "Using hostname $fqdn" >&2
78    hostnamectl set-hostname "$fqdn" || true
79  fi
80
81  gbmc_br_run_hooks GBMC_BR_DHCP_HOOKS || exit
82
83  # If any of our hooks had expectations we should fail here
84  if [ "${#GBMC_BR_DHCP_OUTSTANDING[@]}" -gt 0 ]; then
85    echo "Not done with DHCP process: ${!GBMC_BR_DHCP_OUTSTANDING[*]}" >&2
86    update-dhcp-status 'ONGOING' "Outstanding DHCP hooks ${!GBMC_BR_DHCP_OUTSTANDING[*]}"
87    exit 1
88  fi
89
90  # Ensure that the installer knows we have completed processing DHCP by
91  # running a service that reports completion
92  echo 'Signaling dhcp done' >&2
93  update-dhcp-status 'DONE' "Netboot finished"
94fi
95