2 * mapcalc - MAP parameter calculation
4 * Author: Steven Barth <cyrus@openwrt.org>
5 * Copyright (c) 2014-2015 cisco Systems, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2
9 * as published by the Free Software Foundation
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
19 #include <arpa/inet.h>
22 #include <libubox/utils.h>
25 struct blob_attr
*dump
= NULL
;
32 static const struct blobmsg_policy dump_attrs
[DUMP_ATTR_MAX
] = {
33 [DUMP_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_ARRAY
},
43 static const struct blobmsg_policy iface_attrs
[IFACE_ATTR_MAX
] = {
44 [IFACE_ATTR_INTERFACE
] = { .name
= "interface", .type
= BLOBMSG_TYPE_STRING
},
45 [IFACE_ATTR_PREFIX
] = { .name
= "ipv6-prefix", .type
= BLOBMSG_TYPE_ARRAY
},
55 static const struct blobmsg_policy prefix_attrs
[PREFIX_ATTR_MAX
] = {
56 [PREFIX_ATTR_ADDRESS
] = { .name
= "address", .type
= BLOBMSG_TYPE_STRING
},
57 [PREFIX_ATTR_MASK
] = { .name
= "mask", .type
= BLOBMSG_TYPE_INT32
},
60 static int bmemcmp(const void *av
, const void *bv
, size_t bits
)
62 const uint8_t *a
= av
, *b
= bv
;
63 size_t bytes
= bits
/ 8;
66 int res
= memcmp(a
, b
, bytes
);
67 if (res
== 0 && bits
> 0)
68 res
= (a
[bytes
] >> (8 - bits
)) - (b
[bytes
] >> (8 - bits
));
73 static void bmemcpy(void *av
, const void *bv
, size_t bits
)
76 const uint8_t *b
= bv
;
78 size_t bytes
= bits
/ 8;
83 uint8_t mask
= (1 << (8 - bits
)) - 1;
84 a
[bytes
] = (a
[bytes
] & mask
) | ((~mask
) & b
[bytes
]);
88 static void bmemcpys64(void *av
, const void *bv
, size_t frombits
, size_t nbits
)
91 const uint8_t *b
= bv
;
92 size_t frombyte
= frombits
/ 8, tobyte
= (frombits
+ nbits
) / 8;
94 memcpy(&buf
, &b
[frombyte
], tobyte
- frombyte
+ 1);
95 buf
= cpu_to_be64(be64_to_cpu(buf
) << (frombits
% 8));
97 bmemcpy(av
, &buf
, nbits
);
100 static void handle_dump(struct ubus_request
*req
__attribute__((unused
)),
101 int type
__attribute__((unused
)), struct blob_attr
*msg
)
103 struct blob_attr
*tb
[DUMP_ATTR_INTERFACE
];
104 blobmsg_parse(dump_attrs
, DUMP_ATTR_MAX
, tb
, blob_data(msg
), blob_len(msg
));
106 if (!tb
[DUMP_ATTR_INTERFACE
])
109 dump
= blob_memdup(tb
[DUMP_ATTR_INTERFACE
]);
128 static char *const token
[] = {
131 [OPT_EALEN
] = "ealen",
132 [OPT_PREFIX4LEN
] = "prefix4len",
133 [OPT_PREFIX6LEN
] = "prefix6len",
134 [OPT_IPV6PREFIX
] = "ipv6prefix",
135 [OPT_IPV4PREFIX
] = "ipv4prefix",
136 [OPT_OFFSET
] = "offset",
137 [OPT_PSIDLEN
] = "psidlen",
145 int main(int argc
, char *argv
[])
148 const char *iface
= argv
[1];
150 const char *legacy_env
= getenv("LEGACY");
151 bool legacy
= legacy_env
&& atoi(legacy_env
);
155 fprintf(stderr
, "Usage: %s <interface|*> <rule1> [rule2] [...]\n", argv
[0]);
159 uint32_t network_interface
;
160 struct ubus_context
*ubus
= ubus_connect(NULL
);
162 ubus_lookup_id(ubus
, "network.interface", &network_interface
);
163 ubus_invoke(ubus
, network_interface
, "dump", NULL
, handle_dump
, NULL
, 5000);
167 for (int i
= 2; i
< argc
; ++i
) {
175 struct in_addr ipv4prefix
= {INADDR_ANY
};
176 struct in_addr ipv4addr
= {INADDR_ANY
};
177 struct in6_addr ipv6addr
= IN6ADDR_ANY_INIT
;
178 struct in6_addr ipv6prefix
= IN6ADDR_ANY_INIT
;
179 struct in6_addr pd
= IN6ADDR_ANY_INIT
;
184 const char *dmr
= NULL
;
185 const char *br
= NULL
;
187 for (char *rule
= strdup(argv
[i
]); *rule
; ) {
190 int idx
= getsubopt(&rule
, token
, &value
);
193 if (idx
== OPT_TYPE
) {
194 lw4o6
= (value
&& !strcmp(value
, "lw4o6"));
195 } else if (idx
== OPT_FMR
) {
197 } else if (idx
== OPT_EALEN
&& (intval
= strtoul(value
, NULL
, 0)) <= 48 && !errno
) {
199 } else if (idx
== OPT_PREFIX4LEN
&& (intval
= strtoul(value
, NULL
, 0)) <= 32 && !errno
) {
201 } else if (idx
== OPT_PREFIX6LEN
&& (intval
= strtoul(value
, NULL
, 0)) <= 112 && !errno
) {
203 } else if (idx
== OPT_IPV4PREFIX
&& inet_pton(AF_INET
, value
, &ipv4prefix
) == 1) {
205 } else if (idx
== OPT_IPV6PREFIX
&& inet_pton(AF_INET6
, value
, &ipv6prefix
) == 1) {
207 } else if (idx
== OPT_OFFSET
&& (intval
= strtoul(value
, NULL
, 0)) <= 16 && !errno
) {
209 } else if (idx
== OPT_PSIDLEN
&& (intval
= strtoul(value
, NULL
, 0)) <= 16 && !errno
) {
211 } else if (idx
== OPT_PSID
&& (intval
= strtoul(value
, NULL
, 0)) <= 65535 && !errno
) {
213 } else if (idx
== OPT_DMR
) {
215 } else if (idx
== OPT_BR
) {
218 if (idx
== -1 || idx
>= OPT_MAX
)
219 fprintf(stderr
, "Skipped invalid option: %s\n", value
);
221 fprintf(stderr
, "Skipped invalid value %s for option %s\n",
227 offset
= (lw4o6
) ? 0 : (legacy
) ? 4 : 6;
230 struct blob_attr
*c
, *cur
;
232 blobmsg_for_each_attr(c
, dump
, rem
) {
233 struct blob_attr
*tb
[IFACE_ATTR_MAX
];
234 blobmsg_parse(iface_attrs
, IFACE_ATTR_MAX
, tb
, blobmsg_data(c
), blobmsg_data_len(c
));
236 if (!tb
[IFACE_ATTR_INTERFACE
] || (strcmp(argv
[1], "*") && strcmp(argv
[1],
237 blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]))))
240 if ((cur
= tb
[IFACE_ATTR_PREFIX
])) {
241 if (blobmsg_type(cur
) != BLOBMSG_TYPE_ARRAY
|| !blobmsg_check_attr(cur
, NULL
))
246 blobmsg_for_each_attr(d
, cur
, drem
) {
247 struct blob_attr
*ptb
[PREFIX_ATTR_MAX
];
248 blobmsg_parse(prefix_attrs
, PREFIX_ATTR_MAX
, ptb
,
249 blobmsg_data(d
), blobmsg_data_len(d
));
251 if (!ptb
[PREFIX_ATTR_ADDRESS
] || !ptb
[PREFIX_ATTR_MASK
])
254 struct in6_addr prefix
= IN6ADDR_ANY_INIT
;
255 int mask
= blobmsg_get_u32(ptb
[PREFIX_ATTR_MASK
]);
256 inet_pton(AF_INET6
, blobmsg_get_string(ptb
[PREFIX_ATTR_ADDRESS
]), &prefix
);
258 if (mask
>= prefix6len
&& !bmemcmp(&prefix
, &ipv6prefix
, prefix6len
)) {
261 iface
= blobmsg_get_string(tb
[IFACE_ATTR_INTERFACE
]);
271 if (ealen
< 0 && pdlen
>= 0)
272 ealen
= pdlen
- prefix6len
;
275 psidlen
= ealen
- (32 - prefix4len
);
279 if (psid
< 0 && psidlen
<= 16 && psidlen
>= 0 && pdlen
>= 0 && ealen
>= psidlen
) {
280 bmemcpys64(&psid16
, &pd
, prefix6len
+ ealen
- psidlen
, psidlen
);
281 psid
= be16_to_cpu(psid16
);
284 psid16
= cpu_to_be16(psid
>> (16 - psidlen
));
286 if ((pdlen
>= 0 || ealen
== psidlen
) && ealen
>= psidlen
) {
287 bmemcpys64(&ipv4addr
, &pd
, prefix6len
, ealen
- psidlen
);
288 ipv4addr
.s_addr
= htonl(ntohl(ipv4addr
.s_addr
) >> prefix4len
);
289 bmemcpy(&ipv4addr
, &ipv4prefix
, prefix4len
);
291 if (prefix4len
+ ealen
< 32)
292 addr4len
= prefix4len
+ ealen
;
295 if (prefix4len
< 0 || prefix6len
< 0 || ealen
< 0 || ealen
< psidlen
) {
296 fprintf(stderr
, "Skipping invalid or incomplete rule: %s\n", argv
[i
]);
301 if (pdlen
< 0 && !fmr
) {
302 fprintf(stderr
, "Skipping non-FMR without matching PD: %s\n", argv
[i
]);
305 } else if (pdlen
>= 0) {
306 size_t v4offset
= (legacy
) ? 9 : 10;
307 memcpy(&ipv6addr
.s6_addr
[v4offset
], &ipv4addr
, 4);
308 memcpy(&ipv6addr
.s6_addr
[v4offset
+ 4], &psid16
, 2);
309 bmemcpy(&ipv6addr
, &pd
, pdlen
);
313 char ipv4addrbuf
[INET_ADDRSTRLEN
];
314 char ipv4prefixbuf
[INET_ADDRSTRLEN
];
315 char ipv6prefixbuf
[INET6_ADDRSTRLEN
];
316 char ipv6addrbuf
[INET6_ADDRSTRLEN
];
317 char pdbuf
[INET6_ADDRSTRLEN
];
319 inet_ntop(AF_INET
, &ipv4addr
, ipv4addrbuf
, sizeof(ipv4addrbuf
));
320 inet_ntop(AF_INET
, &ipv4prefix
, ipv4prefixbuf
, sizeof(ipv4prefixbuf
));
321 inet_ntop(AF_INET6
, &ipv6prefix
, ipv6prefixbuf
, sizeof(ipv6prefixbuf
));
322 inet_ntop(AF_INET6
, &ipv6addr
, ipv6addrbuf
, sizeof(ipv6addrbuf
));
323 inet_ntop(AF_INET6
, &pd
, pdbuf
, sizeof(pdbuf
));
325 printf("RULE_%d_FMR=%d\n", rulecnt
, fmr
);
326 printf("RULE_%d_EALEN=%d\n", rulecnt
, ealen
);
327 printf("RULE_%d_PSIDLEN=%d\n", rulecnt
, psidlen
);
328 printf("RULE_%d_OFFSET=%d\n", rulecnt
, offset
);
329 printf("RULE_%d_PREFIX4LEN=%d\n", rulecnt
, prefix4len
);
330 printf("RULE_%d_PREFIX6LEN=%d\n", rulecnt
, prefix6len
);
331 printf("RULE_%d_IPV4PREFIX=%s\n", rulecnt
, ipv4prefixbuf
);
332 printf("RULE_%d_IPV6PREFIX=%s\n", rulecnt
, ipv6prefixbuf
);
335 printf("RULE_%d_IPV6PD=%s\n", rulecnt
, pdbuf
);
336 printf("RULE_%d_PD6LEN=%d\n", rulecnt
, pdlen
);
337 printf("RULE_%d_PD6IFACE=%s\n", rulecnt
, iface
);
338 printf("RULE_%d_IPV6ADDR=%s\n", rulecnt
, ipv6addrbuf
);
339 printf("RULE_BMR=%d\n", rulecnt
);
342 if (ipv4addr
.s_addr
) {
343 printf("RULE_%d_IPV4ADDR=%s\n", rulecnt
, ipv4addrbuf
);
344 printf("RULE_%d_ADDR4LEN=%d\n", rulecnt
, addr4len
);
348 if (psidlen
> 0 && psid
>= 0) {
349 printf("RULE_%d_PORTSETS='", rulecnt
);
350 for (int k
= (offset
) ? 1 : 0; k
< (1 << offset
); ++k
) {
351 int start
= (k
<< (16 - offset
)) | (psid
>> offset
);
352 int end
= start
+ (1 << (16 - offset
- psidlen
)) - 1;
358 printf("%d-%d ", start
, end
);
364 printf("RULE_%d_DMR=%s\n", rulecnt
, dmr
);
367 printf("RULE_%d_BR=%s\n", rulecnt
, br
);
370 printf("RULE_COUNT=%d\n", rulecnt
);