<div dir="ltr"><span style="font-size:12.8000001907349px">Signed-off-by: Aleksandr Kolesnik <</span><a href="mailto:neryba@gmail.com" target="_blank" style="font-size:12.8000001907349px">neryba@gmail.com</a><span style="font-size:12.8000001907349px">></span><br><div><span style="font-size:12.8000001907349px"><br></span></div><div><div style><span style="font-size:12.8000001907349px">--- a/contrib/package/luci/Makefile</span></div><div style><span style="font-size:12.8000001907349px">+++ b/contrib/package/luci/Makefile</span></div><div style><span style="font-size:12.8000001907349px">@@ -194,6 +194,7 @@ $(eval $(call protocol,ipv6,Support for </span></div><div style><span style="font-size:12.8000001907349px"> $(eval $(call protocol,3g,Support for 3G,+PACKAGE_luci-proto-3g:comgt))</span></div><div style><span style="font-size:12.8000001907349px"> $(eval $(call protocol,hso,Support for HSO,+PACKAGE_luci-proto-hso:comgt +PACKAGE_luci-proto-hso:kmod-usb-net +PACKAGE_luci-proto-hso:kmod-usb-net-hso))</span></div><div style><span style="font-size:12.8000001907349px"> $(eval $(call protocol,relay,Support for relayd pseudo bridges,+PACKAGE_luci-proto-relay:relayd))</span></div><div style><span style="font-size:12.8000001907349px">+$(eval $(call protocol,wwan,Support for 3G/4g wwan,+PACKAGE_luci-proto-wwan:wwan))</span></div><div style><span style="font-size:12.8000001907349px"> </span></div><div style><span style="font-size:12.8000001907349px"> </span></div><div style><span style="font-size:12.8000001907349px"> ### Modules ###</span></div><div style><span style="font-size:12.8000001907349px">--- a/modules/base/luasrc/model/network.lua</span></div><div style><span style="font-size:12.8000001907349px">+++ b/modules/base/luasrc/model/network.lua</span></div><div style><span style="font-size:12.8000001907349px">@@ -756,7 +756,11 @@ function protocol.ifname(self)</span></div><div style><span style="font-size:12.8000001907349px"> end</span></div><div style><span style="font-size:12.8000001907349px"> </span></div><div style><span style="font-size:12.8000001907349px"> function protocol.proto(self)</span></div><div style><span style="font-size:12.8000001907349px">-<span class="" style="white-space:pre">      </span>return "none"</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>local p = self:_ubus("proto")</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>if not p then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">               </span>p = "none"</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">        </span>end</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre"> </span>return p</span></div><div style><span style="font-size:12.8000001907349px"> end</span></div><div style><span style="font-size:12.8000001907349px"> </span></div><div style><span style="font-size:12.8000001907349px"> function protocol.get_i18n(self)</span></div><div style><span style="font-size:12.8000001907349px">@@ -934,7 +938,16 @@ function protocol.del_interface(self, if</span></div><div style><span style="font-size:12.8000001907349px"> end</span></div><div style><span style="font-size:12.8000001907349px"> </span></div><div style><span style="font-size:12.8000001907349px"> function protocol.get_interface(self)</span></div><div style><span style="font-size:12.8000001907349px">-<span class="" style="white-space:pre">     </span>if self:is_virtual() then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">   </span>if self:is_virtual() and self:proto() == "wwan" then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">              </span>local ldev = self:_ubus("l3_device")</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">              </span>if ldev then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                        </span>_tunnel[ldev] = true</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                        </span>return interface(ldev, self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                </span>else</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                        </span>_tunnel[self:proto() .. "-" .. self.sid] = true</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                   </span>return interface(self:proto() .. "-" .. self.sid, self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">           </span>end</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre"> </span>elseif self:is_virtual() then</span></div><div style><span style="font-size:12.8000001907349px"> <span class="" style="white-space:pre">              </span>_tunnel[self:proto() .. "-" .. self.sid] = true</span></div><div style><span style="font-size:12.8000001907349px"> <span class="" style="white-space:pre">          </span>return interface(self:proto() .. "-" .. self.sid, self)</span></div><div style><span style="font-size:12.8000001907349px"> <span class="" style="white-space:pre">  </span>elseif self:is_bridge() then</span></div><div style><span style="font-size:12.8000001907349px">--- /dev/null</span></div><div style><span style="font-size:12.8000001907349px">+++ b/protocols/wwan/Makefile</span></div><div style><span style="font-size:12.8000001907349px">@@ -0,0 +1,2 @@</span></div><div style><span style="font-size:12.8000001907349px">+include ../../build/<a href="http://config.mk">config.mk</a></span></div><div style><span style="font-size:12.8000001907349px">+include ../../build/<a href="http://module.mk">module.mk</a></span></div><div style><span style="font-size:12.8000001907349px">--- /dev/null</span></div><div style><span style="font-size:12.8000001907349px">+++ b/protocols/wwan/luasrc/model/cbi/admin_network/proto_wwan.lua</span></div><div style><span style="font-size:12.8000001907349px">@@ -0,0 +1,130 @@</span></div><div style><span style="font-size:12.8000001907349px">+--[[</span></div><div style><span style="font-size:12.8000001907349px">+LuCI - Lua Configuration Interface</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+Copyright 2015 Aleksandr Kolesnik <<a href="mailto:neryba@gmail.com">neryba@gmail.com</a>></span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+Licensed under the Apache License, Version 2.0 (the "License");</span></div><div style><span style="font-size:12.8000001907349px">+you may not use this file except in compliance with the License.</span></div><div style><span style="font-size:12.8000001907349px">+You may obtain a copy of the License at</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">       </span><a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a></span></div><div style><span style="font-size:12.8000001907349px">+]]--</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+local map, section, net = ...</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+local apn, service, pincode, username, password</span></div><div style><span style="font-size:12.8000001907349px">+local ipv6, maxwait, defaultroute, metric, peerdns, dns,</span></div><div style><span style="font-size:12.8000001907349px">+      keepalive_failure, keepalive_interval, demand</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+apn = section:taboption("general", Value, "apn", translate("APN"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+pincode = section:taboption("general", Value, "pincode", translate("PIN"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+username = section:taboption("general", Value, "username", translate("PAP/CHAP username"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+password = section:taboption("general", Value, "password", translate("PAP/CHAP password"))</span></div><div style><span style="font-size:12.8000001907349px">+password.password = true</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+if luci.model.network:has_ipv6() then</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">      </span>ipv6 = section:taboption("advanced", Flag, "ipv6",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">              </span>translate("Enable IPv6 negotiation on the PPP link"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">       </span>ipv6.default = ipv6.disabled</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+maxwait = section:taboption("advanced", Value, "maxwait",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>translate("Modem init timeout"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>translate("Maximum amount of seconds to wait for the modem to become ready"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+maxwait.placeholder = "20"</span></div><div style><span style="font-size:12.8000001907349px">+maxwait.datatype    = "min(1)"</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+defaultroute = section:taboption("advanced", Flag, "defaultroute",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>translate("Use default gateway"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre"> </span>translate("If unchecked, no default route is configured"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+defaultroute.default = defaultroute.enabled</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+metric = section:taboption("advanced", Value, "metric",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">    </span>translate("Use gateway metric"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+metric.placeholder = "0"</span></div><div style><span style="font-size:12.8000001907349px">+metric.datatype    = "uinteger"</span></div><div style><span style="font-size:12.8000001907349px">+metric:depends("defaultroute", defaultroute.enabled)</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+peerdns = section:taboption("advanced", Flag, "peerdns",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre"> </span>translate("Use DNS servers advertised by peer"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>translate("If unchecked, the advertised DNS server addresses are ignored"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+peerdns.default = peerdns.enabled</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+dns = section:taboption("advanced", DynamicList, "dns",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>translate("Use custom DNS servers"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+dns:depends("peerdns", "")</span></div><div style><span style="font-size:12.8000001907349px">+dns.datatype = "ipaddr"</span></div><div style><span style="font-size:12.8000001907349px">+dns.cast     = "string"</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_failure = section:taboption("advanced", Value, "_keepalive_failure",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">        </span>translate("LCP echo failure threshold"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>translate("Presume peer to be dead after given amount of LCP echo failures, use 0 to ignore failures"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function keepalive_failure.cfgvalue(self, section)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>local v = m:get(section, "keepalive")</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>if v and #v > 0 then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">             </span>return tonumber(v:match("^(%d+)[ ,]+%d+") or v)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">   </span>end</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function keepalive_failure.write() end</span></div><div style><span style="font-size:12.8000001907349px">+function keepalive_failure.remove() end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_failure.placeholder = "0"</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_failure.datatype    = "uinteger"</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_interval = section:taboption("advanced", Value, "_keepalive_interval",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">      </span>translate("LCP echo interval"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">   </span>translate("Send LCP echo requests at the given interval in seconds, only effective in conjunction with failure threshold"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function keepalive_interval.cfgvalue(self, section)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">        </span>local v = m:get(section, "keepalive")</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>if v and #v > 0 then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">             </span>return tonumber(v:match("^%d+[ ,]+(%d+)"))</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">        </span>end</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function keepalive_interval.write(self, section, value)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>local f = tonumber(keepalive_failure:formvalue(section)) or 0</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">       </span>local i = tonumber(value) or 5</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">      </span>if i < 1 then i = 1 end</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>if f > 0 then</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">            </span>m:set(section, "keepalive", "%d %d" %{ f, i })</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>else</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">                </span>m:del(section, "keepalive")</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">       </span>end</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_interval.remove      = keepalive_interval.write</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_interval.placeholder = "5"</span></div><div style><span style="font-size:12.8000001907349px">+keepalive_interval.datatype    = "min(1)"</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+demand = section:taboption("advanced", Value, "demand",</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">    </span>translate("Inactivity timeout"),</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>translate("Close inactive connection after the given amount of seconds, use 0 to persist connection"))</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+demand.placeholder = "0"</span></div><div style><span style="font-size:12.8000001907349px">+demand.datatype    = "uinteger"</span></div><div style><span style="font-size:12.8000001907349px">--- /dev/null</span></div><div style><span style="font-size:12.8000001907349px">+++ b/protocols/wwan/luasrc/model/network/proto_wwan.lua</span></div><div style><span style="font-size:12.8000001907349px">@@ -0,0 +1,57 @@</span></div><div style><span style="font-size:12.8000001907349px">+--[[</span></div><div style><span style="font-size:12.8000001907349px">+LuCI - Network model - WWAN protocol extension</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+Copyright 2015 Aleksandr Kolesnik <<a href="mailto:neryba@gmail.com">neryba@gmail.com</a>></span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+Licensed under the Apache License, Version 2.0 (the "License");</span></div><div style><span style="font-size:12.8000001907349px">+you may not use this file except in compliance with the License.</span></div><div style><span style="font-size:12.8000001907349px">+You may obtain a copy of the License at</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">   </span><a href="http://www.apache.org/licenses/LICENSE-2.0">http://www.apache.org/licenses/LICENSE-2.0</a></span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+Unless required by applicable law or agreed to in writing, software</span></div><div style><span style="font-size:12.8000001907349px">+distributed under the License is distributed on an "AS IS" BASIS,</span></div><div style><span style="font-size:12.8000001907349px">+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span></div><div style><span style="font-size:12.8000001907349px">+See the License for the specific language governing permissions and</span></div><div style><span style="font-size:12.8000001907349px">+limitations under the License.</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+]]--</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+local netmod = luci.model.network</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+local proto = netmod:register_protocol("wwan")</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.ifname(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">        </span>return "wwan-" .. self.sid</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.get_i18n(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">      </span>return luci.i18n.translate("WWAN")</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.opkg_package(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>return "wwan"</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.is_installed(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">       </span>return nixio.fs.access("/lib/netifd/proto/wwan.sh")</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.is_floating(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>return true</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.is_virtual(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">     </span>return true</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.get_interfaces(self)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre"> </span>return nil</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+function proto.contains_interface(self,ifc)</span></div><div style><span style="font-size:12.8000001907349px">+<span class="" style="white-space:pre">  </span>return (netmod:ifnameof(ifc) == self:ifname())</span></div><div style><span style="font-size:12.8000001907349px">+end</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style><span style="font-size:12.8000001907349px">+netmod:register_pattern_virtual("^wwan-%%w")</span></div><div style><span style="font-size:12.8000001907349px">+</span></div><div style="font-size:12.8000001907349px"><br></div></div></div>