- 浏览: 316027 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
5.10 添加/更新SPD(安全策略) // 添加安全策略到安全策略数据库SPDB static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { int err = 0; struct sadb_lifetime *lifetime; struct sadb_address *sa; struct sadb_x_policy *pol; struct xfrm_policy *xp; struct km_event c; struct sadb_x_sec_ctx *sec_ctx; // 错误检查, 源目的地址类型要一致, 策略信息非空 if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || !ext_hdrs[SADB_X_EXT_POLICY-1]) return -EINVAL; // 策略指针 pol = ext_hdrs[SADB_X_EXT_POLICY-1]; // 策略类型只能是DISCARD, NONE和IPSEC三者之一 if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC) return -EINVAL; // 必须明确该SP作用于哪个方向的的数据: IN, OUT和FORWARD, 最后那个不是RFC标准的 if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) return -EINVAL; // 分配xfrm策略 xp = xfrm_policy_alloc(GFP_KERNEL); if (xp == NULL) return -ENOBUFS; // 策略的动作: 阻塞还是放行 xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); // 策略的优先级 xp->priority = pol->sadb_x_policy_priority; // 获取策略源地址及地址类型(v4 or v6) sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr); if (!xp->family) { err = -EINVAL; goto out; } // 填充策略选择子结构参数, 选择子中包括用来辨别策略的相关参数, 用来查找匹配策略 // 协议族 xp->selector.family = xp->family; // 地址长度 xp->selector.prefixlen_s = sa->sadb_address_prefixlen; // 协议 xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); // 策略中可以有上层协议的源端口参数, 不过不是必须的 xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port; if (xp->selector.sport) xp->selector.sport_mask = htons(0xffff); // 获取策略目的地址及地址类型(v4 or v6) // 和源地址处理类似 sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); xp->selector.prefixlen_d = sa->sadb_address_prefixlen; /* Amusing, we set this twice. KAME apps appear to set same value * in both addresses. */ xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port; if (xp->selector.dport) xp->selector.dport_mask = htons(0xffff); // 用户定义的安全上下文 sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; if (sec_ctx != NULL) { struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); if (!uctx) { err = -ENOBUFS; goto out; } err = security_xfrm_policy_alloc(xp, uctx); kfree(uctx); if (err) goto out; } // lft: xfrm_lifetime_config, 生存时间配置参数 // 关于字节数和包数的软硬限制初始化 xp->lft.soft_byte_limit = XFRM_INF; xp->lft.hard_byte_limit = XFRM_INF; xp->lft.soft_packet_limit = XFRM_INF; xp->lft.hard_packet_limit = XFRM_INF; // 如果在消息中定义了限制, 设置之 if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) { xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; } if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) { xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; } xp->xfrm_nr = 0; // 如果是IPSEC策略, 解析相关请求 if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && (err = parse_ipsecrequests(xp, pol)) < 0) goto out; // 将策略xp插入内核SPDB err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, // 一般是添加, 也可以是更新 hdr->sadb_msg_type != SADB_X_SPDUPDATE); if (err) goto out; if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) c.event = XFRM_MSG_UPDPOLICY; else c.event = XFRM_MSG_NEWPOLICY; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; // 策略通知回调处理 km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); xfrm_pol_put(xp); return 0; out: security_xfrm_policy_free(xp); kfree(xp); return err; } /* net/xfrm/xfrm_policy.c */ // 插入策略 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) { struct xfrm_policy *pol; struct xfrm_policy *delpol; struct hlist_head *chain; struct hlist_node *entry, *newpos, *last; struct dst_entry *gc_list; write_lock_bh(&xfrm_policy_lock); // 找到具体的hash链表, SPDB也是用HASH表实现的 chain = policy_hash_bysel(&policy->selector, policy->family, dir); delpol = NULL; newpos = NULL; last = NULL; // 遍历链表, 该链表是以策略的优先级值进行排序的链表, 因此需要根据新策略的优先级大小 // 将新策略插到合适的位置 hlist_for_each_entry(pol, entry, chain, bydst) { // delpol要为空 if (!delpol && // 策略类型比较 pol->type == policy->type && // 选择子比较 !selector_cmp(&pol->selector, &policy->selector) && // 安全上下文比较 xfrm_sec_ctx_match(pol->security, policy->security)) { // 找到了 if (excl) { // 如果是添加操作, 要插入的策略在数据库中已经存在, 发生错误 write_unlock_bh(&xfrm_policy_lock); return -EEXIST; } // 保存好要删除的策略位置 delpol = pol; // 要更新的策略优先级值大于原有的优先级值, 重新循环找到合适的插入位置 // 因为这个链表是以优先级值进行排序的, 不能乱 // 现在delpol已经非空了, 前面的策略查找条件已经不可能满足了 if (policy->priority > pol->priority) continue; } else if (policy->priority >= pol->priority) { // 如果新的优先级不低于当前的优先级, 保存当前节点, 继续查找合适插入位置 last = &pol->bydst; continue; } // 这里是根据新策略的优先级确定的插入位置 if (!newpos) newpos = &pol->bydst; // 如果已经找到要删除的策略, 中断 if (delpol) break; last = &pol->bydst; } if (!newpos) newpos = last; // 插入策略到按目的地址HASH的链表 if (newpos) hlist_add_after(newpos, &policy->bydst); else hlist_add_head(&policy->bydst, chain); xfrm_pol_hold(policy); xfrm_policy_count[dir]++; atomic_inc(&flow_cache_genid); // 如果有相同的老策略, 要从目的地址HASH和索引号HASH这两个表中删除 if (delpol) { hlist_del(&delpol->bydst); hlist_del(&delpol->byidx); xfrm_policy_count[dir]--; } // 获取策略索引号, 插入索引HASH链表 policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index)); // 策略插入实际时间 policy->curlft.add_time = (unsigned long)xtime.tv_sec; policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); // 释放老策略 if (delpol) xfrm_policy_kill(delpol); else if (xfrm_bydst_should_resize(dir, NULL)) schedule_work(&xfrm_hash_work); // 下面释放所有策略当前的路由cache read_lock_bh(&xfrm_policy_lock); gc_list = NULL; entry = &policy->bydst; // 遍历链表, 搜集垃圾路由cache建立链表 hlist_for_each_entry_continue(policy, entry, bydst) { struct dst_entry *dst; write_lock(&policy->lock); dst = policy->bundles; if (dst) { struct dst_entry *tail = dst; while (tail->next) tail = tail->next; tail->next = gc_list; gc_list = dst; policy->bundles = NULL; } write_unlock(&policy->lock); } read_unlock_bh(&xfrm_policy_lock); // 释放垃圾路由cahce while (gc_list) { struct dst_entry *dst = gc_list; gc_list = dst->next; dst_free(dst); } return 0; } EXPORT_SYMBOL(xfrm_policy_insert); 5.11 删除SPD static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { int err; struct sadb_address *sa; struct sadb_x_policy *pol; struct xfrm_policy *xp, tmp; struct xfrm_selector sel; struct km_event c; struct sadb_x_sec_ctx *sec_ctx; // 错误检查, 源目的地址类型要一致, 策略信息非空 if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || !ext_hdrs[SADB_X_EXT_POLICY-1]) return -EINVAL; // 消息中定义的策略 pol = ext_hdrs[SADB_X_EXT_POLICY-1]; // 策略类型合法性检查 if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) return -EINVAL; memset(&sel, 0, sizeof(sel)); // 解析消息中的源地址参数填充到选择子结构中 sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); sel.prefixlen_s = sa->sadb_address_prefixlen; sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port; if (sel.sport) sel.sport_mask = htons(0xffff); // 解析消息中的目的地址参数填充到选择子结构中 sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); sel.prefixlen_d = sa->sadb_address_prefixlen; sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port; if (sel.dport) sel.dport_mask = htons(0xffff); sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; memset(&tmp, 0, sizeof(struct xfrm_policy)); // 扩展的用户安全上下文信息处理 if (sec_ctx != NULL) { struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); if (!uctx) return -ENOMEM; err = security_xfrm_policy_alloc(&tmp, uctx); kfree(uctx); if (err) return err; } // 根据策略类型, 处理的数据方向, 选择子参数等信息查找策略 // 同时最后一个参数为1表示找到后将策略从系统的SPDB链表中断开后删除 xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, &sel, tmp.security, 1); security_xfrm_policy_free(&tmp); // 没有该策略, 出错 if (xp == NULL) return -ENOENT; err = 0; if ((err = security_xfrm_policy_delete(xp))) goto out; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; c.event = XFRM_MSG_DELPOLICY; // 反方向的策略通知回调处理 km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); out: // 释放策略 xfrm_pol_put(xp); return err; } /* net/xfrm/xfrm_policy.c */ // 根据选择子和上下文查找策略 struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete) { struct xfrm_policy *pol, *ret; struct hlist_head *chain; struct hlist_node *entry; write_lock_bh(&xfrm_policy_lock); // 定位HASH表 chain = policy_hash_bysel(sel, sel->family, dir); ret = NULL; // 遍历链表 hlist_for_each_entry(pol, entry, chain, bydst) { // 根据类型, 选择子和上下文进行匹配 if (pol->type == type && !selector_cmp(sel, &pol->selector) && xfrm_sec_ctx_match(ctx, pol->security)) { xfrm_pol_hold(pol); if (delete) { // 要的删除话将策略节点从目的地址HASH链表和索引HASH链表中断开 hlist_del(&pol->bydst); hlist_del(&pol->byidx); xfrm_policy_count[dir]--; } ret = pol; break; } } write_unlock_bh(&xfrm_policy_lock); if (ret && delete) { atomic_inc(&flow_cache_genid); // 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除 xfrm_policy_kill(ret); } return ret; } EXPORT_SYMBOL(xfrm_policy_bysel_ctx); 5.12 获取SPD static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { unsigned int dir; int err; struct sadb_x_policy *pol; struct xfrm_policy *xp; struct km_event c; // 消息中的策略头 if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) return -EINVAL; // 根据策略id判断数据方向 dir = xfrm_policy_id2dir(pol->sadb_x_policy_id); if (dir >= XFRM_POLICY_MAX) return -EINVAL; // 根据方向/ID等参数来查找策略, 如果最后一个参数为真的同时删除策略 xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id, hdr->sadb_msg_type == SADB_X_SPDDELETE2); if (xp == NULL) return -ENOENT; err = 0; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) { // 如果要删除策略, 进行通知回调 c.data.byid = 1; c.event = XFRM_MSG_DELPOLICY; km_policy_notify(xp, dir, &c); } else { // 将结果填充一个skb返回给用户空间 err = key_pol_get_resp(sk, xp, hdr, dir); } xfrm_pol_put(xp); return err; } 5.13 输出整个SPD static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; // 遍历策略链表输出策略, dump_sa是输出单一SP的函数 return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); } // 输出单一SP static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) { struct pfkey_dump_data *data = ptr; struct sk_buff *out_skb; struct sadb_msg *out_hdr; // 将安全策略填充到skb前的准备操作 out_skb = pfkey_xfrm_policy2msg_prep(xp); if (IS_ERR(out_skb)) return PTR_ERR(out_skb); // 将安全策略填充到skb pfkey_xfrm_policy2msg(out_skb, xp, dir); // 填充基本SA消息头 out_hdr = (struct sadb_msg *) out_skb->data; out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; out_hdr->sadb_msg_type = SADB_X_SPDDUMP; out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; out_hdr->sadb_msg_errno = 0; // SA消息的序号 out_hdr->sadb_msg_seq = count; out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; // 发送到指定的sock pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); return 0; } /* net/xfrm/xfrm_policy.c */ // 遍历安全策略 int xfrm_policy_walk(u8 type, int (*func)(struct xfrm_policy *, int, int, void*), void *data) { struct xfrm_policy *pol; struct hlist_node *entry; int dir, count, error; read_lock_bh(&xfrm_policy_lock); count = 0; // 先统计符合类型的策略的数量, 方向是双向的 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { struct hlist_head *table = xfrm_policy_bydst[dir].table; int i; // inexact HASH表 hlist_for_each_entry(pol, entry, &xfrm_policy_inexact[dir], bydst) { if (pol->type == type) count++; } // bydst HASH表 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { hlist_for_each_entry(pol, entry, table + i, bydst) { if (pol->type == type) count++; } } } if (count == 0) { error = -ENOENT; goto out; } // 重新遍历HASH表, 当前的count值作为SA的序号, 因此用户空间收到的序号是递减的 for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { struct hlist_head *table = xfrm_policy_bydst[dir].table; int i; hlist_for_each_entry(pol, entry, &xfrm_policy_inexact[dir], bydst) { if (pol->type != type) continue; error = func(pol, dir % XFRM_POLICY_MAX, --count, data); if (error) goto out; } for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { hlist_for_each_entry(pol, entry, table + i, bydst) { if (pol->type != type) continue; error = func(pol, dir % XFRM_POLICY_MAX, --count, data); if (error) goto out; } } } error = 0; out: read_unlock_bh(&xfrm_policy_lock); return error; } EXPORT_SYMBOL(xfrm_policy_walk); 5.14 删除全部SPD [SADB_X_SPDFLUSH] = pfkey_spdflush, // 删除全部SP static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { struct km_event c; // 删除全部MAIN类型的SP xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN); c.data.type = XFRM_POLICY_TYPE_MAIN; c.event = XFRM_MSG_FLUSHPOLICY; c.pid = hdr->sadb_msg_pid; c.seq = hdr->sadb_msg_seq; // 通知回调处理 km_policy_notify(NULL, 0, &c); return 0; } // 删除SP回调 static int key_notify_policy_flush(struct km_event *c) { struct sk_buff *skb_out; struct sadb_msg *hdr; // 分配skb skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); if (!skb_out) return -ENOBUFS; hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); // SA消息类型为删除所有SP hdr->sadb_msg_type = SADB_X_SPDFLUSH; hdr->sadb_msg_seq = c->seq; hdr->sadb_msg_pid = c->pid; hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_errno = (uint8_t) 0; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); // 广播给所有打开PF_KEY类型套接口的用户进程 pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL); return 0; } /* net/xfrm/xfrm_policy.c */ // 删除全部安全策略 void xfrm_policy_flush(u8 type) { int dir; write_lock_bh(&xfrm_policy_lock); for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { struct xfrm_policy *pol; struct hlist_node *entry; int i, killed; killed = 0; again1: // 遍历inexact HASH链表 hlist_for_each_entry(pol, entry, &xfrm_policy_inexact[dir], bydst) { // 判断类型 if (pol->type != type) continue; // 将策略从bydst链表中断开 hlist_del(&pol->bydst); // 将策略从byidt链表中断开 hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); // 将策略状态置为dead, 并添加到系统的策略垃圾链表进行调度处理准备删除 xfrm_policy_kill(pol); killed++; write_lock_bh(&xfrm_policy_lock); goto again1; } // 遍历bydst HASH链表 for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { again2: hlist_for_each_entry(pol, entry, xfrm_policy_bydst[dir].table + i, bydst) { if (pol->type != type) continue; // 将节点从链表中断开 hlist_del(&pol->bydst); hlist_del(&pol->byidx); write_unlock_bh(&xfrm_policy_lock); // 释放节点 xfrm_policy_kill(pol); killed++; write_lock_bh(&xfrm_policy_lock); goto again2; } } xfrm_policy_count[dir] -= killed; } atomic_inc(&flow_cache_genid); write_unlock_bh(&xfrm_policy_lock); } EXPORT_SYMBOL(xfrm_policy_flush); ...... 待续 ......
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2213本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1497本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1947本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1362本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1528本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 1986本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1576Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1955本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1813本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1898本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 1965本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2646本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(12)
2011-01-10 16:21 2115本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3244本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2012本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1838本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1504本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2931本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1500本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1735本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
。。。
详细描述了linux2.4/2.6内核版本中的网络子系统。解释了协议的工作方式、建立了Linux网络体系结构中的多种重要概念——从设备驱动程序概念一直到应用程序接口的概念。能帮助读者更容易理解 Linux网络架构的进程和...
Linux内核之list_head,通常链表数据结构至少应包含两个域:数据域和指针域,数据域用于存储数据,指针域用于建立与下一个节点的联系。按照指针域的组织以及各个节点之间的联系形式,链表又可以分为单链表、双链表、...
linux内核源代码情景分析,对于深入学习者有很大帮助
笔记_Linux内核完全剖析_基于0.12内核
Linux网络体系结构 Linux内核中网络协议的设计与实现,Linux网络体系结构 Linux内核中网络协议的设计与实现
linux内核设计说明,Linux内核设计与实现(第三版中文高清带目录)
Linux内核完全注释:基于0.11内核(V5.0)
linux学习_Linux内核完全注释_Linux操作系统问价学习教程_怎么样读懂Linux内核,高清版,收集打包奉上。
Linux内核完全注释V3.0,很详细很不错,希望喜欢
linux内核设计与实现
编写本书是为了向学生和专业人员提供在Linux内核中实现网络功能时所需的基础知识,本书也适合所有希望深入理解操作系统内部网络特定进程的人。本书介绍了Linux内核的关键网络组件及机制,同时也介绍了通信系统的设计...
3.提高操作系统的设计和实现能力:学习Linux内核TCP/IP协议栈源代码可以帮助学生提高操作系统的设计和实现能力,了解操作系统的核心组件。 4.应用微机原理知识:学习Linux内核TCP/IP协议栈源代码可以帮助学生应用...
Linux 内核模块是 Linux 操作系统中的一种关键机制,它允许用户动态地修改内核、加载自己编写的程序,而不需要每次都编译内核。这种机制极大地改善了 Linux 的灵活性。 Linux 内核模块可以分为静态可加载模块和动态...
Linux内核map的一张详细关系图,可以打印出来作为学习内核的note使用,非常好,也很方便
Linux 内核更新包 wsl_update_x64 Linux 内核更新包 wsl_update_x64 Linux 内核更新包 wsl_update_x64 Linux 内核更新包 wsl_update_x64 Linux 内核更新包 wsl_update_x64 Linux 内核更新包 wsl_update_x64 Linux ...
Linux内核是一个整体是结构,因此向内核添加任何东西,或者删除某些功能,都十分困难。为了解决这个问题引入了内核机制。从而可以动态的想内核中添加或者删除模块。
linux内核软中断_linux内核源码详解.docx
linux内核版本历史_linux内核的作用.docx