Skip to content

Commit 6df34ea

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> openwrt#360 Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
1 parent 5a13d87 commit 6df34ea

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
@@ -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,15 +1156,21 @@ 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;
1160+
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;
11421167

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;
1168+
assigned = (a != NULL);
11471169

11481170
if (!a) {
11491171
if ((!iface->no_dynamic_dhcp || (lease_cfg && is_na)) &&
11501172
(iface->dhcpv6_pd || iface->dhcpv6_na)) {
1173+
11511174
/* Create new binding */
11521175
a = dhcpv6_alloc_lease(duid_len);
11531176

@@ -1157,25 +1180,27 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11571180
a->iaid = ia->iaid;
11581181
a->length = reqlen;
11591182
a->peer = *addr;
1183+
a->iface = iface;
1184+
a->flags = is_pd ? OAF_DHCPV6_PD : OAF_DHCPV6_NA;
1185+
a->valid_until = now;
1186+
a->preferred_until = now;
1187+
11601188
if (is_na)
11611189
a->assigned_host_id = lease_cfg ? lease_cfg->hostid : 0;
11621190
else
11631191
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);
11681192

11691193
if (first)
11701194
memcpy(a->key, first->key, sizeof(a->key));
11711195
else
11721196
odhcpd_urandom(a->key, sizeof(a->key));
11731197

1174-
if (is_pd && iface->dhcpv6_pd)
1198+
if (is_pd && iface->dhcpv6_pd) {
11751199
while (!(assigned = assign_pd(iface, a)) &&
11761200
++a->length <= 64);
1177-
else if (is_na && iface->dhcpv6_na)
1201+
} else if (is_na && iface->dhcpv6_na) {
11781202
assigned = assign_na(iface, a);
1203+
}
11791204

11801205
if (lease_cfg && assigned) {
11811206
if (lease_cfg->hostname) {
@@ -1193,15 +1218,20 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
11931218
}
11941219
}
11951220

1196-
if (!assigned || iface->addr6_len == 0)
1221+
/* Status evaluation */
1222+
if (!assigned || iface->addr6_len == 0) {
11971223
/* 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)) {
1224+
status = is_pd ? DHCPV6_STATUS_NOPREFIXAVAIL : DHCPV6_STATUS_NOADDRSAVAIL;
1225+
} else if (hdr->msg_type == DHCPV6_MSG_REQUEST && !dhcpv6_ia_on_link(ia, a, iface)) {
12001226
/* Send NOTONLINK status for the IA */
12011227
status = DHCPV6_STATUS_NOTONLINK;
12021228
assigned = false;
1203-
} else if (accept_reconf && assigned && !first &&
1204-
hdr->msg_type != DHCPV6_MSG_REBIND) {
1229+
}
1230+
1231+
/* Reconfigure Accept */
1232+
if (accept_reconf && assigned && !first &&
1233+
hdr->msg_type != DHCPV6_MSG_REBIND) {
1234+
12051235
size_t handshake_len = 4;
12061236
buf[0] = 0;
12071237
buf[1] = DHCPV6_OPT_RECONF_ACCEPT;
@@ -1217,74 +1247,110 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12171247
1,
12181248
{0}
12191249
};
1250+
12201251
memcpy(auth.key, a->key, sizeof(a->key));
12211252
memcpy(buf + handshake_len, &auth, sizeof(auth));
12221253
handshake_len += sizeof(auth);
12231254
}
12241255

1225-
12261256
buf += handshake_len;
12271257
buflen -= handshake_len;
12281258
response_len += handshake_len;
12291259

12301260
first = a;
12311261
}
12321262

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

