6 #include <netinet/in.h>
13 struct static_proto_state
{
14 struct interface_proto_state proto
;
16 struct uci_section
*section
;
17 struct interface
*iface
;
21 split_netmask(char *str
, unsigned int *netmask
)
23 char *delim
, *err
= NULL
;
25 delim
= strchr(str
, '/');
29 *netmask
= strtoul(delim
, &err
, 10);
37 parse_ip_and_netmask(int af
, const char *str
, void *addr
, unsigned int *netmask
)
39 char *astr
= alloca(strlen(str
) + 1);
42 if (!split_netmask(astr
, netmask
))
53 return inet_pton(af
, str
, addr
);
57 parse_addr(struct static_proto_state
*state
, const char *str
, bool v6
, int mask
)
59 struct device_addr
*addr
;
60 int af
= v6
? AF_INET6
: AF_INET
;
62 addr
= calloc(1, sizeof(*addr
));
63 addr
->flags
= v6
? DEVADDR_INET6
: DEVADDR_INET4
;
66 if (!parse_ip_and_netmask(af
, str
, &addr
->addr
, &addr
->mask
)) {
67 interface_add_error(state
->iface
, "proto-static", "INVALID_ADDRESS", &str
, 1);
71 interface_add_address(state
->iface
, addr
);
76 parse_address_option(struct static_proto_state
*state
, struct uci_option
*o
, bool v6
, int netmask
)
78 struct uci_element
*e
;
81 if (o
->type
== UCI_TYPE_STRING
) {
83 if (!parse_addr(state
, o
->v
.string
, v6
, netmask
))
86 uci_foreach_element(&o
->v
.list
, e
) {
88 if (!parse_addr(state
, e
->name
, v6
, netmask
))
97 parse_gateway_option(struct static_proto_state
*state
, struct uci_option
*o
, bool v6
)
99 struct device_route
*route
;
100 const char *str
= o
->v
.string
;
101 int af
= v6
? AF_INET6
: AF_INET
;
103 route
= calloc(1, sizeof(*route
));
104 if (!inet_pton(af
, str
, &route
->nexthop
)) {
105 interface_add_error(state
->iface
, "proto-static",
106 "INVALID_GATEWAY", &str
, 1);
111 route
->flags
= DEVADDR_DEVICE
| (v6
? DEVADDR_INET6
: DEVADDR_INET4
);
112 interface_add_route(state
->iface
, route
);
126 static const struct uci_parse_option opts
[__OPT_MAX
] = {
127 [OPT_IPADDR
] = { .name
= "ipaddr" },
128 [OPT_IP6ADDR
] = { .name
= "ip6addr" },
129 [OPT_NETMASK
] = { .name
= "netmask", .type
= UCI_TYPE_STRING
},
130 [OPT_GATEWAY
] = { .name
= "gateway", .type
= UCI_TYPE_STRING
},
131 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= UCI_TYPE_STRING
},
135 static_proto_setup(struct static_proto_state
*state
)
137 struct uci_option
*tb
[__OPT_MAX
];
141 int n_v4
= 0, n_v6
= 0;
143 uci_parse_section(state
->section
, opts
, __OPT_MAX
, tb
);
145 if (tb
[OPT_NETMASK
]) {
146 if (!inet_aton(tb
[OPT_NETMASK
]->v
.string
, &ina
)) {
147 error
= "INVALID_NETMASK";
151 netmask
= 32 - fls(~(ntohl(ina
.s_addr
)));
155 n_v4
= parse_address_option(state
, tb
[OPT_IPADDR
], false, netmask
);
158 n_v6
= parse_address_option(state
, tb
[OPT_IP6ADDR
], true, netmask
);
160 if (!n_v4
&& !n_v6
) {
161 error
= "NO_ADDRESS";
165 if (n_v4
< 0 || n_v6
< 0)
168 if (n_v4
&& tb
[OPT_GATEWAY
]) {
169 if (!parse_gateway_option(state
, tb
[OPT_GATEWAY
], false))
173 if (n_v6
&& tb
[OPT_IP6GW
]) {
174 if (!parse_gateway_option(state
, tb
[OPT_IP6GW
], true))
181 interface_add_error(state
->iface
, "proto-static", error
, NULL
, 0);
187 static_handler(struct interface_proto_state
*proto
,
188 enum interface_proto_cmd cmd
, bool force
)
190 struct static_proto_state
*state
;
193 state
= container_of(proto
, struct static_proto_state
, proto
);
196 case PROTO_CMD_SETUP
:
197 if (static_proto_setup(state
))
201 case PROTO_CMD_TEARDOWN
:
202 interface_del_ctx_addr(state
->iface
, state
);
209 static_free(struct interface_proto_state
*proto
)
211 struct static_proto_state
*state
;
213 state
= container_of(proto
, struct static_proto_state
, proto
);
217 struct interface_proto_state
*
218 static_attach(struct proto_handler
*h
, struct interface
*iface
,
219 struct uci_section
*s
)
221 struct static_proto_state
*state
;
223 state
= calloc(1, sizeof(*state
));
224 state
->iface
= iface
;
226 state
->proto
.free
= static_free
;
227 state
->proto
.handler
= static_handler
;
228 state
->proto
.flags
= PROTO_FLAG_IMMEDIATE
;
230 return &state
->proto
;
233 static struct proto_handler static_proto
= {
235 .attach
= static_attach
,
239 static_proto_init(void)
241 add_proto_handler(&static_proto
);