6 #include <netinet/in.h>
23 enum static_proto_flags
{
24 STATIC_F_IPV4GW
= (1 << 0),
25 STATIC_F_IPV6GW
= (1 << 1),
28 struct static_proto_settings
{
37 struct in_addr ipv4gw
;
38 struct in6_addr ipv6gw
;
41 struct static_proto_state
{
42 struct interface_proto_state proto
;
43 struct interface
*iface
;
45 struct static_proto_settings s
;
49 static_handler(struct interface_proto_state
*proto
,
50 enum interface_proto_cmd cmd
, bool force
)
52 struct static_proto_state
*state
;
53 struct static_proto_settings
*ps
;
58 state
= container_of(proto
, struct static_proto_state
, proto
);
60 dev
= state
->iface
->main_dev
.dev
;
64 for (i
= 0; i
< state
->s
.n_v4
; i
++) {
67 ret
= system_add_address(dev
, AF_INET
,
68 &ps
->v4
[i
].addr
, ps
->v4
[i
].prefix
);
70 for (i
= 0; i
< state
->s
.n_v6
; i
++) {
73 ret
= system_add_address(dev
, AF_INET6
,
74 &ps
->v6
[i
].addr
, ps
->v6
[i
].prefix
);
80 interface_add_error(state
->iface
, "proto-static",
81 "SET_ADDRESS_FAILED", NULL
, 0);
84 case PROTO_CMD_TEARDOWN
:
85 for (i
= 0; i
< ps
->n_v4
; i
++)
86 system_del_address(dev
, AF_INET
, &ps
->v4
[i
].addr
);
87 for (i
= 0; i
< ps
->n_v6
; i
++)
88 system_del_address(dev
, AF_INET6
, &ps
->v6
[i
].addr
);
95 static_free(struct interface_proto_state
*proto
)
97 struct static_proto_state
*state
;
99 state
= container_of(proto
, struct static_proto_state
, proto
);
103 struct interface_proto_state
*
104 static_create_state(struct interface
*iface
, struct static_proto_settings
*ps
)
106 struct static_proto_state
*state
;
107 int v4_len
= sizeof(struct v4_addr
) * ps
->n_v4
;
108 int v6_len
= sizeof(struct v6_addr
) * ps
->n_v6
;
111 state
= calloc(1, sizeof(*state
) + v4_len
+ v6_len
);
112 state
->iface
= iface
;
113 state
->proto
.free
= static_free
;
114 state
->proto
.handler
= static_handler
;
115 state
->proto
.flags
= PROTO_FLAG_IMMEDIATE
;
116 memcpy(&state
->s
, ps
, sizeof(state
->s
));
118 next
= (void *) (state
+ 1);
122 memcpy(next
, ps
->v4
, sizeof(struct v4_addr
) * ps
->n_v4
);
124 next
= ps
->v4
+ ps
->n_v4
;
129 memcpy(next
, ps
->v6
, sizeof(struct v6_addr
) * ps
->n_v6
);
132 return &state
->proto
;
136 split_netmask(char *str
, unsigned int *netmask
)
138 char *delim
, *err
= NULL
;
140 delim
= strchr(str
, '/');
144 *netmask
= strtoul(delim
, &err
, 10);
152 parse_ip_and_netmask(int af
, const char *str
, void *addr
, unsigned int *netmask
)
154 char *astr
= alloca(strlen(str
) + 1);
157 if (!split_netmask(astr
, netmask
))
160 if (af
== AF_INET6
) {
168 return inet_pton(af
, str
, addr
);
172 parse_v4(const char *str
, struct v4_addr
*v4
, int netmask
)
174 v4
->prefix
= netmask
;
175 return parse_ip_and_netmask(AF_INET
, str
, &v4
->addr
, &v4
->prefix
);
179 parse_v6(const char *str
, struct v6_addr
*v6
, int netmask
)
181 v6
->prefix
= netmask
;
182 return parse_ip_and_netmask(AF_INET6
, str
, &v6
->addr
, &v6
->prefix
);
186 count_list_entries(struct uci_option
*o
)
188 struct uci_element
*e
;
191 uci_foreach_element(&o
->v
.list
, e
)
206 static const struct uci_parse_option opts
[__OPT_MAX
] = {
207 [OPT_IPADDR
] = { .name
= "ipaddr" },
208 [OPT_IP6ADDR
] = { .name
= "ip6addr" },
209 [OPT_NETMASK
] = { .name
= "netmask", .type
= UCI_TYPE_STRING
},
210 [OPT_GATEWAY
] = { .name
= "gateway", .type
= UCI_TYPE_STRING
},
211 [OPT_IP6GW
] = { .name
= "ip6gw", .type
= UCI_TYPE_STRING
},
214 struct interface_proto_state
*
215 static_attach(struct proto_handler
*h
, struct interface
*iface
,
216 struct uci_section
*s
)
218 struct uci_option
*tb
[__OPT_MAX
];
219 struct uci_element
*e
;
220 struct in_addr ina
= {};
221 const char *error
= NULL
;
224 struct static_proto_settings ps
;
226 memset(&ps
, 0, sizeof(ps
));
227 uci_parse_section(s
, opts
, __OPT_MAX
, tb
);
229 if (tb
[OPT_NETMASK
]) {
230 if (!inet_aton(tb
[OPT_NETMASK
]->v
.string
, &ina
)) {
231 error
= "INVALID_NETMASK";
235 netmask
= 32 - fls(~(ntohl(ina
.s_addr
)));
238 if (tb
[OPT_IPADDR
]) {
239 if (tb
[OPT_IPADDR
]->type
== UCI_TYPE_STRING
) {
241 ps
.v4
= alloca(sizeof(struct v4_addr
));
242 if (!parse_v4(tb
[OPT_IPADDR
]->v
.string
, ps
.v4
, netmask
))
246 ps
.n_v4
= count_list_entries(tb
[OPT_IPADDR
]);
247 ps
.v4
= alloca(sizeof(struct v4_addr
) * ps
.n_v4
);
248 uci_foreach_element(&tb
[OPT_IPADDR
]->v
.list
, e
) {
249 if (!parse_v4(e
->name
, &ps
.v4
[i
++], netmask
))
255 if (tb
[OPT_IP6ADDR
]) {
256 if (tb
[OPT_IP6ADDR
]->type
== UCI_TYPE_STRING
) {
258 ps
.v6
= alloca(sizeof(struct v6_addr
));
259 ps
.v6
->prefix
= netmask
;
260 if (!parse_v6(tb
[OPT_IP6ADDR
]->v
.string
, ps
.v6
, netmask
))
264 ps
.n_v6
= count_list_entries(tb
[OPT_IP6ADDR
]);
265 ps
.v6
= alloca(sizeof(struct v6_addr
) * ps
.n_v6
);
266 uci_foreach_element(&tb
[OPT_IP6ADDR
]->v
.list
, e
) {
267 if (!parse_v6(e
->name
, &ps
.v6
[i
++], netmask
))
273 if (!ps
.n_v4
&& !ps
.n_v6
) {
274 error
= "NO_ADDRESS";
278 if (ps
.n_v4
&& tb
[OPT_GATEWAY
]) {
279 if (!inet_pton(AF_INET
, tb
[OPT_GATEWAY
]->v
.string
, &ps
.ipv4gw
)) {
280 error
= "INVALID_GATEWAY";
283 ps
.flags
|= STATIC_F_IPV4GW
;
286 if (ps
.n_v6
&& tb
[OPT_IP6GW
]) {
287 if (!inet_pton(AF_INET6
, tb
[OPT_IP6GW
]->v
.string
, &ps
.ipv6gw
)) {
288 error
= "INVALID_GATEWAY";
291 ps
.flags
|= STATIC_F_IPV6GW
;
294 return static_create_state(iface
, &ps
);
297 error
= "INVALID_ADDRESS";
300 interface_add_error(iface
, "proto-static", error
, NULL
, 0);
304 static struct proto_handler static_proto
= {
306 .attach
= static_attach
,
310 static_proto_init(void)
312 add_proto_handler(&static_proto
);