Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | /* * Generic loadable firewalls. At the moment only IP will actually * use these, but people can add the others as they are needed. * * Authors: Dave Bonn (for IP) * much hacked by: Alan Cox */ #include <linux/module.h> #include <linux/skbuff.h> #include <linux/firewall.h> #include <linux/init.h> #include <linux/interrupt.h> #include <asm/semaphore.h> DECLARE_MUTEX(firewall_sem); static int firewall_policy[NPROTO]; static struct firewall_ops *firewall_chain[NPROTO]; /* * Register a firewall */ int register_firewall(int pf, struct firewall_ops *fw) { struct firewall_ops **p; if(pf<0||pf>=NPROTO) return -EINVAL; /* * Don't allow two people to adjust at once. */ down(&firewall_sem); p=&firewall_chain[pf]; while(*p) { if(fw->fw_priority > (*p)->fw_priority) break; p=&((*p)->next); } /* * We need to use a memory barrier to make sure that this * works correctly even in SMP with weakly ordered writes. * * This is atomic wrt interrupts (and generally walking the * chain), but not wrt itself (so you can't call this from * an interrupt. Not that you'd want to). */ fw->next=*p; mb(); *p = fw; /* * And release the sleep lock */ up(&firewall_sem); return 0; } /* * Unregister a firewall */ int unregister_firewall(int pf, struct firewall_ops *fw) { struct firewall_ops **nl; if(pf<0||pf>=NPROTO) return -EINVAL; /* * Don't allow two people to adjust at once. */ down(&firewall_sem); nl=&firewall_chain[pf]; while(*nl!=NULL) { if(*nl==fw) { struct firewall_ops *f=fw->next; *nl = f; up(&firewall_sem); synchronize_bh(); return 0; } nl=&((*nl)->next); } up(&firewall_sem); return -ENOENT; } int call_fw_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb) { struct firewall_ops *fw=firewall_chain[pf]; while(fw!=NULL) { int rc=fw->fw_forward(fw,pf,dev,phdr,arg,skb); if(rc!=FW_SKIP) return rc; fw=fw->next; } return firewall_policy[pf]; } /* * Actual invocation of the chains */ int call_in_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb) { struct firewall_ops *fw=firewall_chain[pf]; while(fw!=NULL) { int rc=fw->fw_input(fw,pf,dev,phdr,arg,skb); if(rc!=FW_SKIP) return rc; fw=fw->next; } return firewall_policy[pf]; } int call_out_firewall(int pf, struct device *dev, void *phdr, void *arg, struct sk_buff **skb) { struct firewall_ops *fw=firewall_chain[pf]; while(fw!=NULL) { int rc=fw->fw_output(fw,pf,dev,phdr,arg,skb); if(rc!=FW_SKIP) return rc; fw=fw->next; } /* alan, is this right? */ return firewall_policy[pf]; } EXPORT_SYMBOL(register_firewall); EXPORT_SYMBOL(unregister_firewall); EXPORT_SYMBOL(call_in_firewall); EXPORT_SYMBOL(call_out_firewall); EXPORT_SYMBOL(call_fw_firewall); __initfunc(void fwchain_init(void)) { int i; for(i=0;i<NPROTO;i++) firewall_policy[i]=FW_ACCEPT; } |