Skip to content

Commit 9857adb

Browse files
systemcrashNoltari
authored andcommitted
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> #360 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
1 parent 5a13d87 commit 9857adb

File tree

1 file changed

+139
-64
lines changed

1 file changed

+139
-64
lines changed

src/dhcpv6-ia.c

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

960960
dhcpv6_for_each_option(start, end, otype, olen, odata) {
961-
if (otype == DHCPV6_OPT_CLIENTID) {
961+
switch (otype) {
962+
case DHCPV6_OPT_CLIENTID:
962963
duid = odata;
963964
duid_len = olen;
964965

@@ -969,17 +970,33 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
969970

970971
if (olen <= DUID_MAX_LEN)
971972
odhcpd_hexlify(duidbuf, odata, olen);
972-
} else if (otype == DHCPV6_OPT_FQDN && olen >= 2 && olen <= 255) {
973+
break;
974+
975+
case DHCPV6_OPT_FQDN:
976+
if (olen < 2 || olen > 255)
977+
break;
978+
973979
uint8_t fqdn_buf[256];
974980
memcpy(fqdn_buf, odata, olen);
975981
fqdn_buf[olen++] = 0;
976982

977983
if (dn_expand(&fqdn_buf[1], &fqdn_buf[olen], &fqdn_buf[1], hostname, sizeof(hostname)) > 0)
978984
hostname_len = strcspn(hostname, ".");
979-
} else if (otype == DHCPV6_OPT_RECONF_ACCEPT)
985+
986+
break;
987+
988+
case DHCPV6_OPT_RECONF_ACCEPT:
980989
accept_reconf = true;
981-
else if (otype == DHCPV6_OPT_RAPID_COMMIT && hdr->msg_type == DHCPV6_MSG_SOLICIT)
982-
rapid_commit = true;
990+
break;
991+
992+
case DHCPV6_OPT_RAPID_COMMIT:
993+
if (hdr->msg_type == DHCPV6_MSG_SOLICIT)
994+
rapid_commit = true;
995+
break;
996+
997+
default:
998+
break;
999+
}
9831000
}
9841001

