| 84 | | -- The PVID options (if any) are added to this table so that |
| 85 | | -- section create below can add the just created vlan to the |
| 86 | | -- choice list of the PVID options... |
| 87 | | local pvid_opts = { } |
| 88 | | |
| 89 | | -- This function re-reads all existing vlan ids and populates |
| 90 | | -- PVID options choice lists |
| 91 | | local function populate_pvids() |
| 92 | | local vlan_ids = { } |
| 93 | | m.uci:foreach("network", "switch_vlan", |
| 94 | | function(s) |
| 95 | | if s.device == switch_name then |
| 96 | | local vid = s[has_vlan4k or "vlan"] or s["vlan"] |
| 97 | | if vid ~= nil then |
| 98 | | vlan_ids[#vlan_ids+1] = vid |
| 99 | | end |
| 100 | | end |
| 101 | | end) |
| 102 | | |
| 103 | | local opt, vid |
| 104 | | for _, opt in ipairs(pvid_opts) do |
| 105 | | opt:reset_values() |
| 106 | | opt:value("", translate("none")) |
| 107 | | for _, vid in luci.util.vspairs(vlan_ids) do |
| 108 | | opt:value(vid, translatef("VLAN %d", tonumber(vid))) |
| 109 | | end |
| 110 | | end |
| 111 | | end |
| 112 | | |
| 303 | | |
| 304 | | |
| 305 | | -- Does this switch support PVIDs? |
| 306 | | if has_ptpvid then |
| 307 | | |
| 308 | | -- Spawn a "virtual" section. We just attach it to the global |
| 309 | | -- switch section here, the overrides below take care of writing |
| 310 | | -- the actual values to the correct uci sections. |
| 311 | | s = m:section(TypedSection, "switch", |
| 312 | | translatef("Port PVIDs on %q", switch_name), |
| 313 | | translate("Port <abbr title=\"Primary VLAN IDs\">PVIDs</abbr> specify " .. |
| 314 | | "the default VLAN ID added to received untagged frames.")) |
| 315 | | |
| 316 | | s.template = "cbi/tblsection" |
| 317 | | s.addremove = false |
| 318 | | s.anonymous = true |
| 319 | | |
| 320 | | -- Filter by switch |
| 321 | | function s.filter(self, section) |
| 322 | | return (m:get(section, "name") == switch_name) |
| 323 | | end |
| 324 | | |
| 325 | | -- Build port list, store pointers to the option objects in the |
| 326 | | -- pvid_opts array so that other callbacks can repopulate their |
| 327 | | -- choice lists. |
| 328 | | local pt |
| 329 | | for pt = 0, num_ports - 1 do |
| 330 | | local po = s:option(ListValue, tostring(pt), |
| 331 | | (pt == cpu_port) and translate("CPU") or translatef("Port %d", (pt + 1))) |
| 332 | | |
| 333 | | -- When cbi queries the current config value for this post, |
| 334 | | -- lookup the associated switch_port section (if any) and |
| 335 | | -- return its "pvid" or "vlan" option value. |
| 336 | | po.cfgvalue = function(self, section) |
| 337 | | local val |
| 338 | | m.uci:foreach("network", "switch_port", |
| 339 | | function(s) |
| 340 | | if s.port == self.option then |
| 341 | | val = s[has_ptpvid] |
| 342 | | return false |
| 343 | | end |
| 344 | | end) |
| 345 | | return val |
| 346 | | end |
| 347 | | |
| 348 | | -- On write, find the actual switch_port section associated |
| 349 | | -- to this port and set the value there. Create a new |
| 350 | | -- switch_port section for this port if there is none yet. |
| 351 | | po.write = function(self, section, value) |
| 352 | | local found = false |
| 353 | | |
| 354 | | m.uci:foreach("network", "switch_port", |
| 355 | | function(s) |
| 356 | | if s.port == self.option then |
| 357 | | m.uci:set("network", s['.name'], has_ptpvid, value) |
| 358 | | found = true |
| 359 | | return false |
| 360 | | end |
| 361 | | end) |
| 362 | | |
| 363 | | if not found then |
| 364 | | m.uci:section("network", "switch_port", nil, { |
| 365 | | ["port"] = self.option, |
| 366 | | [has_ptpvid] = value |
| 367 | | }) |
| 368 | | end |
| 369 | | end |
| 370 | | |
| 371 | | -- If the user cleared the PVID value on this port, find |
| 372 | | -- the associated switch_port section and clear it. |
| 373 | | -- If the section does not contain any other unrelated |
| 374 | | -- options (like led or blinkrate) then remove it completely, |
| 375 | | -- else just clear out the "pvid" option. |
| 376 | | po.remove = function(self, section) |
| 377 | | m.uci:foreach("network", "switch_port", |
| 378 | | function(s) |
| 379 | | if s.port == self.option then |
| 380 | | local k, found |
| 381 | | local empty = true |
| 382 | | |
| 383 | | for k, _ in pairs(s) do |
| 384 | | if k:sub(1,1) ~= "." and k ~= "port" and k ~= has_ptpvid then |
| 385 | | empty = false |
| 386 | | break |
| 387 | | end |
| 388 | | end |
| 389 | | |
| 390 | | if empty then |
| 391 | | m.uci:delete("network", s['.name']) |
| 392 | | else |
| 393 | | m.uci:delete("network", s['.name'], has_ptpvid) |
| 394 | | end |
| 395 | | |
| 396 | | return false |
| 397 | | end |
| 398 | | end) |
| 399 | | end |
| 400 | | |
| 401 | | -- The referenced VLAN might just have been removed, simply |
| 402 | | -- return "" (none) in this case to avoid triggering a |
| 403 | | -- validation error. |
| 404 | | po.validate = function(...) |
| 405 | | return ListValue.validate(...) or "" |
| 406 | | end |
| 407 | | |
| 408 | | pvid_opts[#pvid_opts+1] = po |
| 409 | | end |
| 410 | | |
| 411 | | populate_pvids() |
| 412 | | end |