Skip to content

Commit 1aad8be

Browse files
committed
dhcpv6-ia: switch case refactor in dhcpv6_handle_ias()
Rewrite core logic using switch cases for clarity and improved performance. This also simplifies the DHCPV6_MSG_REBIND cases: DHCPV6_MSG_REBIND and !a is parsed in the switch DHCPV6_MSG_REBIND and a is now parsed after the switch (5 lines) Signed-off-by: Paul Donald <newtwen+github@gmail.com>
1 parent 1450e1e commit 1aad8be

File tree

1 file changed

+140
-64
lines changed

1 file changed

+140
-64
lines changed

src/dhcpv6-ia.c

Lines changed: 140 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -954,7 +954,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
954954
char duidbuf[DUID_HEXSTRLEN], hostname[256];
955955

956956
dhcpv6_for_each_option(start, end, otype, olen, odata) {
957-
if (otype == DHCPV6_OPT_CLIENTID) {
957+
switch (otype) {
958+
case DHCPV6_OPT_CLIENTID:
958959
duid = odata;
959960
duid_len = olen;
960961

@@ -965,17 +966,33 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
965966

966967
if (olen <= DUID_MAX_LEN)
967968
odhcpd_hexlify(duidbuf, odata, olen);
968-
} else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) {
969+
break;
970+
971+
case DHCPV6_OPT_FQDN:
972+
if (olen < 2 || olen > 255)
973+
break;
974+
969975
uint8_t fqdn_buf[256];
970976
memcpy(fqdn_buf, odata, olen);
971977
fqdn_buf[olen++] = 0;
972978

973979
if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0)
974980
hostname_len = strcspn(hostname, ".");
975-
} else if (otype == DHCPV6_OPT_RECONF_ACCEPT)
981+
982+
break;
983+
984+
case DHCPV6_OPT_RECONF_ACCEPT:
976985
accept_reconf = true;
977-
else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT)
978-
rapid_commit = true;
986+
break;
987+
988+
case DHCPV6_OPT_RAPID_COMMIT:
989+
if (hdr->msg_type == DHCPV6_MSG_SOLICIT)
990+
rapid_commit = true;
991+
break;
992+
993+
default:
994+
break;
995+
}
979996
}
980997

