Linux.ChinaUnix.net
ChinaUnix | Linux首页 | 新闻 | 博客 | 文章 | 专栏 | 新手 | 方案 | 图书 | 下载 | 人才 | 手册 | wiki | 搜索     
Linux论坛
  会员: 密码: 免费注册 | 忘记密码 | 会员登录 | 搜索 | 帮助 


奥运快报: 
奥运热点:
 

Kernel Bug-Vulnerability-Comment library
首页 » CU论坛 » Linux » 汇总贴列表 » 内核源码 »  
[打印] [订阅] [收藏] [推荐给朋友] [本帖文本页]
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
61楼 发表于 2007-12-15 11:19 


part-2,IRT entry programming

static struct IO_APIC_route_entry  ioapic_read_entry(int apic, int pin);
/*
* basic IRTE read/write, indexed by pin,
* but how is mapped to irq, then to vector??
*/
static void ioapic_write_entry (int apic, int pin,
                struct IO_APIC_route_entry e);

/* shutup IRQ mapped by pin */
static void ioapic_mask_entry (int apic, int pin);

/*
* IRQ<-->pin mapping table is irq_2_pin[]
*
* but where irq come from??
*/
static void add_pin_to_irq (unsigned int irq, int apic, int pin)
{
        static int first_free_entry = NR_IRQS;
        struct irq_pin_list *entry = irq_2_pin + irq;

        while (entry->next)
                entry = irq_2_pin + entry->next;

        if (entry->pin != -1) {
                /*
                 * in case IRQ is shared
                 */
                entry->next = first_free_entry;
                entry = irq_2_pin + entry->next;
               
                if (++first_free_entry >= PIN_MAP_SIZE)
                        panic("io_apic.c: whoops");
        }
        entry->apic = apic;
        entry->pin  = pin;
}

/*
* Reroute an IRQ to a different pin
*
* or, cfg pin to use IRQ
*/
static void __init replace_pin_at_irq(unsigned int irq,
                                      int oldapic, int oldpin,
                                      int newapic, int newpin);
/*
* core programing method,
* first read, then write.
*/
static void __modify_IO_APIC_irq (unsigned int irq,
                                  unsigned long enable,
                                  unsigned long disable)

