packet_queue.c

説明を見る。
00001 /*
00002  * This is a module which is used for queueing IPv4 packets and
00003  * communicating with userspace via netlink.
00004  *
00005 
00006  * (C) 2000 James Morris, this code is GPL.
00007  *
00008  * 2002-01-10: I modified this code slight to offer more comparisions... - Luke Klein-Berndt
00009  * 2000-03-27: Simplified code (thanks to Andi Kleen for clues).
00010  * 2000-05-20: Fixed notifier problems (following Miguel Freitas' report).
00011  * 2000-06-19: Fixed so nfmark is copied to metadata (reported by Sebastian
00012  *             Zander).
00013  * 2000-08-01: Added Nick Williams' MAC support.
00014  *
00015  */
00016 
00017 #include "packet_queue.h"
00018 
00019 #define IPQ_QMAX_DEFAULT 1024
00020 #define IPQ_PROC_FS_NAME "ip_queue"
00021 #define NET_IPQ_QMAX 2088
00022 #define NET_IPQ_QMAX_NAME "ip_queue_maxlen"
00023 
00024 typedef struct ipq_rt_info {
00025     __u8 tos;
00026     __u32 daddr;
00027     __u32 saddr;
00028 } ipq_rt_info_t;
00029 
00030 typedef struct ipq_queue_element {
00031     struct list_head list;              /* Links element into queue */
00032     int verdict;                        /* Current verdict */
00033     struct nf_info *info;               /* Extra info from netfilter */
00034     struct sk_buff *skb;                /* Packet inside */
00035     ipq_rt_info_t rt_info;              /* May need post-mangle routing */
00036 } ipq_queue_element_t;
00037 
00038 typedef int (*ipq_send_cb_t)(ipq_queue_element_t *e);
00039 
00040 typedef struct ipq_queue {
00041     int len;                    /* Current queue len */
00042     int *maxlen;                        /* Maximum queue len, via sysctl */
00043     unsigned char flushing;             /* If queue is being flushed */
00044     unsigned char terminate;    /* If the queue is being terminated */
00045     struct list_head list;              /* Head of packet queue */
00046     spinlock_t lock;            /* Queue spinlock */
00047 } ipq_queue_t;
00048 
00049 static ipq_queue_t *q;
00050 static int netfilter_receive(struct sk_buff *skb, struct nf_info *info, void *data);
00051 
00052 /****************************************************************************
00053  *
00054  * Packet queue
00055  *
00056  ****************************************************************************/
00057 /* Dequeue a packet if matched by cmp, or the next available if cmp is NULL */
00058 static ipq_queue_element_t * ipq_dequeue( int (*cmp)(ipq_queue_element_t *, u_int32_t), u_int32_t data)
00059 {
00060     struct list_head *i;
00061 
00062     spin_lock_bh(&q->lock);
00063     for (i = q->list.prev; i != &q->list; i = i->prev) {
00064         ipq_queue_element_t *e = (ipq_queue_element_t *)i;
00065 
00066         if (!cmp || cmp(e, data)) {
00067             list_del(&e->list);
00068             q->len--;
00069             spin_unlock_bh(&q->lock);
00070             return e;
00071         }
00072     }
00073     spin_unlock_bh(&q->lock);
00074     return NULL;
00075 }
00076 
00077 
00078 /* Flush all packets */
00079 static void ipq_flush()
00080 {
00081     ipq_queue_element_t *e;
00082 
00083     spin_lock_bh(&q->lock);
00084     q->flushing = 1;
00085     spin_unlock_bh(&q->lock);
00086     while ((e = ipq_dequeue( NULL, 0))) {
00087         e->verdict = NF_DROP;
00088         nf_reinject(e->skb, e->info, e->verdict);
00089         kfree(e);
00090     }
00091     spin_lock_bh(&q->lock);
00092     q->flushing = 0;
00093     spin_unlock_bh(&q->lock);
00094 }
00095 
00096 
00097 
00098 
00099 static int ipq_create_queue(int *sysctl_qmax)
00100 {
00101     int status;
00102 
00103     q = kmalloc(sizeof(ipq_queue_t), GFP_KERNEL);
00104     if (q == NULL) {
00105         return 0;
00106     }
00107     q->len = 0;
00108     q->maxlen = sysctl_qmax;
00109     q->flushing = 0;
00110     q->terminate = 0;
00111     INIT_LIST_HEAD(&q->list);
00112     spin_lock_init(&q->lock);
00113 
00114     status = nf_register_queue_handler(PF_INET, netfilter_receive, q);
00115     if (status < 0) {
00116       printk("Could not create Packet Queue! %d\n",status);
00117         kfree(q);
00118         return 0;
00119     }
00120     return 1;
00121 }
00122 
00123 static int ipq_enqueue(ipq_queue_t *g,struct sk_buff *skb, struct nf_info *info)
00124 {
00125     ipq_queue_element_t *e;
00126 
00127 
00128     if (q!=g)
00129     {
00130         printk("trying to enqueue but do not have right queue!!!\n");
00131         return 0;
00132     }
00133 
00134     e = kmalloc(sizeof(*e), GFP_ATOMIC);
00135     if (e == NULL) {
00136         printk(KERN_ERR "ip_queue: OOM in enqueue\n");
00137         return -ENOMEM;
00138     }
00139 
00140     e->verdict = NF_DROP;
00141     e->info = info;
00142     e->skb = skb;
00143 
00144     if (e->info->hook == NF_IP_LOCAL_OUT) {
00145         struct iphdr *iph = skb->nh.iph;
00146 
00147         e->rt_info.tos = iph->tos;
00148         e->rt_info.daddr = iph->daddr;
00149         e->rt_info.saddr = iph->saddr;
00150     }
00151 
00152     spin_lock_bh(&q->lock);
00153     if (q->len >= *q->maxlen) {
00154         spin_unlock_bh(&q->lock);
00155         if (net_ratelimit())
00156             printk(KERN_WARNING "ip_queue: full at %d entries, "
00157                    "dropping packet(s).\n", q->len);
00158         goto free_drop;
00159     }
00160     if (q->flushing || q->terminate) {
00161         spin_unlock_bh(&q->lock);
00162         goto free_drop;
00163     }
00164     list_add(&e->list, &q->list);
00165     q->len++;
00166     spin_unlock_bh(&q->lock);
00167 
00168     return q->len;
00169 free_drop:
00170     kfree(e);
00171     return -EBUSY;
00172 }
00173 
00174 static void ipq_destroy_queue()
00175 {
00176 
00177     nf_unregister_queue_handler(PF_INET);
00178 
00179     spin_lock_bh(&q->lock);
00180     q->terminate = 1;
00181     spin_unlock_bh(&q->lock);
00182     ipq_flush();
00183     kfree(q);
00184 }
00185 
00186 /* With a chainsaw... */
00187 static int route_me_harder(struct sk_buff *skb)
00188 {
00189     struct iphdr *iph = skb->nh.iph;
00190     struct rtable *rt;
00191 
00192     struct rt_key key = {
00193                     dst:iph->daddr, src:iph->saddr,
00194                     oif:skb->sk ? skb->sk->bound_dev_if : 0,
00195                     tos:RT_TOS(iph->tos)|RTO_CONN,
00196 #ifdef CONFIG_IP_ROUTE_FWMARK
00197                     fwmark:skb->nfmark
00198 #endif
00199                         };
00200 
00201     if (ip_route_output_key(&rt, &key) != 0) {
00202         printk("route_me_harder: No more route.\n");
00203         return -EINVAL;
00204     }
00205 
00206     /* Drop old route. */
00207     dst_release(skb->dst);
00208     skb->dst = &rt->u.dst;
00209     return 0;
00210 }
00211 
00212 static inline int id_cmp(ipq_queue_element_t *e,u_int32_t id)
00213 {
00214     return (id == (unsigned long )e);
00215 }
00216 
00217 
00218 static inline int dev_cmp(ipq_queue_element_t *e, u_int32_t ifindex)
00219 {
00220     if (e->info->indev)
00221         if (e->info->indev->ifindex == ifindex)
00222             return 1;
00223     if (e->info->outdev)
00224         if (e->info->outdev->ifindex == ifindex)
00225             return 1;
00226     return 0;
00227 }
00228 
00229 static inline int ip_cmp(ipq_queue_element_t *e, u_int32_t ip)
00230 {
00231 
00232     if (e->rt_info.daddr == ip)
00233         return 1;
00234 
00235     return 0;
00236 }
00237 
00238 
00239 /* Drop any queued packets associated with device ifindex */
00240 static void ipq_dev_drop(int ifindex)
00241 {
00242     ipq_queue_element_t *e;
00243 
00244     while ((e = ipq_dequeue(dev_cmp,  ifindex))) {
00245         e->verdict = NF_DROP;
00246         nf_reinject(e->skb, e->info, e->verdict);
00247         kfree(e);
00248     }
00249 }
00250 
00251 void ipq_send_ip(u_int32_t ip)
00252 {
00253     ipq_queue_element_t *e;
00254 
00255     while ((e = ipq_dequeue( ip_cmp, ip))) {
00256         e->verdict = NF_ACCEPT;
00257         
00258         e->skb->nfcache |= NFC_ALTERED;
00259         route_me_harder(e->skb);
00260         nf_reinject(e->skb, e->info, e->verdict);
00261 
00262         kfree(e);
00263     }
00264 }
00265 
00266 
00267 void ipq_drop_ip(u_int32_t ip)
00268 {
00269     ipq_queue_element_t *e;
00270 
00271     while ((e = ipq_dequeue( ip_cmp, ip))) {
00272 
00273         e->verdict = NF_DROP;
00274         icmp_send(e->skb,ICMP_DEST_UNREACH,ICMP_HOST_UNREACH,0);
00275         nf_reinject(e->skb, e->info, e->verdict);
00276         kfree(e);
00277     }
00278 }
00279 
00280 
00281 /****************************************************************************
00282  *
00283  * Netfilter interface
00284  *
00285  ****************************************************************************/
00286 
00287 /*
00288  * Packets arrive here from netfilter for queuing to userspace.
00289  * All of them must be fed back via nf_reinject() or Alexey will kill Rusty.
00290  */
00291 int ipq_insert_packet(struct sk_buff *skb,
00292                       struct nf_info *info)
00293 {
00294     return ipq_enqueue(q, skb, info);
00295 }
00296 
00297 
00298 static int netfilter_receive(struct sk_buff *skb,
00299                              struct nf_info *info, void *data)
00300 {
00301     return ipq_enqueue((ipq_queue_t *)data, skb, info);
00302 }
00303 
00304 /****************************************************************************
00305  *
00306  * System events
00307  *
00308  ****************************************************************************/
00309 
00310 static int receive_event(struct notifier_block *this,
00311                          unsigned long event, void *ptr)
00312 {
00313     struct net_device *dev = ptr;
00314 
00315     /* Drop any packets associated with the downed device */
00316     if (event == NETDEV_DOWN)
00317         ipq_dev_drop( dev->ifindex);
00318     return NOTIFY_DONE;
00319 }
00320 
00321 struct notifier_block ipq_dev_notifier = {
00322             receive_event,
00323             NULL,
00324             0
00325         };
00326 
00327 /****************************************************************************
00328  *
00329  * Sysctl - queue tuning.
00330  *
00331  ****************************************************************************/
00332 
00333 static int sysctl_maxlen = IPQ_QMAX_DEFAULT;
00334 
00335 static struct ctl_table_header *ipq_sysctl_header;
00336 
00337 static ctl_table ipq_table[] = {
00338                                    { NET_IPQ_QMAX, NET_IPQ_QMAX_NAME, &sysctl_maxlen,
00339                                      sizeof(sysctl_maxlen), 0644,  NULL, proc_dointvec },
00340                                    { 0 }
00341                                };
00342 
00343 static ctl_table ipq_dir_table[] = {
00344                                        {NET_IPV4, "ipv4", NULL, 0, 0555, ipq_table, 0, 0, 0, 0, 0},
00345                                        { 0 }
00346                                    };
00347 
00348 static ctl_table ipq_root_table[] = {
00349                                         {CTL_NET, "net", NULL, 0, 0555, ipq_dir_table, 0, 0, 0, 0, 0},
00350                                         { 0 }
00351                                     };
00352 
00353 /****************************************************************************
00354  *
00355  * Module stuff.
00356  *
00357  ****************************************************************************/
00358 
00359 int init_packet_queue(void)
00360 {
00361     int status = 0;
00362     //struct proc_dir_entry *proc;
00363 
00364     status= ipq_create_queue(  &sysctl_maxlen);
00365     if (status == 0) {
00366         printk(KERN_ERR "ip_queue: initialisation failed: unable to "
00367                "create queue\n");
00368 
00369         return status;
00370     }
00371     /*  proc = proc_net_create(IPQ_PROC_FS_NAME, 0, ipq_get_info);
00372         if (proc) proc->owner = THIS_MODULE;
00373         else {
00374                 ipq_destroy_queue(nlq);
00375                 sock_release(nfnl->socket);
00376                 return -ENOMEM;
00377         }*/
00378 
00379     ipq_sysctl_header = register_sysctl_table(ipq_root_table, 0);
00380     return status;
00381 }
00382 
00383 void cleanup_packet_queue(void)
00384 {
00385     unregister_sysctl_table(ipq_sysctl_header);
00386     //proc_net_remove(IPQ_PROC_FS_NAME);
00387 
00388     ipq_destroy_queue(q);
00389 
00390 }
00391 

kernel_aodvmに対してThu Nov 10 18:53:11 2005に生成されました。  doxygen 1.4.5