Free (GPLv2) TCP/IP stack developed by TASS Belgium
Fork of PicoTCP by
modules/pico_ipfilter.c@1:cfe8984a32b4, 2013-05-17 (annotated)
- Committer:
- tass
- Date:
- Fri May 17 12:09:59 2013 +0000
- Revision:
- 1:cfe8984a32b4
- Parent:
- libraries/picotcp/modules/pico_ipfilter.c@0:d7f2341ab245
Update for smaller SOCKETQ
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
daniele | 0:d7f2341ab245 | 1 | /********************************************************************* |
daniele | 0:d7f2341ab245 | 2 | PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. |
daniele | 0:d7f2341ab245 | 3 | See LICENSE and COPYING for usage. |
daniele | 0:d7f2341ab245 | 4 | |
daniele | 0:d7f2341ab245 | 5 | Authors: Simon Maes |
daniele | 0:d7f2341ab245 | 6 | *********************************************************************/ |
daniele | 0:d7f2341ab245 | 7 | |
daniele | 0:d7f2341ab245 | 8 | #include "pico_ipv4.h" |
daniele | 0:d7f2341ab245 | 9 | #include "pico_config.h" |
daniele | 0:d7f2341ab245 | 10 | #include "pico_icmp4.h" |
daniele | 0:d7f2341ab245 | 11 | #include "pico_stack.h" |
daniele | 0:d7f2341ab245 | 12 | #include "pico_eth.h" |
daniele | 0:d7f2341ab245 | 13 | #include "pico_socket.h" |
daniele | 0:d7f2341ab245 | 14 | #include "pico_device.h" |
daniele | 0:d7f2341ab245 | 15 | #include "pico_ipfilter.h" |
daniele | 0:d7f2341ab245 | 16 | #include "pico_tcp.h" |
daniele | 0:d7f2341ab245 | 17 | #include "pico_udp.h" |
daniele | 0:d7f2341ab245 | 18 | |
daniele | 0:d7f2341ab245 | 19 | |
daniele | 0:d7f2341ab245 | 20 | //#define ipf_dbg dbg |
daniele | 0:d7f2341ab245 | 21 | #define ipf_dbg(...) do{}while(0) |
daniele | 0:d7f2341ab245 | 22 | |
daniele | 0:d7f2341ab245 | 23 | struct filter_node; |
daniele | 0:d7f2341ab245 | 24 | typedef int (*func_pntr)(struct filter_node *filter, struct pico_frame *f); |
daniele | 0:d7f2341ab245 | 25 | |
daniele | 0:d7f2341ab245 | 26 | struct filter_node { |
daniele | 0:d7f2341ab245 | 27 | struct pico_device *fdev; |
daniele | 0:d7f2341ab245 | 28 | struct filter_node *next_filter; |
daniele | 0:d7f2341ab245 | 29 | uint32_t out_addr; |
daniele | 0:d7f2341ab245 | 30 | uint32_t out_addr_netmask; |
daniele | 0:d7f2341ab245 | 31 | uint32_t in_addr; |
daniele | 0:d7f2341ab245 | 32 | uint32_t in_addr_netmask; |
daniele | 0:d7f2341ab245 | 33 | uint16_t out_port; |
daniele | 0:d7f2341ab245 | 34 | uint16_t in_port; |
daniele | 0:d7f2341ab245 | 35 | uint8_t proto; |
daniele | 0:d7f2341ab245 | 36 | int8_t priority; |
daniele | 0:d7f2341ab245 | 37 | uint8_t tos; |
daniele | 0:d7f2341ab245 | 38 | uint8_t filter_id; |
daniele | 0:d7f2341ab245 | 39 | func_pntr function_ptr; |
daniele | 0:d7f2341ab245 | 40 | }; |
daniele | 0:d7f2341ab245 | 41 | |
daniele | 0:d7f2341ab245 | 42 | static struct filter_node *head = NULL; |
daniele | 0:d7f2341ab245 | 43 | static struct filter_node *tail = NULL; |
daniele | 0:d7f2341ab245 | 44 | |
daniele | 0:d7f2341ab245 | 45 | /*======================== FUNCTION PNTRS ==========================*/ |
daniele | 0:d7f2341ab245 | 46 | |
daniele | 0:d7f2341ab245 | 47 | static int fp_accept(struct filter_node *filter, struct pico_frame *f) {return 0;} |
daniele | 0:d7f2341ab245 | 48 | |
daniele | 0:d7f2341ab245 | 49 | static int fp_priority(struct filter_node *filter, struct pico_frame *f) { |
daniele | 0:d7f2341ab245 | 50 | |
daniele | 0:d7f2341ab245 | 51 | //TODO do priority-stuff |
daniele | 0:d7f2341ab245 | 52 | return 0; |
daniele | 0:d7f2341ab245 | 53 | } |
daniele | 0:d7f2341ab245 | 54 | |
daniele | 0:d7f2341ab245 | 55 | static int fp_reject(struct filter_node *filter, struct pico_frame *f) { |
daniele | 0:d7f2341ab245 | 56 | // TODO check first if sender is pico itself or not |
daniele | 0:d7f2341ab245 | 57 | ipf_dbg("ipfilter> #reject\n"); |
daniele | 0:d7f2341ab245 | 58 | pico_icmp4_packet_filtered(f); |
daniele | 0:d7f2341ab245 | 59 | pico_frame_discard(f); |
daniele | 0:d7f2341ab245 | 60 | return 1; |
daniele | 0:d7f2341ab245 | 61 | } |
daniele | 0:d7f2341ab245 | 62 | |
daniele | 0:d7f2341ab245 | 63 | static int fp_drop(struct filter_node *filter, struct pico_frame *f) { |
daniele | 0:d7f2341ab245 | 64 | |
daniele | 0:d7f2341ab245 | 65 | ipf_dbg("ipfilter> # drop\n"); |
daniele | 0:d7f2341ab245 | 66 | pico_frame_discard(f); |
daniele | 0:d7f2341ab245 | 67 | return 1; |
daniele | 0:d7f2341ab245 | 68 | } |
daniele | 0:d7f2341ab245 | 69 | |
daniele | 0:d7f2341ab245 | 70 | /*============================ API CALLS ============================*/ |
daniele | 0:d7f2341ab245 | 71 | int pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port, int8_t priority, uint8_t tos, enum filter_action action) |
daniele | 0:d7f2341ab245 | 72 | { |
daniele | 0:d7f2341ab245 | 73 | static uint8_t filter_id = 0; |
daniele | 0:d7f2341ab245 | 74 | struct filter_node *new_filter; |
daniele | 0:d7f2341ab245 | 75 | |
daniele | 0:d7f2341ab245 | 76 | if ( !(dev != NULL || proto != 0 || (out_addr != NULL && out_addr->addr != 0U) || (out_addr_netmask != NULL && out_addr_netmask->addr != 0U)|| (in_addr != NULL && in_addr->addr != 0U) || (in_addr_netmask != NULL && in_addr_netmask->addr != 0U)|| out_port != 0 || in_port !=0 || tos != 0 )) { |
daniele | 0:d7f2341ab245 | 77 | pico_err = PICO_ERR_EINVAL; |
daniele | 0:d7f2341ab245 | 78 | return -1; |
daniele | 0:d7f2341ab245 | 79 | } |
daniele | 0:d7f2341ab245 | 80 | if ( priority > 10 || priority < -10) { |
daniele | 0:d7f2341ab245 | 81 | pico_err = PICO_ERR_EINVAL; |
daniele | 0:d7f2341ab245 | 82 | return -1; |
daniele | 0:d7f2341ab245 | 83 | } |
daniele | 0:d7f2341ab245 | 84 | if (action > 3 || action < 0) { |
daniele | 0:d7f2341ab245 | 85 | pico_err = PICO_ERR_EINVAL; |
daniele | 0:d7f2341ab245 | 86 | return -1; |
daniele | 0:d7f2341ab245 | 87 | } |
daniele | 0:d7f2341ab245 | 88 | ipf_dbg("ipfilter> # adding filter\n"); |
daniele | 0:d7f2341ab245 | 89 | |
daniele | 0:d7f2341ab245 | 90 | new_filter = pico_zalloc(sizeof(struct filter_node)); |
daniele | 0:d7f2341ab245 | 91 | if (!head) { |
daniele | 0:d7f2341ab245 | 92 | head = tail = new_filter; |
daniele | 0:d7f2341ab245 | 93 | } else { |
daniele | 0:d7f2341ab245 | 94 | tail->next_filter = new_filter; |
daniele | 0:d7f2341ab245 | 95 | tail = new_filter; |
daniele | 0:d7f2341ab245 | 96 | } |
daniele | 0:d7f2341ab245 | 97 | |
daniele | 0:d7f2341ab245 | 98 | new_filter->fdev = dev; |
daniele | 0:d7f2341ab245 | 99 | new_filter->proto = proto; |
daniele | 0:d7f2341ab245 | 100 | if (out_addr != NULL) |
daniele | 0:d7f2341ab245 | 101 | new_filter->out_addr = out_addr->addr; |
daniele | 0:d7f2341ab245 | 102 | else |
daniele | 0:d7f2341ab245 | 103 | new_filter->out_addr = 0U; |
daniele | 0:d7f2341ab245 | 104 | |
daniele | 0:d7f2341ab245 | 105 | if (out_addr_netmask != NULL) |
daniele | 0:d7f2341ab245 | 106 | new_filter->out_addr_netmask = out_addr_netmask->addr; |
daniele | 0:d7f2341ab245 | 107 | else |
daniele | 0:d7f2341ab245 | 108 | new_filter->out_addr_netmask = 0U; |
daniele | 0:d7f2341ab245 | 109 | |
daniele | 0:d7f2341ab245 | 110 | if (in_addr != NULL) |
daniele | 0:d7f2341ab245 | 111 | new_filter->in_addr = in_addr->addr; |
daniele | 0:d7f2341ab245 | 112 | else |
daniele | 0:d7f2341ab245 | 113 | new_filter->in_addr = 0U; |
daniele | 0:d7f2341ab245 | 114 | |
daniele | 0:d7f2341ab245 | 115 | if (in_addr_netmask != NULL) |
daniele | 0:d7f2341ab245 | 116 | new_filter->in_addr_netmask = in_addr_netmask->addr; |
daniele | 0:d7f2341ab245 | 117 | else |
daniele | 0:d7f2341ab245 | 118 | new_filter->in_addr_netmask = 0U; |
daniele | 0:d7f2341ab245 | 119 | |
daniele | 0:d7f2341ab245 | 120 | new_filter->out_port = out_port; |
daniele | 0:d7f2341ab245 | 121 | new_filter->in_port = in_port; |
daniele | 0:d7f2341ab245 | 122 | new_filter->priority = priority; |
daniele | 0:d7f2341ab245 | 123 | new_filter->tos = tos; |
daniele | 0:d7f2341ab245 | 124 | new_filter->filter_id = filter_id++; |
daniele | 0:d7f2341ab245 | 125 | |
daniele | 0:d7f2341ab245 | 126 | /*Define filterType_functionPointer here instead of in ipfilter-function, to prevent running multiple times through switch*/ |
daniele | 0:d7f2341ab245 | 127 | switch (action) { |
daniele | 0:d7f2341ab245 | 128 | case FILTER_ACCEPT: |
daniele | 0:d7f2341ab245 | 129 | new_filter->function_ptr = fp_accept; |
daniele | 0:d7f2341ab245 | 130 | break; |
daniele | 0:d7f2341ab245 | 131 | case FILTER_PRIORITY: |
daniele | 0:d7f2341ab245 | 132 | new_filter->function_ptr = fp_priority; |
daniele | 0:d7f2341ab245 | 133 | break; |
daniele | 0:d7f2341ab245 | 134 | case FILTER_REJECT: |
daniele | 0:d7f2341ab245 | 135 | new_filter->function_ptr = fp_reject; |
daniele | 0:d7f2341ab245 | 136 | break; |
daniele | 0:d7f2341ab245 | 137 | case FILTER_DROP: |
daniele | 0:d7f2341ab245 | 138 | new_filter->function_ptr = fp_drop; |
daniele | 0:d7f2341ab245 | 139 | break; |
daniele | 0:d7f2341ab245 | 140 | default: |
daniele | 0:d7f2341ab245 | 141 | ipf_dbg("ipfilter> #unknown filter action\n"); |
daniele | 0:d7f2341ab245 | 142 | break; |
daniele | 0:d7f2341ab245 | 143 | } |
daniele | 0:d7f2341ab245 | 144 | return new_filter->filter_id; |
daniele | 0:d7f2341ab245 | 145 | } |
daniele | 0:d7f2341ab245 | 146 | |
daniele | 0:d7f2341ab245 | 147 | int pico_ipv4_filter_del(uint8_t filter_id) |
daniele | 0:d7f2341ab245 | 148 | { |
daniele | 0:d7f2341ab245 | 149 | struct filter_node *work; |
daniele | 0:d7f2341ab245 | 150 | struct filter_node *prev; |
daniele | 0:d7f2341ab245 | 151 | |
daniele | 0:d7f2341ab245 | 152 | if (!tail || !head) { |
daniele | 0:d7f2341ab245 | 153 | pico_err = PICO_ERR_EPERM; |
daniele | 0:d7f2341ab245 | 154 | return -1; |
daniele | 0:d7f2341ab245 | 155 | } |
daniele | 0:d7f2341ab245 | 156 | |
daniele | 0:d7f2341ab245 | 157 | work = head; |
daniele | 0:d7f2341ab245 | 158 | if (work->filter_id == filter_id) { |
daniele | 0:d7f2341ab245 | 159 | /*delete filter_node from linked list*/ |
daniele | 0:d7f2341ab245 | 160 | head = work->next_filter; |
daniele | 0:d7f2341ab245 | 161 | pico_free(work); |
daniele | 0:d7f2341ab245 | 162 | return 0; |
daniele | 0:d7f2341ab245 | 163 | } |
daniele | 0:d7f2341ab245 | 164 | prev = work; |
daniele | 0:d7f2341ab245 | 165 | work = work->next_filter; |
daniele | 0:d7f2341ab245 | 166 | |
daniele | 0:d7f2341ab245 | 167 | while (1) { |
daniele | 0:d7f2341ab245 | 168 | if (work->filter_id == filter_id) { |
daniele | 0:d7f2341ab245 | 169 | if (work != tail) { |
daniele | 0:d7f2341ab245 | 170 | /*delete filter_node from linked list*/ |
daniele | 0:d7f2341ab245 | 171 | prev->next_filter = work->next_filter; |
daniele | 0:d7f2341ab245 | 172 | pico_free(work); |
daniele | 0:d7f2341ab245 | 173 | return 0; |
daniele | 0:d7f2341ab245 | 174 | } else { |
daniele | 0:d7f2341ab245 | 175 | prev->next_filter = NULL; |
daniele | 0:d7f2341ab245 | 176 | pico_free(work); |
daniele | 0:d7f2341ab245 | 177 | return 0; |
daniele | 0:d7f2341ab245 | 178 | } |
daniele | 0:d7f2341ab245 | 179 | } else { |
daniele | 0:d7f2341ab245 | 180 | /*check next filter_node*/ |
daniele | 0:d7f2341ab245 | 181 | prev = work; |
daniele | 0:d7f2341ab245 | 182 | work = work->next_filter; |
daniele | 0:d7f2341ab245 | 183 | if (work == tail) { |
daniele | 0:d7f2341ab245 | 184 | pico_err = PICO_ERR_EINVAL; |
daniele | 0:d7f2341ab245 | 185 | return -1; |
daniele | 0:d7f2341ab245 | 186 | } |
daniele | 0:d7f2341ab245 | 187 | } |
daniele | 0:d7f2341ab245 | 188 | } |
daniele | 0:d7f2341ab245 | 189 | } |
daniele | 0:d7f2341ab245 | 190 | |
daniele | 0:d7f2341ab245 | 191 | /*================================== CORE FILTER FUNCTIONS ==================================*/ |
daniele | 0:d7f2341ab245 | 192 | int match_filter(struct filter_node *filter, struct pico_frame *f) |
daniele | 0:d7f2341ab245 | 193 | { |
daniele | 0:d7f2341ab245 | 194 | struct filter_node temp; |
daniele | 0:d7f2341ab245 | 195 | struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; |
daniele | 0:d7f2341ab245 | 196 | struct pico_tcp_hdr *tcp_hdr; |
daniele | 0:d7f2341ab245 | 197 | struct pico_udp_hdr *udp_hdr; |
daniele | 0:d7f2341ab245 | 198 | |
daniele | 0:d7f2341ab245 | 199 | if (!filter|| !f) { |
daniele | 0:d7f2341ab245 | 200 | ipf_dbg("ipfilter> ## nullpointer in match filter \n"); |
daniele | 0:d7f2341ab245 | 201 | return -1; |
daniele | 0:d7f2341ab245 | 202 | } |
daniele | 0:d7f2341ab245 | 203 | |
daniele | 0:d7f2341ab245 | 204 | temp.fdev = f->dev; |
daniele | 0:d7f2341ab245 | 205 | temp.out_addr = ipv4_hdr->dst.addr; |
daniele | 0:d7f2341ab245 | 206 | temp.in_addr = ipv4_hdr->src.addr; |
daniele | 0:d7f2341ab245 | 207 | if (ipv4_hdr->proto == PICO_PROTO_TCP ) { |
daniele | 0:d7f2341ab245 | 208 | tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; |
daniele | 0:d7f2341ab245 | 209 | temp.out_port = short_be(tcp_hdr->trans.dport); |
daniele | 0:d7f2341ab245 | 210 | temp.in_port = short_be(tcp_hdr->trans.sport); |
daniele | 0:d7f2341ab245 | 211 | }else if (ipv4_hdr->proto == PICO_PROTO_UDP ) { |
daniele | 0:d7f2341ab245 | 212 | udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; |
daniele | 0:d7f2341ab245 | 213 | temp.out_port = short_be(udp_hdr->trans.dport); |
daniele | 0:d7f2341ab245 | 214 | temp.in_port = short_be(udp_hdr->trans.sport); |
daniele | 0:d7f2341ab245 | 215 | } else { |
daniele | 0:d7f2341ab245 | 216 | temp.out_port = temp.in_port = 0; |
daniele | 0:d7f2341ab245 | 217 | } |
daniele | 0:d7f2341ab245 | 218 | temp.proto = ipv4_hdr->proto; |
daniele | 0:d7f2341ab245 | 219 | temp.priority = f->priority; |
daniele | 0:d7f2341ab245 | 220 | temp.tos = ipv4_hdr->tos; |
daniele | 0:d7f2341ab245 | 221 | |
daniele | 0:d7f2341ab245 | 222 | |
daniele | 0:d7f2341ab245 | 223 | |
daniele | 0:d7f2341ab245 | 224 | if ( ((filter->fdev == NULL || filter->fdev == temp.fdev) && \ |
daniele | 0:d7f2341ab245 | 225 | (filter->in_addr == 0 || ((filter->in_addr_netmask == 0) ? (filter->in_addr == temp.in_addr) : 1)) &&\ |
daniele | 0:d7f2341ab245 | 226 | (filter->in_port == 0 || filter->in_port == temp.in_port) &&\ |
daniele | 0:d7f2341ab245 | 227 | (filter->out_addr == 0 || ((filter->out_addr_netmask == 0) ? (filter->out_addr == temp.out_addr) : 1)) && \ |
daniele | 0:d7f2341ab245 | 228 | (filter->out_port == 0 || filter->out_port == temp.out_port) && \ |
daniele | 0:d7f2341ab245 | 229 | (filter->proto == 0 || filter->proto == temp.proto ) &&\ |
daniele | 0:d7f2341ab245 | 230 | (filter->priority == 0 || filter->priority == temp.priority ) &&\ |
daniele | 0:d7f2341ab245 | 231 | (filter->tos == 0 || filter->tos == temp.tos ) &&\ |
daniele | 0:d7f2341ab245 | 232 | (filter->out_addr_netmask == 0 || ((filter->out_addr & filter->out_addr_netmask) == (temp.out_addr & filter->out_addr_netmask)) ) &&\ |
daniele | 0:d7f2341ab245 | 233 | (filter->in_addr_netmask == 0 || ((filter->in_addr & filter->in_addr_netmask) == (temp.in_addr & filter->in_addr_netmask)) )\ |
daniele | 0:d7f2341ab245 | 234 | ) ) |
daniele | 0:d7f2341ab245 | 235 | return 0; |
daniele | 0:d7f2341ab245 | 236 | |
daniele | 0:d7f2341ab245 | 237 | //No filter match! |
daniele | 0:d7f2341ab245 | 238 | ipf_dbg("ipfilter> #no match\n"); |
daniele | 0:d7f2341ab245 | 239 | return 1; |
daniele | 0:d7f2341ab245 | 240 | } |
daniele | 0:d7f2341ab245 | 241 | |
daniele | 0:d7f2341ab245 | 242 | int ipfilter(struct pico_frame *f) |
daniele | 0:d7f2341ab245 | 243 | { |
daniele | 0:d7f2341ab245 | 244 | struct filter_node *work = head; |
daniele | 0:d7f2341ab245 | 245 | |
daniele | 0:d7f2341ab245 | 246 | /*return 1 if pico_frame is discarded as result of the filtering, 0 for an incomming packet, -1 for faults*/ |
daniele | 0:d7f2341ab245 | 247 | if (!tail || !head) { |
daniele | 0:d7f2341ab245 | 248 | return 0; |
daniele | 0:d7f2341ab245 | 249 | } |
daniele | 0:d7f2341ab245 | 250 | |
daniele | 0:d7f2341ab245 | 251 | if ( match_filter(work, f) == 0 ) { |
daniele | 0:d7f2341ab245 | 252 | ipf_dbg("ipfilter> # ipfilter match\n"); |
daniele | 0:d7f2341ab245 | 253 | /*filter match, execute filter!*/ |
daniele | 0:d7f2341ab245 | 254 | return work->function_ptr(work, f); |
daniele | 0:d7f2341ab245 | 255 | } |
daniele | 0:d7f2341ab245 | 256 | while (tail != work) { |
daniele | 0:d7f2341ab245 | 257 | ipf_dbg("ipfilter> next filter..\n"); |
daniele | 0:d7f2341ab245 | 258 | work = work->next_filter; |
daniele | 0:d7f2341ab245 | 259 | if ( match_filter(work, f) == 0 ) { |
daniele | 0:d7f2341ab245 | 260 | ipf_dbg("ipfilter> # ipfilter match\n"); |
daniele | 0:d7f2341ab245 | 261 | /*filter match, execute filter!*/ |
daniele | 0:d7f2341ab245 | 262 | return work->function_ptr(work, f); |
daniele | 0:d7f2341ab245 | 263 | } |
daniele | 0:d7f2341ab245 | 264 | } |
daniele | 0:d7f2341ab245 | 265 | return 0; |
daniele | 0:d7f2341ab245 | 266 | } |
daniele | 0:d7f2341ab245 | 267 |