9851002
if (!duid || duid_len < DUID_MIN_LEN || duid_len > DUID_MAX_LEN)
@@ -1095,8 +1112,8 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
10951112
* If there's a DUID configured for this static lease, but without
10961113
* an IAID, we will proceed under the assumption that a request
10971114
* with the right DUID but with *any* IAID should be able to take
1098-
* over the assignment. E.g. when switching from WiFi to ethernet
1099-
* on the same client. This is similar to how multiple MAC adresses
1115+
* over the assignment. E.g. when switching from WiFi to Ethernet
1116+
* on the same client. This is similar to how multiple MAC addresses
11001117
* are handled for DHCPv4.
11011118
*/
11021119
for (size_t i = 0; i < lease_cfg->duid_count; i++) {
@@ -1139,11 +1156,16 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11391156
proceed:
11401157
/* Generic message handling */
11411158
uint16_t status = DHCPV6_STATUS_OK;
1159+
bool assigned = false;
11421160

1143-
if (hdr->msg_type == DHCPV6_MSG_SOLICIT ||
1144-
hdr->msg_type == DHCPV6_MSG_REQUEST ||
1145-
(hdr->msg_type == DHCPV6_MSG_REBIND && !a)) {
1146-
bool assigned = !!a;
1161+
switch (hdr->msg_type) {
1162+
case DHCPV6_MSG_SOLICIT:
1163+
case DHCPV6_MSG_REQUEST:
1164+
case DHCPV6_MSG_REBIND: {
1165+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a)
1166+
break;
1167+
1168+
assigned = (a != NULL);
11471169

11481170
if (!a) {
11491171
if ((!iface->no_dynamic_dhcp || (lease_cfg && is_na)) &&
@@ -1157,25 +1179,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11571179
a->iaid = ia->iaid;
11581180
a->length = reqlen;
11591181
a->peer = *addr;
1182+
a->iface = iface;
1183+
a->flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA;
1184+
a->valid_until = now;
1185+
a->preferred_until = now;
1186+
11601187
if (is_na)
11611188
a->assigned_host_id = lease_cfg ? lease_cfg->hostid : 0;
11621189
else
11631190
a->assigned_subnet_id = reqhint;
1164-
a->valid_until = now;
1165-
a->preferred_until = now;
1166-
a->iface = iface;
1167-
a->flags = (is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA);
11681191

11691192
if (first)
11701193
memcpy(a->key, first->key, sizeof(a->key));
11711194
else
11721195
odhcpd_urandom(a->key, sizeof(a->key));
11731196

1174-
if (is_pd && iface->dhcpv6_pd)
1197+
if (is_pd && iface->dhcpv6_pd) {
11751198
while (!(assigned = assign_pd(iface, a)) &&
11761199
++a->length <= 64);
1177-
else if (is_na && iface->dhcpv6_na)
1200+
} else if (is_na && iface->dhcpv6_na) {
11781201
assigned = assign_na(iface, a);
1202+
}
11791203

11801204
if (lease_cfg && assigned) {
11811205
if (lease_cfg->hostname) {
@@ -1193,15 +1217,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11931217
}
11941218
}
11951219

1196-
if (!assigned || iface->addr6_len == 0)
1220+
/* Status evaluation */
1221+
if (!assigned || iface->addr6_len == 0) {
11971222
/* Set error status */
1198-
status = (is_pd) ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1199-
else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
1223+
status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1224+
} else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
12001225
/* Send NOTONLINK status for the IA */
12011226
status = DHCPV6_STATUS_NOTONLINK;
12021227
assigned = false;
1203-
} else if (accept_reconf && assigned && !first &&
1204-
hdr->msg_type != DHCPV6_MSG_REBIND) {
1228+
}
1229+
1230+
/* Reconfigure Accept */
1231+
if (accept_reconf && assigned && !first &&
1232+
hdr->msg_type != DHCPV6_MSG_REBIND) {
1233+
12051234
size_t handshake_len = 4;
12061235
buf[0] = 0;
12071236
buf[1] = DHCPV6_OPT_RECONF_ACCEPT;
@@ -1217,74 +1246,110 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12171246
1,
12181247
{0}
12191248
};
1249+
12201250
memcpy(auth.key, a->key, sizeof(a->key));
12211251
memcpy(buf + handshake_len, &auth, sizeof(auth));
12221252
handshake_len += sizeof(auth);
12231253
}
12241254

1225-
12261255
buf += handshake_len;
12271256
buflen -= handshake_len;
12281257
response_len += handshake_len;
12291258

12301259
first = a;
12311260
}
12321261

1233-
ia_response_len = build_ia(buf, buflen, status, ia, a, iface,
1234-
hdr->msg_type == DHCPV6_MSG_REBIND ? false : true);
1262+
ia_response_len = build_ia(
1263+
buf, buflen, status, ia, a, iface,
1264+
hdr->msg_type != DHCPV6_MSG_REBIND);
12351265

12361266
/* Was only a solicitation: mark binding for removal in 60 seconds */
1237-
if (assigned && hdr->msg_type == DHCPV6_MSG_SOLICIT && !rapid_commit) {
1238-
a->bound = false;
1239-
a->valid_until = now + 60;
1240-
1241-
} else if (assigned &&
1242-
((hdr->msg_type == DHCPV6_MSG_SOLICIT && rapid_commit) ||
1243-
hdr->msg_type == DHCPV6_MSG_REQUEST ||
1244-
hdr->msg_type == DHCPV6_MSG_REBIND)) {
1245-
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1246-
char *tmp = realloc(a->hostname, hostname_len + 1);
1247-
if (tmp) {
1248-
a->hostname = tmp;
1249-
memcpy(a->hostname, hostname, hostname_len);
1250-
a->hostname[hostname_len] = 0;
1251-
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
1267+
if (assigned) {
1268+
switch (hdr->msg_type) {
1269+
case DHCPV6_MSG_SOLICIT:
1270+
if (!rapid_commit) {
1271+
a->bound = false;
1272+
a->valid_until = now + 60;
1273+
break;
1274+
}
1275+
1276+
_o_fallthrough;
1277+
case DHCPV6_MSG_REQUEST:
1278+
case DHCPV6_MSG_REBIND:
1279+
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1280+
1281+
char *tmp = realloc(a->hostname, hostname_len + 1);
1282+
if (tmp) {
1283+
a->hostname = tmp;
1284+
memcpy(a->hostname, hostname, hostname_len);
1285+
a->hostname[hostname_len] = 0;
1286+
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
1287+
}
12521288
}
1289+
1290+
a->accept_fr_nonce = accept_reconf;
1291+
a->bound = true;
1292+
apply_lease(a, true);
1293+
break;
1294+
1295+
default:
1296+
break;
12531297
}
1254-
a->accept_fr_nonce = accept_reconf;
1255-
a->bound = true;
1256-
apply_lease(a, true);
1257-
} else if (!assigned) {
1258-
/* Cleanup failed assignment */
1298+
} else {
1299+
/* Clean up failed assignment */
12591300
dhcpv6_free_lease(a);
12601301
a = NULL;
12611302
}
1262-
} else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1263-
hdr->msg_type == DHCPV6_MSG_RELEASE ||
1264-
hdr->msg_type == DHCPV6_MSG_REBIND ||
1265-
hdr->msg_type == DHCPV6_MSG_DECLINE) {
1266-
if (!a && hdr->msg_type != DHCPV6_MSG_REBIND) {
1303+
1304+
break;
1305+
}
1306+
1307+
case DHCPV6_MSG_RENEW:
1308+
case DHCPV6_MSG_RELEASE:
1309+
case DHCPV6_MSG_DECLINE: {
1310+
/* RENEW / RELEASE / DECLINE require an existing binding */
1311+
if (!a) {
12671312
status = DHCPV6_STATUS_NOBINDING;
12681313
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1269-
} else if (hdr->msg_type == DHCPV6_MSG_RENEW ||
1270-
hdr->msg_type == DHCPV6_MSG_REBIND) {
1314+
break;
1315+
}
1316+
1317+
switch (hdr->msg_type) {
1318+
case DHCPV6_MSG_RENEW:
12711319
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1272-
if (a) {
1273-
a->bound = true;
1274-
apply_lease(a, true);
1275-
}
1276-
} else if (hdr->msg_type == DHCPV6_MSG_RELEASE) {
1320+
1321+
a->bound = true;
1322+
apply_lease(a, true);
1323+
break;
1324+
1325+
case DHCPV6_MSG_RELEASE:
1326+
/* Immediately expire the lease */
12771327
a->valid_until = now - 1;
1278-
} else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) {
1328+
break;
1329+
1330+
case DHCPV6_MSG_DECLINE:
1331+
/* DECLINE only applies to non-temporary addresses */
1332+
if (!(a->flags & OAF_DHCPV6_NA))
1333+
break;
1334+
12791335
a->bound = false;
12801336

1281-
if (!a->lease_cfg || a->lease_cfg->hostid != a->assigned_host_id) {
1282-
memset(a->duid, 0, a->duid_len);
1283-
a->valid_until = now + 3600; /* Block address for 1h */
1284-
} else
1337+
if (a->lease_cfg &&
1338+
a->lease_cfg->hostid == a->assigned_host_id) {
1339+
/* Static lease: release immediately */
12851340
a->valid_until = now - 1;
1341+
} else {
1342+
/* Dynamic lease: block address for 1 hour */
1343+
memset(a->duid, 0, a->duid_len);
1344+
a->valid_until = now + 3600;
1345+
}
1346+
break;
12861347
}
1287-
} else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
1348+
1349+
break;
1350+
}
1351+
1352+
case DHCPV6_MSG_CONFIRM:
12881353
if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
12891354
notonlink = true;
12901355
break;
@@ -1294,13 +1359,23 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12941359
response_len = 0;
12951360
goto out;
12961361
}
1362+
break;
1363+
1364+
default:
1365+
break;
1366+
}
1367+
1368+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a) {
1369+
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1370+
a->bound = true;
1371+
apply_lease(a, true);
12971372
}
12981373

12991374
buf += ia_response_len;
13001375
buflen -= ia_response_len;
13011376
response_len += ia_response_len;
13021377
dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
1303-
}
1378+
} /* end dhcpv6_for_each_option */
13041379

13051380
switch (hdr->msg_type) {
13061381
case DHCPV6_MSG_RELEASE:

0 commit comments

Comments
 (0)