981998
if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN)
@@ -1091,8 +1108,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
10911108
* If there's a DUID configured for this static lease, but without
10921109
* an IAID, we will proceed under the assumption that a request
10931110
* with the right DUID but with *any* IAID should be able to take
1094-
* over the assignment. E.g. when switching from WiFi to ethernet
1095-
* on the same client. This is similar to how multiple MAC adresses
1111+
* over the assignment. E.g. when switching from WiFi to Ethernet
1112+
* on the same client. This is similar to how multiple MAC addresses
10961113
* are handled for DHCPv4.
10971114
*/
10981115
for (size_t i = 0; i < lease_cfg->duid_count; i++) {
@@ -1135,15 +1152,21 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11351152
proceed:
11361153
/* Generic message handling */
11371154
uint16_t status = DHCPV6_STATUS_OK;
1155+
bool assigned = false;
1156+
1157+
switch (hdr->msg_type) {
1158+
case DHCPV6_MSG_SOLICIT:
1159+
case DHCPV6_MSG_REQUEST:
1160+
case DHCPV6_MSG_REBIND: {
1161+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a)
1162+
break;
11381163

1139-
if (hdr->msg_type == DHCPV6_MSG_SOLICIT ||
1140-
hdr->msg_type == DHCPV6_MSG_REQUEST ||
1141-
(hdr->msg_type == DHCPV6_MSG_REBIND && !a)) {
1142-
bool assigned = !!a;
1164+
assigned = (a != NULL);
11431165

11441166
if (!a) {
11451167
if ((!iface->no_dynamic_dhcp || (lease_cfg && is_na)) &&
11461168
(iface->dhcpv6_pd || iface->dhcpv6_na)) {
1169+
11471170
/* Create new binding */
11481171
a = dhcpv6_alloc_lease(duid_len);
11491172

@@ -1153,25 +1176,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11531176
a->iaid = ia->iaid;
11541177
a->length = reqlen;
11551178
a->peer = *addr;
1179+
a->iface = iface;
1180+
a->flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA;
1181+
a->valid_until = now;
1182+
a->preferred_until = now;
1183+
11561184
if (is_na)
11571185
a->assigned_host_id = lease_cfg ? lease_cfg->hostid : 0;
11581186
else
11591187
a->assigned_subnet_id = reqhint;
1160-
a->valid_until = now;
1161-
a->preferred_until = now;
1162-
a->iface = iface;
1163-
a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA);
11641188

11651189
if (first)
11661190
memcpy(a->key, first->key, sizeof(a->key));
11671191
else
11681192
odhcpd_urandom(a->key, sizeof(a->key));
11691193

1170-
if (is_pd && iface->dhcpv6_pd)
1194+
if (is_pd && iface->dhcpv6_pd) {
11711195
while (!(assigned = assign_pd(iface, a)) &&
11721196
++a->length <= 64);
1173-
else if (is_na && iface->dhcpv6_na)
1197+
} else if (is_na && iface->dhcpv6_na) {
11741198
assigned = assign_na(iface, a);
1199+
}
11751200

11761201
if (lease_cfg && assigned) {
11771202
if (lease_cfg->hostname) {
@@ -1189,15 +1214,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11891214
}
11901215
}
11911216

1192-
if (!assigned || iface->addr6_len == 0)
1217+
/* Status evaluation */
1218+
if (!assigned || iface->addr6_len == 0) {
11931219
/* Set error status */
1194-
status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1195-
else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
1220+
status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1221+
} else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
11961222
/* Send NOTONLINK status for the IA */
11971223
status = DHCPV6_STATUS_NOTONLINK;
11981224
assigned = false;
1199-
} else if (accept_reconf && assigned && !first &&
1200-
hdr->msg_type != DHCPV6_MSG_REBIND) {
1225+
}
1226+
1227+
/* Reconfigure Accept */
1228+
if (accept_reconf && assigned && !first &&
1229+
hdr->msg_type != DHCPV6_MSG_REBIND) {
1230+
12011231
size_t handshake_len = 4;
12021232
buf[0] = 0;
12031233
buf[1] = DHCPV6_OPT_RECONF_ACCEPT;
@@ -1213,74 +1243,110 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12131243
1,
12141244
{0}
12151245
};
1246+
12161247
memcpy(auth.key, a->key, sizeof(a->key));
12171248
memcpy(buf + handshake_len, &auth, sizeof(auth));
12181249
handshake_len += sizeof(auth);
12191250
}
12201251

1221-
12221252
buf += handshake_len;
12231253
buflen -= handshake_len;
12241254
response_len += handshake_len;
12251255

12261256
first = a;
12271257
}
12281258

1229-
ia_response_len = build_ia(buf, buflen, status, ia, a, iface,
1230-
hdr->msg_type == DHCPV6_MSG_REBIND ? false : true);
1259+
ia_response_len = build_ia(
1260+
buf, buflen, status, ia, a, iface,
1261+
hdr->msg_type != DHCPV6_MSG_REBIND);
12311262

12321263
/* Was only a solicitation: mark binding for removal in 60 seconds */
1233-
if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
1234-
a->bound = false;
1235-
a->valid_until = now + 60;
1236-
1237-
} else if (assigned &&
1238-
((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
1239-
hdr->msg_type == DHCPV6_MSG_REQUEST ||
1240-
hdr->msg_type == DHCPV6_MSG_REBIND)) {
1241-
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1242-
char *tmp = realloc(a->hostname, hostname_len + 1);
1243-
if (tmp) {
1244-
a->hostname = tmp;
1245-
memcpy(a->hostname, hostname, hostname_len);
1246-
a->hostname[hostname_len] = 0;
1247-
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
1264+
if (assigned) {
1265+
switch (hdr->msg_type) {
1266+
case DHCPV6_MSG_SOLICIT:
1267+
if (!rapid_commit) {
1268+
a->bound = false;
1269+
a->valid_until = now + 60;
1270+
break;
1271+
}
1272+
1273+
_o_fallthrough;
1274+
case DHCPV6_MSG_REQUEST:
1275+
case DHCPV6_MSG_REBIND:
1276+
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1277+
1278+
char *tmp = realloc(a->hostname, hostname_len + 1);
1279+
if (tmp) {
1280+
a->hostname = tmp;
1281+
memcpy(a->hostname, hostname, hostname_len);
1282+
a->hostname[hostname_len] = 0;
1283+
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
1284+
}
12481285
}
1286+
1287+
a->accept_fr_nonce = accept_reconf;
1288+
a->bound = true;
1289+
apply_lease(a, true);
1290+
break;
1291+
1292+
default:
1293+
break;
12491294
}
1250-
a->accept_fr_nonce = accept_reconf;
1251-
a->bound = true;
1252-
apply_lease(a, true);
1253-
} else if (!assigned) {
1254-
/* Cleanup failed assignment */
1295+
} else {
1296+
/* Clean up failed assignment */
12551297
dhcpv6_free_lease(a);
12561298
a = NULL;
12571299
}
1258-
} else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1259-
hdr->msg_type == DHCPV6_MSG_RELEASE ||
1260-
hdr->msg_type == DHCPV6_MSG_REBIND ||
1261-
hdr->msg_type == DHCPV6_MSG_DECLINE) {
1262-
if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) {
1300+
1301+
break;
1302+
}
1303+
1304+
case DHCPV6_MSG_RENEW:
1305+
case DHCPV6_MSG_RELEASE:
1306+
case DHCPV6_MSG_DECLINE: {
1307+
/* RENEW / RELEASE / DECLINE require an existing binding */
1308+
if (!a) {
12631309
status = DHCPV6_STATUS_NOBINDING;
12641310
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1265-
} else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1266-
hdr->msg_type == DHCPV6_MSG_REBIND) {
1311+
break;
1312+
}
1313+
1314+
switch (hdr->msg_type) {
1315+
case DHCPV6_MSG_RENEW:
12671316
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1268-
if (a) {
1269-
a->bound = true;
1270-
apply_lease(a, true);
1271-
}
1272-
} else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
1317+
1318+
a->bound = true;
1319+
apply_lease(a, true);
1320+
break;
1321+
1322+
case DHCPV6_MSG_RELEASE:
1323+
/* Immediately expire the lease */
12731324
a->valid_until = now - 1;
1274-
} else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) {
1325+
break;
1326+
1327+
case DHCPV6_MSG_DECLINE:
1328+
/* DECLINE only applies to non-temporary addresses */
1329+
if (!(a->flags & OAF_DHCPV6_NA))
1330+
break;
1331+
12751332
a->bound = false;
12761333

1277-
if (!a->lease_cfg || a->lease_cfg->hostid != a->assigned_host_id) {
1278-
memset(a->duid, 0, a->duid_len);
1279-
a->valid_until = now + 3600; /* Block address for 1h */
1280-
} else
1334+
if (a->lease_cfg &&
1335+
a->lease_cfg->hostid == a->assigned_host_id) {
1336+
/* Static lease: release immediately */
12811337
a->valid_until = now - 1;
1338+
} else {
1339+
/* Dynamic lease: block address for 1 hour */
1340+
memset(a->duid, 0, a->duid_len);
1341+
a->valid_until = now + 3600;
1342+
}
1343+
break;
12821344
}
1283-
} else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
1345+
1346+
break;
1347+
}
1348+
1349+
case DHCPV6_MSG_CONFIRM:
12841350
if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
12851351
notonlink = true;
12861352
break;
@@ -1290,13 +1356,23 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12901356
response_len = 0;
12911357
goto out;
12921358
}
1359+
break;
1360+
1361+
default:
1362+
break;
1363+
}
1364+
1365+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a) {
1366+
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1367+
a->bound = true;
1368+
apply_lease(a, true);
12931369
}
12941370

12951371
buf += ia_response_len;
12961372
buflen -= ia_response_len;
12971373
response_len += ia_response_len;
12981374
dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
1299-
}
1375+
} /* end dhcpv6_for_each_option */
13001376

13011377
switch (hdr->msg_type) {
13021378
case DHCPV6_MSG_RELEASE:

0 commit comments

Comments
 (0)