static void clear_IO_APIC_pin (unsigned int apic, unsigned int pin)
{
/*
* in chip of ioapic, pin is represented by route entry
*/
        struct IO_APIC_route_entry entry;
       
        /* Check delivery_mode to be sure we're not clearing an SMI pin */
        entry = ioapic_read_entry(apic, pin);
        if (entry.delivery_mode == dest_SMI)
                return;
        /*
         * Disable it in the IO-APIC irq-routing table:
         */
        ioapic_mask_entry(apic, pin);
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
62楼 发表于 2007-12-15 11:20 


part-3 irq affinity/balance

非常高兴,关于balance在CU已经看见 思一克 漂亮的工作,
这里八哥就不费心了。

[ 本帖最后由 sisi8408 于 2007-12-15 11:29 编辑 ]



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
63楼 发表于 2007-12-15 13:48 


part-4 麻烦来了,MADT/MPS

/*
* Find the IRQ entry number of a certain pin
*/
static int find_irq_entry (int apic, int pin, int type)
{
        int i;
        /*
         * bonding of irq and pin is pre-defined?!
         */
        for (i = 0; i < mp_irq_entries; i++) {
                if (mp_irqs[i].mpc_irqtype == type &&
                    (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid ||
                     mp_irqs[i].mpc_dstapic == MP_APIC_ALL) &&
                    mp_irqs[i].mpc_dstirq == pin)
                        return i;
        }
        return -1;
}
/*
* seems it is impossible to make IRQ unshared, if
* two pci devices cfged shared in mp_irqs[]??
* and it is appreciated in practical usage where
* unshared IRQ preferred.
*/
static int __init find_pci_irq_pin (int irq, int type)
{
        int i;

        for (i = 0; i < mp_irq_entries; i++) {
                int lbus;
               
                lbus = mp_irqs[i].mpc_srcbus;

                if (mp_bus_id_to_type[lbus]  == MP_BUS_PCI
                 && mp_irqs[i].mpc_irqtype   == type
                 && mp_irqs[i].mpc_srcbusirq == irq)        /* defined in this way */
                        return mp_irqs[i].mpc_dstirq;        /* and its pin */
        }
        return -1;
}

/*
* Find a specific PCI IRQ entry
*
*********************************************
* Not an __init, possibly needed by modules *  
*********************************************
*
* linux从不决人后路,如果Solaris敢放马开放,
* linux充分吸收后,就没有吸引用户的必要了,请鳖揭开面纱。
*/

int IO_APIC_get_PCI_irq_vector (int bus, int slot, int pin)
{
        int apic, i, best_guess = -1;

        apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus%d, "
                "slot%d, pin%d\n", bus, slot, pin);
       
        if (mp_bus_id_to_pci_bus[bus] == -1) {
                printk(KERN_WARNING
                        "PCI BIOS passed nonexistent PCI bus%d!\n", bus);
                return -1;
        }

        for (i = 0; i < mp_irq_entries; i++) {
                int lbus = mp_irqs[i].mpc_srcbus;

                for (apic = 0; apic < nr_ioapics; apic++) {
                        /*
                         * determine IRQ controler
                         */
                        if (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid
                         || mp_irqs[i].mpc_dstapic == MP_APIC_ALL)
                                break;
                }

                if (mp_bus_id_to_type[lbus] == MP_BUS_PCI
                 && !mp_irqs[i].mpc_irqtype /* need confirm */
                 && bus == lbus                /* both bus and slot match */
                 && slot == (mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f) {
                        int irq;
                       
                        irq = pin_2_irq(i, apic, mp_irqs[i].mpc_dstirq);
                        if (!(apic || IO_APIC_IRQ(irq)))
                                continue;
                        /*
                         * and pin match
                         */
                        if (pin == (mp_irqs[i].mpc_srcbusirq & 3))
                                return irq;

                        /*
                         * Use the first all-but-pin matching entry as a
                         * best-guess fuzzy result for broken mptables.
                         */
                        if (best_guess < 0)
                                best_guess = irq;
                }
        }
        return best_guess;
}
/*
* irq of pci_bus:slot.dev is determined in IOAPIC space
* 1, to which controler connected and pin?
* 2, irq = controler_nr * nr_irte + pin
* limited currently by
*        256 vector per cpu
*        128 controler
*         24 irte per controler
*
* irt<-->LAPIC mapping can also be programmed,
* goto see set_ioapic_affinity_irq(irq, TARGET_CPUS) and
* balanced_irq_init()
*
* the major purpose of MADT maybe tell OS controler and pin,
* irq can be re-cfged.
* no problem, ok.
*/
static int pin_2_irq (int idx, int apic, int pin)
{
        int irq, i;
        int bus = mp_irqs[idx].mpc_srcbus;
        /*
         * Debugging check, we are in big trouble if this message pops up!
         */
        if (mp_irqs[idx].mpc_dstirq != pin)
                printk(KERN_ERR "broken BIOS or MPTABLE parser in pin_2_irq, ayiee!!\n");

        switch (mp_bus_id_to_type[bus])
        {
                case MP_BUS_ISA: /* ISA pin */
                case MP_BUS_EISA:
                case MP_BUS_MCA:
                {
                        irq = mp_irqs[idx].mpc_srcbusirq;
                        break;
                }
                case MP_BUS_PCI: /* PCI pin */
                {
                        /*
                         * PCI IRQs are mapped in order
                         */
                        i = irq = 0;
                        while (i < apic)
                                irq += nr_ioapic_registers[i++];
                        irq += pin;
                        /*
                         * For MPS mode, so far only needed by ES7000 platform
                         */
                        if (ioapic_renumber_irq)
                                irq = ioapic_renumber_irq(apic, irq);
                        break;
                }
                default:
                {
                        printk(KERN_ERR "unknown bus type %d in pin_2_irq\n",bus);
                        irq = 0;
                        break;
                }
        }
        /*
         * PCI IRQ command line redirection.
         * Yes, limits are hardcoded.
         */
        if (pin >= 16 && pin <= 23) {
                if (pirq_entries[pin -16] != -1) {
                        if (!pirq_entries[pin -16]) {
                                apic_printk(APIC_VERBOSE, KERN_DEBUG
                                        "disabling PIRQ%d\n", pin -16);
                        } else {
                                irq = pirq_entries[pin -16];
                                apic_printk(APIC_VERBOSE, KERN_DEBUG
                                        "using PIRQ%d -> IRQ %d\n", pin -16, irq);
                        }
                }
        }
        return irq;
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
64楼 发表于 2007-12-15 13:49 


part-5 IRQ attr: trigger/polarity

/*
* 不仅变化快,还很复杂,
*  trigger: edge/level
*  polarity: high/low
*/

/*
* check irq is level or edge
*/
static inline int IO_APIC_irq_trigger (int irq)
{
        int apic, idx, pin;

        for (apic = 0; apic < nr_ioapics; apic++) {
                for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
                        idx = find_irq_entry(apic, pin, mp_INT);
                        if (idx != -1
                         && irq == pin_2_irq(idx, apic, pin))
                                return irq_trigger(idx);
                }
        }
        /*
         * nonexistent IRQs are edge default
         */
        return 0;
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
65楼 发表于 2007-12-15 13:51 


part-6 vector[IRQ]

/*
* irq_vectors is indexed by the sum of all RTEs in all I/O APICs
*/
static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };

static int __assign_irq_vector (int irq)
{
        static int current_vector = FIRST_DEVICE_VECTOR;
        static int current_offset = 0;
        int vector, offset, i;

        BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);

        if (irq_vector[irq] > 0)        /* shared irq */
                return irq_vector[irq];

        vector = current_vector;
        offset = current_offset;
next:
        vector += 8;
        if (vector >= FIRST_SYSTEM_VECTOR) {
                offset = (offset + 1) % 8;
                /*
                 * the vector of pci-irq has to
                 * be larger than FIRST_DEVICE_VECTOR,
                 * imposed by Intel
                 */
                vector = FIRST_DEVICE_VECTOR + offset;
        }
        if (vector == current_vector)
                return -ENOSPC;

        if (vector == SYSCALL_VECTOR)
                goto next;

        for (i = 0; i < NR_IRQ_VECTORS; i++)
                if (irq_vector[i] == vector)
                        goto next;

        current_vector = vector;
        current_offset = offset;

        irq_vector[irq] = vector;
        return vector;
}

