⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qeth_eddp.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	int page_offset;	struct qeth_eddp_element *element;	int first_lap = 1;	QETH_DBF_TEXT(trace, 5, "eddpcsdt");	page = ctx->pages[ctx->offset >> PAGE_SHIFT];	page_offset = ctx->offset % PAGE_SIZE;	element = &ctx->elements[ctx->num_elements];	while (data_len){		page_remainder = PAGE_SIZE - page_offset;		if (page_remainder < data_len){			qeth_eddp_copy_data_tcp(page + page_offset, eddp,						page_remainder, &hcsum);			element->length += page_remainder;			if (first_lap)				element->flags = SBAL_FLAGS_FIRST_FRAG;			else				element->flags = SBAL_FLAGS_MIDDLE_FRAG;			ctx->num_elements++;			element++;			data_len -= page_remainder;			ctx->offset += page_remainder;			page = ctx->pages[ctx->offset >> PAGE_SHIFT];			page_offset = 0;			element->addr = page + page_offset;		} else {			qeth_eddp_copy_data_tcp(page + page_offset, eddp,						data_len, &hcsum);			element->length += data_len;			if (!first_lap)				element->flags = SBAL_FLAGS_LAST_FRAG;			ctx->num_elements++;			ctx->offset += data_len;			data_len = 0;		}		first_lap = 0;	}	((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);}static inline u32qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len){	u32 phcsum; /* pseudo header checksum */	QETH_DBF_TEXT(trace, 5, "eddpckt4");	eddp->th.tcp.h.check = 0;	/* compute pseudo header checksum */	phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr,				    eddp->thl + data_len, IPPROTO_TCP, 0);	/* compute checksum of tcp header */	return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);}static inline u32qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len){	u32 proto;	u32 phcsum; /* pseudo header checksum */	QETH_DBF_TEXT(trace, 5, "eddpckt6");	eddp->th.tcp.h.check = 0;	/* compute pseudo header checksum */	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr,			      sizeof(struct in6_addr), 0);	phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr,			      sizeof(struct in6_addr), phcsum);	proto = htonl(IPPROTO_TCP);	phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum);	return phcsum;}static inline struct qeth_eddp_data *qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl){	struct qeth_eddp_data *eddp;	QETH_DBF_TEXT(trace, 5, "eddpcrda");	eddp = kmalloc(sizeof(struct qeth_eddp_data), GFP_ATOMIC);	if (eddp){		memset(eddp, 0, sizeof(struct qeth_eddp_data));		eddp->nhl = nhl;		eddp->thl = thl;		memcpy(&eddp->qh, qh, sizeof(struct qeth_hdr));		memcpy(&eddp->nh, nh, nhl);		memcpy(&eddp->th, th, thl);		eddp->frag = -1; /* initially we're in skb->data */	}	return eddp;}static inline void__qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,			     struct qeth_eddp_data *eddp){	struct tcphdr *tcph;	int data_len;	u32 hcsum;		QETH_DBF_TEXT(trace, 5, "eddpftcp");	eddp->skb_offset = sizeof(struct qeth_hdr) + eddp->nhl + eddp->thl;	tcph = eddp->skb->h.th;	while (eddp->skb_offset < eddp->skb->len) {		data_len = min((int)skb_shinfo(eddp->skb)->tso_size,			       (int)(eddp->skb->len - eddp->skb_offset));		/* prepare qdio hdr */		if (eddp->qh.hdr.l2.id == QETH_HEADER_TYPE_LAYER2){			eddp->qh.hdr.l2.pkt_length = data_len + ETH_HLEN +						     eddp->nhl + eddp->thl -						     sizeof(struct qeth_hdr);#ifdef CONFIG_QETH_VLAN			if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q))				eddp->qh.hdr.l2.pkt_length += VLAN_HLEN;#endif /* CONFIG_QETH_VLAN */		} else			eddp->qh.hdr.l3.length = data_len + eddp->nhl +						 eddp->thl;		/* prepare ip hdr */		if (eddp->skb->protocol == ETH_P_IP){			eddp->nh.ip4.h.tot_len = data_len + eddp->nhl +						 eddp->thl;			eddp->nh.ip4.h.check = 0;			eddp->nh.ip4.h.check =				ip_fast_csum((u8 *)&eddp->nh.ip4.h,						eddp->nh.ip4.h.ihl);		} else			eddp->nh.ip6.h.payload_len = data_len + eddp->thl;		/* prepare tcp hdr */		if (data_len == (eddp->skb->len - eddp->skb_offset)){			/* last segment -> set FIN and PSH flags */			eddp->th.tcp.h.fin = tcph->fin;			eddp->th.tcp.h.psh = tcph->psh;		}		if (eddp->skb->protocol == ETH_P_IP)			hcsum = qeth_eddp_check_tcp4_hdr(eddp, data_len);		else			hcsum = qeth_eddp_check_tcp6_hdr(eddp, data_len);		/* fill the next segment into the context */		qeth_eddp_create_segment_hdrs(ctx, eddp, data_len);		qeth_eddp_create_segment_data_tcp(ctx, eddp, data_len, hcsum);		if (eddp->skb_offset >= eddp->skb->len)			break;		/* prepare headers for next round */		if (eddp->skb->protocol == ETH_P_IP)			eddp->nh.ip4.h.id++;		eddp->th.tcp.h.seq += data_len;	}}			   static inline intqeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,			   struct sk_buff *skb, struct qeth_hdr *qhdr){	struct qeth_eddp_data *eddp = NULL;		QETH_DBF_TEXT(trace, 5, "eddpficx");	/* create our segmentation headers and copy original headers */	if (skb->protocol == ETH_P_IP)		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.iph,				skb->nh.iph->ihl*4,				(u8 *)skb->h.th, skb->h.th->doff*4);	else		eddp = qeth_eddp_create_eddp_data(qhdr, (u8 *)skb->nh.ipv6h,				sizeof(struct ipv6hdr),				(u8 *)skb->h.th, skb->h.th->doff*4);	if (eddp == NULL) {		QETH_DBF_TEXT(trace, 2, "eddpfcnm");		return -ENOMEM;	}	if (qhdr->hdr.l2.id == QETH_HEADER_TYPE_LAYER2) {		memcpy(&eddp->mac, eth_hdr(skb), ETH_HLEN);#ifdef CONFIG_QETH_VLAN		if (eddp->mac.h_proto == __constant_htons(ETH_P_8021Q)) {			eddp->vlan[0] = __constant_htons(skb->protocol);			eddp->vlan[1] = htons(vlan_tx_tag_get(skb));		}#endif /* CONFIG_QETH_VLAN */	}	/* the next flags will only be set on the last segment */	eddp->th.tcp.h.fin = 0;	eddp->th.tcp.h.psh = 0;	eddp->skb = skb;	/* begin segmentation and fill context */	__qeth_eddp_fill_context_tcp(ctx, eddp);	kfree(eddp);	return 0;}static inline voidqeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,			 int hdr_len){	int skbs_per_page;		QETH_DBF_TEXT(trace, 5, "eddpcanp");	/* can we put multiple skbs in one page? */	skbs_per_page = PAGE_SIZE / (skb_shinfo(skb)->tso_size + hdr_len);	if (skbs_per_page > 1){		ctx->num_pages = (skb_shinfo(skb)->tso_segs + 1) /				 skbs_per_page + 1;		ctx->elements_per_skb = 1;	} else {		/* no -> how many elements per skb? */		ctx->elements_per_skb = (skb_shinfo(skb)->tso_size + hdr_len +				     PAGE_SIZE) >> PAGE_SHIFT;		ctx->num_pages = ctx->elements_per_skb *				 (skb_shinfo(skb)->tso_segs + 1);	}	ctx->num_elements = ctx->elements_per_skb *			    (skb_shinfo(skb)->tso_segs + 1);}static inline struct qeth_eddp_context *qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,				 int hdr_len){	struct qeth_eddp_context *ctx = NULL;	u8 *addr;	int i;	QETH_DBF_TEXT(trace, 5, "creddpcg");	/* create the context and allocate pages */	ctx = kmalloc(sizeof(struct qeth_eddp_context), GFP_ATOMIC);	if (ctx == NULL){		QETH_DBF_TEXT(trace, 2, "ceddpcn1");		return NULL;	}	memset(ctx, 0, sizeof(struct qeth_eddp_context));	ctx->type = QETH_LARGE_SEND_EDDP;	qeth_eddp_calc_num_pages(ctx, skb, hdr_len);	if (ctx->elements_per_skb > QETH_MAX_BUFFER_ELEMENTS(card)){		QETH_DBF_TEXT(trace, 2, "ceddpcis");		kfree(ctx);		return NULL;	}	ctx->pages = kmalloc(ctx->num_pages * sizeof(u8 *), GFP_ATOMIC);	if (ctx->pages == NULL){		QETH_DBF_TEXT(trace, 2, "ceddpcn2");		kfree(ctx);		return NULL;	}	memset(ctx->pages, 0, ctx->num_pages * sizeof(u8 *));	for (i = 0; i < ctx->num_pages; ++i){		addr = (u8 *)__get_free_page(GFP_ATOMIC);		if (addr == NULL){			QETH_DBF_TEXT(trace, 2, "ceddpcn3");			ctx->num_pages = i;			qeth_eddp_free_context(ctx);			return NULL;		}		memset(addr, 0, PAGE_SIZE);		ctx->pages[i] = addr;	}	ctx->elements = kmalloc(ctx->num_elements *				sizeof(struct qeth_eddp_element), GFP_ATOMIC);	if (ctx->elements == NULL){		QETH_DBF_TEXT(trace, 2, "ceddpcn4");		qeth_eddp_free_context(ctx);		return NULL;	}	memset(ctx->elements, 0,	       ctx->num_elements * sizeof(struct qeth_eddp_element));	/* reset num_elements; will be incremented again in fill_buffer to	 * reflect number of actually used elements */	ctx->num_elements = 0;	return ctx;}static inline struct qeth_eddp_context *qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,			     struct qeth_hdr *qhdr){	struct qeth_eddp_context *ctx = NULL;		QETH_DBF_TEXT(trace, 5, "creddpct");	if (skb->protocol == ETH_P_IP)		ctx = qeth_eddp_create_context_generic(card, skb,			sizeof(struct qeth_hdr) + skb->nh.iph->ihl*4 +			skb->h.th->doff*4);	else if (skb->protocol == ETH_P_IPV6)		ctx = qeth_eddp_create_context_generic(card, skb,			sizeof(struct qeth_hdr) + sizeof(struct ipv6hdr) +			skb->h.th->doff*4);	else		QETH_DBF_TEXT(trace, 2, "cetcpinv");	if (ctx == NULL) {		QETH_DBF_TEXT(trace, 2, "creddpnl");		return NULL;	}	if (qeth_eddp_fill_context_tcp(ctx, skb, qhdr)){		QETH_DBF_TEXT(trace, 2, "ceddptfe");		qeth_eddp_free_context(ctx);		return NULL;	}	atomic_set(&ctx->refcnt, 1);	return ctx;}struct qeth_eddp_context *qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,			 struct qeth_hdr *qhdr){	QETH_DBF_TEXT(trace, 5, "creddpc");	switch (skb->sk->sk_protocol){	case IPPROTO_TCP:		return qeth_eddp_create_context_tcp(card, skb, qhdr);	default:		QETH_DBF_TEXT(trace, 2, "eddpinvp");	}	return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -