Skip to content

Commit 2b921a0

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 2b921a0

File tree

1 file changed

+118
-44
lines changed

1 file changed

+118
-44
lines changed

src/dhcpv6-ia.c

Lines changed: 118 additions & 44 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;
11381156

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;
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;
1163+
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,6 +1243,7 @@ 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);
@@ -1226,19 +1257,24 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12261257
first = a;
12271258
}
12281259

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

12321265
/* Was only a solicitation: mark binding for removal in 60 seconds */
12331266
if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
1267+
12341268
a->bound = false;
12351269
a->valid_until = now + 60;
12361270

12371271
} else if (assigned &&
12381272
((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
12391273
hdr->msg_type == DHCPV6_MSG_REQUEST ||
12401274
hdr->msg_type == DHCPV6_MSG_REBIND)) {
1275+
12411276
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1277+
12421278
char *tmp = realloc(a->hostname, hostname_len + 1);
12431279
if (tmp) {
12441280
a->hostname = tmp;
@@ -1247,40 +1283,66 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12471283
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
12481284
}
12491285
}
1286+
12501287
a->accept_fr_nonce = accept_reconf;
12511288
a->bound = true;
12521289
apply_lease(a, true);
1290+
12531291
} else if (!assigned) {
1254-
/* Cleanup failed assignment */
1292+
/* Clean up failed assignment */
12551293
dhcpv6_free_lease(a);
12561294
a = NULL;
12571295
}
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) {
1296+
1297+
break;
1298+
}
1299+
1300+
case DHCPV6_MSG_RENEW:
1301+
case DHCPV6_MSG_RELEASE:
1302+
case DHCPV6_MSG_DECLINE: {
1303+
/* RENEW / RELEASE / DECLINE require an existing binding */
1304+
if (!a) {
12631305
status = DHCPV6_STATUS_NOBINDING;
12641306
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) {
1307+
break;
1308+
}
1309+
1310+
switch (hdr->msg_type) {
1311+
case DHCPV6_MSG_RENEW:
12671312
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) {
1313+
1314+
a->bound = true;
1315+
apply_lease(a, true);
1316+
break;
1317+
1318+
case DHCPV6_MSG_RELEASE:
1319+
/* Immediately expire the lease */
12731320
a->valid_until = now - 1;
1274-
} else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) {
1321+
break;
1322+
1323+
case DHCPV6_MSG_DECLINE:
1324+
/* DECLINE only applies to non-temporary addresses */
1325+
if (!(a->flags & OAF_DHCPV6_NA))
1326+
break;
1327+
12751328
a->bound = false;
12761329

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
1330+
if (a->lease_cfg &&
1331+
a->lease_cfg->hostid == a->assigned_host_id) {
1332+
/* Static lease: release immediately */
12811333
a->valid_until = now - 1;
1334+
} else {
1335+
/* Dynamic lease: block address for 1 hour */
1336+
memset(a->duid, 0, a->duid_len);
1337+
a->valid_until = now + 3600;
1338+
}
1339+
break;
12821340
}
1283-
} else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
1341+
1342+
break;
1343+
}
1344+
1345+
case DHCPV6_MSG_CONFIRM:
12841346
if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
12851347
notonlink = true;
12861348
break;
@@ -1290,13 +1352,25 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12901352
response_len = 0;
12911353
goto out;
12921354
}
1355+
break;
1356+
1357+
default:
1358+
break;
1359+
1360+
}
1361+
1362+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a) {
1363+
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1364+
a->bound = true;
1365+
apply_lease(a, true);
12931366
}
12941367

12951368
buf += ia_response_len;
12961369
buflen -= ia_response_len;
12971370
response_len += ia_response_len;
12981371
dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
1299-
}
1372+
1373+
} /* end dhcpv6_for_each_option */
13001374

13011375
switch (hdr->msg_type) {
13021376
case DHCPV6_MSG_RELEASE:

0 commit comments

Comments
 (0)