static struct irq_chip        ioapic_chip;

#define IOAPIC_AUTO        -1
#define IOAPIC_EDGE         0
#define IOAPIC_LEVEL         1

static void ioapic_register_intr (int irq, int vector, unsigned long trigger)
{
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq))
          || trigger == IOAPIC_LEVEL)
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                 handle_fasteoi_irq, "fasteoi");
        else
                set_irq_chip_and_handler_name(irq, &ioapic_chip,
                                 handle_edge_irq, "edge");

        set_intr_gate(vector, interrupt[irq]);
}
/* and put all together through
* __ioapic_write_entry(apic, pin, entry);
*/
static void __init setup_IO_APIC_irqs (void);

/*
* finally setup
* struct irq_chip msi_chip, lapic_chip and ioapic_chip
* for use by struct irq_desc,
* the nut of linux abstract core of IRQ subsystem
*/
[homework]
1, howto make pci-dev irqs unshared??
2, is IT from independent thought??
[/homework]




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
66楼 发表于 2007-12-16 10:25 


#ifdef CONFIG_SMP
/*
* linux-2.6.22.5/arch/i386/kernel/io_apic.c
* 2007-12-16 10:18
* ¥1
*/
static void set_msi_irq_affinity (unsigned int irq, cpumask_t mask)
{
        struct msi_msg msg;
        unsigned int dest;
        cpumask_t tmp;
        int vector;

        cpus_and(tmp, mask, cpu_online_map);
        if (cpus_empty(tmp))
                tmp = TARGET_CPUS;
        /*
         * though tmp checked, but not used anymore.
         * the following `mask' should be tmp
         *
         * mask = tmp;
         */
        vector = assign_irq_vector(irq);
        if (vector < 0)
                return;

        dest = cpu_mask_to_apicid(mask);

        read_msi_msg(irq, &msg);

        msg.data &= ~MSI_DATA_VECTOR_MASK;
        msg.data |= MSI_DATA_VECTOR(vector);

        msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
        msg.address_lo |= MSI_ADDR_DEST_ID(dest);

        write_msi_msg(irq, &msg);
        irq_desc[irq].affinity = mask;
}
#endif




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
67楼 发表于 2007-12-16 19:27 


