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

📄 llc_conn.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
 *	@sap: SAP *	@daddr: address of remote LLC (MAC + SAP) *	@laddr: address of local LLC (MAC + SAP) * *	Search connection list of the SAP and finds connection using the remote *	mac, remote sap, local mac, and local sap. Returns pointer for *	connection found, %NULL otherwise. *	Caller has to make sure local_bh is disabled. */static struct sock *__llc_lookup_established(struct llc_sap *sap,					     struct llc_addr *daddr,					     struct llc_addr *laddr){	struct sock *rc;	struct hlist_node *node;	read_lock(&sap->sk_list.lock);	sk_for_each(rc, node, &sap->sk_list.list) {		struct llc_sock *llc = llc_sk(rc);		if (llc->laddr.lsap == laddr->lsap &&		    llc->daddr.lsap == daddr->lsap &&		    llc_mac_match(llc->laddr.mac, laddr->mac) &&		    llc_mac_match(llc->daddr.mac, daddr->mac)) {			sock_hold(rc);			goto found;		}	}	rc = NULL;found:	read_unlock(&sap->sk_list.lock);	return rc;}struct sock *llc_lookup_established(struct llc_sap *sap,				    struct llc_addr *daddr,				    struct llc_addr *laddr){	struct sock *sk;	local_bh_disable();	sk = __llc_lookup_established(sap, daddr, laddr);	local_bh_enable();	return sk;}/** *	llc_lookup_listener - Finds listener for local MAC + SAP *	@sap: SAP *	@laddr: address of local LLC (MAC + SAP) * *	Search connection list of the SAP and finds connection listening on *	local mac, and local sap. Returns pointer for parent socket found, *	%NULL otherwise. *	Caller has to make sure local_bh is disabled. */static struct sock *llc_lookup_listener(struct llc_sap *sap,					struct llc_addr *laddr){	struct sock *rc;	struct hlist_node *node;	read_lock(&sap->sk_list.lock);	sk_for_each(rc, node, &sap->sk_list.list) {		struct llc_sock *llc = llc_sk(rc);		if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN &&		    llc->laddr.lsap == laddr->lsap &&		    (llc_mac_match(llc->laddr.mac, laddr->mac) ||		     llc_mac_null(llc->laddr.mac))) {			sock_hold(rc);			goto found;		}	}	rc = NULL;found:	read_unlock(&sap->sk_list.lock);	return rc;}static struct sock *__llc_lookup(struct llc_sap *sap,				 struct llc_addr *daddr,				 struct llc_addr *laddr){	struct sock *sk = __llc_lookup_established(sap, daddr, laddr);	return sk ? : llc_lookup_listener(sap, laddr);}/** *	llc_data_accept_state - designates if in this state data can be sent. *	@state: state of connection. * *	Returns 0 if data can be sent, 1 otherwise. */u8 llc_data_accept_state(u8 state){	return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&	       state != LLC_CONN_STATE_REJ;}/** *	llc_find_next_offset - finds offset for next category of transitions *	@state: state table. *	@offset: start offset. * *	Finds offset of next category of transitions in transition table. *	Returns the start index of next category. */static u16 __init llc_find_next_offset(struct llc_conn_state *state, u16 offset){	u16 cnt = 0;	struct llc_conn_state_trans **next_trans;	for (next_trans = state->transitions + offset;	     (*next_trans)->ev; next_trans++)		++cnt;	return cnt;}/** *	llc_build_offset_table - builds offset table of connection * *	Fills offset table of connection state transition table *	(llc_offset_table). */void __init llc_build_offset_table(void){	struct llc_conn_state *curr_state;	int state, ev_type, next_offset;	for (state = 0; state < NBR_CONN_STATES; state++) {		curr_state = &llc_conn_state_table[state];		next_offset = 0;		for (ev_type = 0; ev_type < NBR_CONN_EV; ev_type++) {			llc_offset_table[state][ev_type] = next_offset;			next_offset += llc_find_next_offset(curr_state,							    next_offset) + 1;		}	}}/** *	llc_find_offset - finds start offset of category of transitions *	@state: state of connection *	@ev_type: type of happened event * *	Finds start offset of desired category of transitions. Returns the *	desired start offset. */static int llc_find_offset(int state, int ev_type){	int rc = 0;	/* at this stage, llc_offset_table[..][2] is not important. it is for	 * init_pf_cycle and I don't know what is it.	 */	switch (ev_type) {	case LLC_CONN_EV_TYPE_PRIM:		rc = llc_offset_table[state][0]; break;	case LLC_CONN_EV_TYPE_PDU:		rc = llc_offset_table[state][4]; break;	case LLC_CONN_EV_TYPE_SIMPLE:		rc = llc_offset_table[state][1]; break;	case LLC_CONN_EV_TYPE_P_TMR:	case LLC_CONN_EV_TYPE_ACK_TMR:	case LLC_CONN_EV_TYPE_REJ_TMR:	case LLC_CONN_EV_TYPE_BUSY_TMR:		rc = llc_offset_table[state][3]; break;	}	return rc;}/** *	llc_sap_add_socket - adds a socket to a SAP *	@sap: SAP *	@sk: socket * *	This function adds a socket to sk_list of a SAP. */void llc_sap_add_socket(struct llc_sap *sap, struct sock *sk){	llc_sap_hold(sap);	write_lock_bh(&sap->sk_list.lock);	llc_sk(sk)->sap = sap;	sk_add_node(sk, &sap->sk_list.list);	write_unlock_bh(&sap->sk_list.lock);}/** *	llc_sap_remove_socket - removes a socket from SAP *	@sap: SAP *	@sk: socket * *	This function removes a connection from sk_list.list of a SAP if *	the connection was in this list. */void llc_sap_remove_socket(struct llc_sap *sap, struct sock *sk){	write_lock_bh(&sap->sk_list.lock);	sk_del_node_init(sk);	write_unlock_bh(&sap->sk_list.lock);	llc_sap_put(sap);}/** *	llc_conn_rcv - sends received pdus to the connection state machine *	@sk: current connection structure. *	@skb: received frame. * *	Sends received pdus to the connection state machine. */static int llc_conn_rcv(struct sock* sk, struct sk_buff *skb){	struct llc_conn_state_ev *ev = llc_conn_ev(skb);	ev->type   = LLC_CONN_EV_TYPE_PDU;	ev->reason = 0;	return llc_conn_state_process(sk, skb);}static struct sock *llc_create_incoming_sock(struct sock *sk,					     struct net_device *dev,					     struct llc_addr *saddr,					     struct llc_addr *daddr){	struct sock *newsk = llc_sk_alloc(sk->sk_net, sk->sk_family, GFP_ATOMIC,					  sk->sk_prot);	struct llc_sock *newllc, *llc = llc_sk(sk);	if (!newsk)		goto out;	newllc = llc_sk(newsk);	memcpy(&newllc->laddr, daddr, sizeof(newllc->laddr));	memcpy(&newllc->daddr, saddr, sizeof(newllc->daddr));	newllc->dev = dev;	dev_hold(dev);	llc_sap_add_socket(llc->sap, newsk);	llc_sap_hold(llc->sap);out:	return newsk;}void llc_conn_handler(struct llc_sap *sap, struct sk_buff *skb){	struct llc_addr saddr, daddr;	struct sock *sk;	llc_pdu_decode_sa(skb, saddr.mac);	llc_pdu_decode_ssap(skb, &saddr.lsap);	llc_pdu_decode_da(skb, daddr.mac);	llc_pdu_decode_dsap(skb, &daddr.lsap);	sk = __llc_lookup(sap, &saddr, &daddr);	if (!sk)		goto drop;	bh_lock_sock(sk);	/*	 * This has to be done here and not at the upper layer ->accept	 * method because of the way the PROCOM state machine works:	 * it needs to set several state variables (see, for instance,	 * llc_adm_actions_2 in net/llc/llc_c_st.c) and send a packet to	 * the originator of the new connection, and this state has to be	 * in the newly created struct sock private area. -acme	 */	if (unlikely(sk->sk_state == TCP_LISTEN)) {		struct sock *newsk = llc_create_incoming_sock(sk, skb->dev,							      &saddr, &daddr);		if (!newsk)			goto drop_unlock;		skb_set_owner_r(skb, newsk);	} else {		/*		 * Can't be skb_set_owner_r, this will be done at the		 * llc_conn_state_process function, later on, when we will use		 * skb_queue_rcv_skb to send it to upper layers, this is		 * another trick required to cope with how the PROCOM state		 * machine works. -acme		 */		skb->sk = sk;	}	if (!sock_owned_by_user(sk))		llc_conn_rcv(sk, skb);	else {		dprintk("%s: adding to backlog...\n", __FUNCTION__);		llc_set_backlog_type(skb, LLC_PACKET);		sk_add_backlog(sk, skb);	}out:	bh_unlock_sock(sk);	sock_put(sk);	return;drop:	kfree_skb(skb);	return;drop_unlock:	kfree_skb(skb);	goto out;}#undef LLC_REFCNT_DEBUG#ifdef LLC_REFCNT_DEBUGstatic atomic_t llc_sock_nr;#endif/** *	llc_backlog_rcv - Processes rx frames and expired timers. *	@sk: LLC sock (p8022 connection) *	@skb: queued rx frame or event * *	This function processes frames that has received and timers that has *	expired during sending an I pdu (refer to data_req_handler).  frames *	queue by llc_rcv function (llc_mac.c) and timers queue by timer *	callback functions(llc_c_ac.c). */static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb){	int rc = 0;	struct llc_sock *llc = llc_sk(sk);	if (likely(llc_backlog_type(skb) == LLC_PACKET)) {		if (likely(llc->state > 1)) /* not closed */			rc = llc_conn_rcv(sk, skb);		else			goto out_kfree_skb;	} else if (llc_backlog_type(skb) == LLC_EVENT) {		/* timer expiration event */		if (likely(llc->state > 1))  /* not closed */			rc = llc_conn_state_process(sk, skb);		else			goto out_kfree_skb;	} else {		printk(KERN_ERR "%s: invalid skb in backlog\n", __FUNCTION__);		goto out_kfree_skb;	}out:	return rc;out_kfree_skb:	kfree_skb(skb);	goto out;}/** *     llc_sk_init - Initializes a socket with default llc values. *     @sk: socket to initialize. * *     Initializes a socket with default llc values. */static void llc_sk_init(struct sock* sk){	struct llc_sock *llc = llc_sk(sk);	llc->state    = LLC_CONN_STATE_ADM;	llc->inc_cntr = llc->dec_cntr = 2;	llc->dec_step = llc->connect_step = 1;	init_timer(&llc->ack_timer.timer);	llc->ack_timer.expire	      = sysctl_llc2_ack_timeout;	llc->ack_timer.timer.data     = (unsigned long)sk;	llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;	init_timer(&llc->pf_cycle_timer.timer);	llc->pf_cycle_timer.expire	   = sysctl_llc2_p_timeout;	llc->pf_cycle_timer.timer.data     = (unsigned long)sk;	llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;	init_timer(&llc->rej_sent_timer.timer);	llc->rej_sent_timer.expire	   = sysctl_llc2_rej_timeout;	llc->rej_sent_timer.timer.data     = (unsigned long)sk;	llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;	init_timer(&llc->busy_state_timer.timer);	llc->busy_state_timer.expire	     = sysctl_llc2_busy_timeout;	llc->busy_state_timer.timer.data     = (unsigned long)sk;	llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;	llc->n2 = 2;   /* max retransmit */	llc->k  = 2;   /* tx win size, will adjust dynam */	llc->rw = 128; /* rx win size (opt and equal to			* tx_win of remote LLC) */	skb_queue_head_init(&llc->pdu_unack_q);	sk->sk_backlog_rcv = llc_backlog_rcv;}/** *	llc_sk_alloc - Allocates LLC sock *	@family: upper layer protocol family *	@priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) * *	Allocates a LLC sock and initializes it. Returns the new LLC sock *	or %NULL if there's no memory available for one */struct sock *llc_sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot){	struct sock *sk = sk_alloc(net, family, priority, prot);	if (!sk)		goto out;	llc_sk_init(sk);	sock_init_data(NULL, sk);#ifdef LLC_REFCNT_DEBUG	atomic_inc(&llc_sock_nr);	printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,		__FUNCTION__, atomic_read(&llc_sock_nr));#endifout:	return sk;}/** *	llc_sk_free - Frees a LLC socket *	@sk - socket to free * *	Frees a LLC socket */void llc_sk_free(struct sock *sk){	struct llc_sock *llc = llc_sk(sk);	llc->state = LLC_CONN_OUT_OF_SVC;	/* Stop all (possibly) running timers */	llc_conn_ac_stop_all_timers(sk, NULL);#ifdef DEBUG_LLC_CONN_ALLOC	printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,		skb_queue_len(&llc->pdu_unack_q),		skb_queue_len(&sk->sk_write_queue));#endif	skb_queue_purge(&sk->sk_receive_queue);	skb_queue_purge(&sk->sk_write_queue);	skb_queue_purge(&llc->pdu_unack_q);#ifdef LLC_REFCNT_DEBUG	if (atomic_read(&sk->sk_refcnt) != 1) {		printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",			sk, __FUNCTION__, atomic_read(&sk->sk_refcnt));		printk(KERN_DEBUG "%d LLC sockets are still alive\n",			atomic_read(&llc_sock_nr));	} else {		atomic_dec(&llc_sock_nr);		printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,			__FUNCTION__, atomic_read(&llc_sock_nr));	}#endif	sock_put(sk);}/** *	llc_sk_reset - resets a connection *	@sk: LLC socket to reset * *	Resets a connection to the out of service state. Stops its timers *	and frees any frames in the queues of the connection. */void llc_sk_reset(struct sock *sk){	struct llc_sock *llc = llc_sk(sk);	llc_conn_ac_stop_all_timers(sk, NULL);	skb_queue_purge(&sk->sk_write_queue);	skb_queue_purge(&llc->pdu_unack_q);	llc->remote_busy_flag	= 0;	llc->cause_flag		= 0;	llc->retry_count	= 0;	llc_conn_set_p_flag(sk, 0);	llc->f_flag		= 0;	llc->s_flag		= 0;	llc->ack_pf		= 0;	llc->first_pdu_Ns	= 0;	llc->ack_must_be_send	= 0;	llc->dec_step		= 1;	llc->inc_cntr		= 2;	llc->dec_cntr		= 2;	llc->X			= 0;	llc->failed_data_req	= 0 ;	llc->last_nr		= 0;}

⌨️ 快捷键说明

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