12361267
/* 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);
1268+
if (assigned) {
1269+
switch (hdr->msg_type) {
1270+
case DHCPV6_MSG_SOLICIT:
1271+
if (!rapid_commit) {
1272+
a->bound = false;
1273+
a->valid_until = now + 60;
1274+
break;
1275+
}
1276+
1277+
_o_fallthrough;
1278+
case DHCPV6_MSG_REQUEST:
1279+
case DHCPV6_MSG_REBIND:
1280+
if (hostname_len > 0 && (!a->lease_cfg || !a->lease_cfg->hostname)) {
1281+
1282+
char *tmp = realloc(a->hostname, hostname_len + 1);
1283+
if (tmp) {
1284+
a->hostname = tmp;
1285+
memcpy(a->hostname, hostname, hostname_len);
1286+
a->hostname[hostname_len] = 0;
1287+
a->hostname_valid = odhcpd_hostname_valid(a->hostname);
1288+
}
12521289
}
1290+
1291+
a->accept_fr_nonce = accept_reconf;
1292+
a->bound = true;
1293+
apply_lease(a, true);
1294+
break;
1295+
1296+
default:
1297+
break;
12531298
}
1254-
a->accept_fr_nonce = accept_reconf;
1255-
a->bound = true;
1256-
apply_lease(a, true);
1257-
} else if (!assigned) {
1258-
/* Cleanup failed assignment */
1299+
} else {
1300+
/* Clean up failed assignment */
12591301
dhcpv6_free_lease(a);
12601302
a = NULL;
12611303
}
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) {
1304+
1305+
break;
1306+
}
1307+
1308+
case DHCPV6_MSG_RENEW:
1309+
case DHCPV6_MSG_RELEASE:
1310+
case DHCPV6_MSG_DECLINE: {
1311+
/* RENEW / RELEASE / DECLINE require an existing binding */
1312+
if (!a) {
12671313
status = DHCPV6_STATUS_NOBINDING;
12681314
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) {
1315+
break;
1316+
}
1317+
1318+
switch (hdr->msg_type) {
1319+
case DHCPV6_MSG_RENEW:
12711320
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) {
1321+
1322+
a->bound = true;
1323+
apply_lease(a, true);
1324+
break;
1325+
1326+
case DHCPV6_MSG_RELEASE:
1327+
/* Immediately expire the lease */
12771328
a->valid_until = now - 1;
1278-
} else if ((a->flags & OAF_DHCPV6_NA) && hdr->msg_type == DHCPV6_MSG_DECLINE) {
1329+
break;
1330+
1331+
case DHCPV6_MSG_DECLINE:
1332+
/* DECLINE only applies to non-temporary addresses */
1333+
if (!(a->flags & OAF_DHCPV6_NA))
1334+
break;
1335+
12791336
a->bound = false;
12801337

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
1338+
if (a->lease_cfg &&
1339+
a->lease_cfg->hostid == a->assigned_host_id) {
1340+
/* Static lease: release immediately */
12851341
a->valid_until = now - 1;
1342+
} else {
1343+
/* Dynamic lease: block address for 1 hour */
1344+
memset(a->duid, 0, a->duid_len);
1345+
a->valid_until = now + 3600;
1346+
}
1347+
break;
12861348
}
1287-
} else if (hdr->msg_type == DHCPV6_MSG_CONFIRM) {
1349+
1350+
break;
1351+
}
1352+
1353+
case DHCPV6_MSG_CONFIRM:
12881354
if (ia_addr_present && !dhcpv6_ia_on_link(ia, a, iface)) {
12891355
notonlink = true;
12901356
break;
@@ -1294,13 +1360,23 @@ ssize_t dhcpv6_ia_handle_IAs(uint8_t *buf, size_t buflen, struct interface *ifac
12941360
response_len = 0;
12951361
goto out;
12961362
}
1363+
break;
1364+
1365+
default:
1366+
break;
1367+
}
1368+
1369+
if (hdr->msg_type == DHCPV6_MSG_REBIND && a) {
1370+
ia_response_len = build_ia(buf, buflen, status, ia, a, iface, false);
1371+
a->bound = true;
1372+
apply_lease(a, true);
12971373
}
12981374

12991375
buf += ia_response_len;
13001376
buflen -= ia_response_len;
13011377
response_len += ia_response_len;
13021378
dhcpv6_log(hdr->msg_type, iface, now, duidbuf, is_pd, a, status);
1303-
}
1379+
} /* end dhcpv6_for_each_option */
13041380

13051381
switch (hdr->msg_type) {
13061382
case DHCPV6_MSG_RELEASE:

0 commit comments

Comments
 (0)