/* linux-2.6.22.5/arch/x86_64/kernel/mpparse.c
* 2007-12-16 19:20
* ¥1
*/
static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
{
        if (!(m->mpc_flags & MPC_APIC_USABLE))
                return;

        printk("I/O APIC #%d at 0x%X.\n",
                m->mpc_apicid, m->mpc_apicaddr);

        if (bad_ioapic(m->mpc_apicaddr))
                return;
/*
        printk("I/O APIC #%d at 0x%X",
                m->mpc_apicid, m->mpc_apicaddr);

        if (bad_ioapic(m->mpc_apicaddr)) {
                printk(" bad\n");
                return;
        } else
                printk("\n");
*/
        mp_ioapics[nr_ioapics] = *m;
        nr_ioapics++;
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
68楼 发表于 2007-12-19 21:02 


/* linux-2.6.22.5/include/linux/skbuff.h
* 2007-12-19 20:52
* ¥1
*/
static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len)
{
        if (likely(len <= skb_headlen(skb))) {
                /*
                 * howto sure skb->data += len not overflow ?
                 */
                return 1;
        }
        if (unlikely(len > skb->len))
                return 0;
        return __pskb_pull_tail(skb, len-skb_headlen(skb)) != NULL;
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
69楼 发表于 2007-12-22 09:26 


/*
  linux-2.6.22.5/kernel/workqueue.c
  2007-12-22 9:19
*/
struct workqueue_struct *__create_workqueue(const char *name,
                                            int singlethread, int freezeable)
{
        struct workqueue_struct *wq;
        struct cpu_workqueue_struct *cwq;
        int err = 0, cpu;

        wq = kzalloc(sizeof(*wq), GFP_KERNEL);
        if (!wq)
                return NULL;

        wq->cpu_wq = alloc_percpu(struct cpu_workqueue_struct);
        if (!wq->cpu_wq) {
                kfree(wq);
                return NULL;
        }

        wq->name = name;
        wq->singlethread = singlethread;
        wq->freezeable = freezeable;
        INIT_LIST_HEAD(&wq->list);

        if (singlethread) {
                cwq = init_cpu_workqueue(wq, singlethread_cpu);
                err = create_workqueue_thread(cwq, singlethread_cpu);
                start_workqueue_thread(cwq, -1);
        } else {
                mutex_lock(&workqueue_mutex);
                list_add(&wq->list, &workqueues);

                for_each_possible_cpu(cpu) {
                        cwq = init_cpu_workqueue(wq, cpu);
                        /*
                        if (!cpu_online(cpu))
                                continue;
                        if (err)
                                break;
                        */
                        if (err || !cpu_online(cpu))
                                continue;
                        err = create_workqueue_thread(cwq, cpu);
                        start_workqueue_thread(cwq, cpu);
                }
                mutex_unlock(&workqueue_mutex);
        }

        if (err) {
                destroy_workqueue(wq);
                wq = NULL;
        }
        return wq;
}




您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘
sisi8408 (linux八哥)
风云使者




UID:509266
注册:2006-12-22
最后登录: 2008-07-28
帖子:617
精华:0

可用积分:567 (稍有积蓄)
信誉积分:100
专家积分:0 (本版)

状态:...离线...

[资料] [站内短信] [Blog]


顶部
70楼 发表于 2007-12-22 12:55 


/*
  linux-2.6.22.5/net/netfilter/nf_conntrack_proto_tcp.c
  2007-12-22 10:38
  ¥6
  howto crash netfilter with TCP SYN packet, possible?
*/
static int tcp_error(struct sk_buff *skb,
                     unsigned int dataoff,
                     enum ip_conntrack_info *ctinfo,
                     int pf,
                     unsigned int hooknum)
{
        struct tcphdr _tcph, *th;
        unsigned int tcplen = skb->len - dataoff;
        u_int8_t tcpflags;

        /* Smaller that minimal TCP header? */
        th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
        if (th == NULL) {
                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                "nf_ct_tcp: short packet ");
                return -NF_ACCEPT;
        }

        /* Not whole TCP header or malformed packet */
        if (th->doff*4 < sizeof(struct tcphdr)
            || tcplen < th->doff*4) {
[color=Red]                /*
                 * 其一 隐患;/
                 * TCP头长大于60字节是合法的 8-(:
                 */
[/color]                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                "nf_ct_tcp: truncated/malformed packet ");
                return -NF_ACCEPT;
        }

        /* Checksum invalid? Ignore.
         * We skip checking packets on the outgoing path
         * because the checksum is assumed to be correct.
         */
        /* FIXME: Source route IP option packets --RR */
        if (nf_conntrack_checksum &&
            ((pf == PF_INET && hooknum == NF_IP_PRE_ROUTING) ||
             (pf == PF_INET6 && hooknum == NF_IP6_PRE_ROUTING)) &&
            nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                  "nf_ct_tcp: bad TCP checksum ");
                return -NF_ACCEPT;
        }

        /* Check TCP flags. */
        tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR|TH_PUSH));
        if (!tcp_valid_flags[tcpflags]) {
                if (LOG_INVALID(IPPROTO_TCP))
                        nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                  "nf_ct_tcp: invalid TCP flag combination ");
                return -NF_ACCEPT;
        }
        return NF_ACCEPT;
}

static void tcp_options(const struct sk_buff *skb,
                        unsigned int dataoff,
                        struct tcphdr *tcph,
                        struct ip_ct_tcp_state *state)
{
        unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
        unsigned char *ptr;
        int length = (tcph->doff*4) - sizeof(struct tcphdr);
        /*
         * length可以大于40;/
         * but sizeof(buff) = 40
         */
        if (!length)
                return;

        ptr = skb_header_pointer(skb, dataoff + sizeof(struct tcphdr),
                                 length, buff);
[color=Red]        /*
         * 其二 buff可能overflow
         */
[/color]        BUG_ON(ptr == NULL);

        state->td_scale = state->flags = 0;

        while (length > 0) {
                int opcode = *ptr++;
                int opsize;

                switch (opcode) {
                case TCPOPT_EOL:
                        return;
               
                case TCPOPT_NOP:        /* Ref: RFC 793 section 3.1 */
                        length--;
                        continue;
               
                default:
                        opsize = *ptr++;
                       
                        if (opsize < 2) /* "silly options" */
                                return;
                       
                        if (opsize > length)
                                break;        /* don't parse partial options */

                        if (opcode == TCPOPT_SACK_PERM
                            && opsize == TCPOLEN_SACK_PERM) {
                                state->flags |= IP_CT_TCP_FLAG_SACK_PERM;
                        }
                        else if (opcode == TCPOPT_WINDOW
                                 && opsize == TCPOLEN_WINDOW) {
                                state->td_scale = *(u_int8_t *)ptr;

                                if (state->td_scale > 14) {
                                        /* See RFC1323 */
                                        state->td_scale = 14;
                                }
                                state->flags |= IP_CT_TCP_FLAG_WINDOW_SCALE;
                        }
                        ptr += opsize - 2;
                        length -= opsize;
                }
        }
}

static inline void * skb_header_pointer (const struct sk_buff *skb,
                                         int offset, int len, void *buffer)
{ /* in <linux/skbuff.h> */
       
        int hlen = skb_headlen(skb);

        if (hlen - offset >= len)
                return skb->data + offset;
[color=Red]        /*
         * 其三  如果是大SYN包,使得skb_copy_bits被调用了,
         * if (len > 40 bytes)
         *        buffer overflow;
         *
         * 但是,netfilter看到的包都是整合过的,
         * 这样的机会几乎没有,要看ipfrag reasm的结果
         */
[/color]        if (skb_copy_bits(skb, offset, buffer, len) < 0)
                return NULL;

        return buffer;
}
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
{
        int i, copy;
        int start = skb_headlen(skb);

        if (offset > (int)skb->len - len)
                goto fault;

        /* Copy header. */
        if ((copy = start - offset) > 0) {
                if (copy > len)
                        copy = len;
                /*
                  这里没有check len,
                  而是默认len <= sizeof(to)
                */
                skb_copy_from_linear_data_offset(skb, offset, to, copy);
                if ((len -= copy) == 0)
                        return 0;
                offset += copy;
                to     += copy;
        }
        ...
}
void * memcpy(void *dest, const void *src, size_t count)
{
/*
   C版的memcpy in lib/string.c

   memcpy没有检测overflow的义务;/
*/
        char *tmp = dest;
        const char *s = src;

        while (count--)
                *tmp++ = *s++;
        return dest;
}

static struct sk_buff * ip_frag_reasm (struct ipq *qp, struct net_device *dev)
{ /* net/ipv4/ip_fragment.c */
       
        struct iphdr *iph;
        struct sk_buff *fp, *head = qp->fragments;
        int len;
        int ihlen;

        ipq_kill(qp);

        BUG_TRAP(head != NULL);
        BUG_TRAP(FRAG_CB(head)->offset == 0);

        /* Allocate a new buffer for the datagram. */
        ihlen = ip_hdrlen(head);
        len = ihlen + qp->len;

        if (len > 65535)
                goto out_oversize;

        /* Head of list must not be cloned. */
        if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
                goto out_nomem;

        /* If the first fragment is fragmented itself, we split
         * it to two chunks: the first with data and paged part
         * and the second, holding only fragments. */
        if (skb_shinfo(head)->frag_list) {
                struct sk_buff *clone;
                int i, plen = 0;

                if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
                        goto out_nomem;
                clone->next = head->next;
                head->next = clone;
                skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
                skb_shinfo(head)->frag_list = NULL;
                for (i=0; i<skb_shinfo(head)->nr_frags; i++)
                        plen += skb_shinfo(head)->frags[i].size;
                clone->len = clone->data_len = head->data_len - plen;
                head->data_len -= clone->len;
                head->len -= clone->len;
                clone->csum = 0;
                clone->ip_summed = head->ip_summed;
                atomic_add(clone->truesize, &ip_frag_mem);
        }

        skb_shinfo(head)->frag_list = head->next;
[color=Red]        /*
         * 其四  linux skb精巧的设计,可以方便地处理大包 &)
         *
         * 在这里没有实施linearize,性能可佳。
         */
[/color]        skb_push(head, head->data - skb_network_header(head));
        atomic_sub(head->truesize, &ip_frag_mem);

        for (fp = head->next; fp; fp = fp->next) {
                head->data_len += fp->len;
[color=Red]                /*
                 * 由于没有linearize操作,
                 * 虽然总包长要求len < 65535 byte,
                 * 首包长确可以是
                 * 82byte = 20byte<IP> + 60byte<TCP> + 2byte<trash>
                 *
                 * 所以 tcp->doff*4 = 88byte,
                 * 将迫使skb_header_pointer调用skb_copy_bits,
                 * 结果导致40byte的buff overflow
                 */
[/color]                head->len += fp->len;
               
                if (head->ip_summed != fp->ip_summed)
                        head->ip_summed = CHECKSUM_NONE;
                else if (head->ip_summed == CHECKSUM_COMPLETE)
                        head->csum = csum_add(head->csum, fp->csum);
               
                head->truesize += fp->truesize;
                atomic_sub(fp->truesize, &ip_frag_mem);
        }

        head->next = NULL;
        head->dev = dev;
        head->tstamp = qp->stamp;

        iph = ip_hdr(head);
        iph->frag_off = 0;
        iph->tot_len = htons(len);
        IP_INC_STATS_BH(IPSTATS_MIB_REASMOKS);
        qp->fragments = NULL;
        return head;

out_nomem:
        LIMIT_NETDEBUG(KERN_ERR "IP: queue_glue: no memory for gluing "
                              "queue %p\n", qp);
        goto out_fail;
out_oversize:
        if (net_ratelimit())
                printk(KERN_INFO
                        "Oversized IP packet from %d.%d.%d.%d.\n",
                        NIPQUAD(qp->saddr));
out_fail:
        IP_INC_STATS_BH(IPSTATS_MIB_REASMFAILS);
        return NULL;
}

[ 本帖最后由 sisi8408 于 2007-12-22 14:42 编辑 ]



您对本贴的看法:鲜花[0] 臭蛋[0]

__________________________________

东直门外大街
张字85号
丁字96号

发奥运快讯+1800分! | 有奖跟帖:服务器节能,奖50-100元图书 | 致电800-858-2903,了解DELL如何为你量身订制笔记本 | 送2G U盘

首页 » CU论坛 » Linux » 汇总贴列表 » 内核源码 »

 


Copyright © 2001-2008 ChinaUnix.net All Rights Reserved     联系我们:

感谢所有关心和支持过ChinaUnix的朋友们    转载本站内容请注明原作者名及出处

京ICP证041476号


清除 Cookies - Linux时代 - Archiver - WAP - TOP

Processed in 0.049106 second(s), 5 queries , Gzip enabled