xref: /openbmc/linux/net/llc/llc_station.c (revision ff5cb6a4)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * llc_station.c - station component of LLC
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * Copyright (c) 1997 by Procom Technology, Inc.
51da177e4SLinus Torvalds  * 		 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * This program can be redistributed or modified under the terms of the
81da177e4SLinus Torvalds  * GNU General Public License as published by the Free Software Foundation.
91da177e4SLinus Torvalds  * This program is distributed without any warranty or implied warranty
101da177e4SLinus Torvalds  * of merchantability or fitness for a particular purpose.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * See the GNU General Public License for more details.
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds #include <linux/init.h>
151da177e4SLinus Torvalds #include <linux/module.h>
165a0e3ad6STejun Heo #include <linux/slab.h>
171da177e4SLinus Torvalds #include <net/llc.h>
181da177e4SLinus Torvalds #include <net/llc_sap.h>
191da177e4SLinus Torvalds #include <net/llc_conn.h>
201da177e4SLinus Torvalds #include <net/llc_c_ac.h>
211da177e4SLinus Torvalds #include <net/llc_s_ac.h>
221da177e4SLinus Torvalds #include <net/llc_c_ev.h>
231da177e4SLinus Torvalds #include <net/llc_c_st.h>
241da177e4SLinus Torvalds #include <net/llc_s_ev.h>
251da177e4SLinus Torvalds #include <net/llc_s_st.h>
261da177e4SLinus Torvalds #include <net/llc_pdu.h>
271da177e4SLinus Torvalds 
llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff * skb)281da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
291da177e4SLinus Torvalds {
301da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
311da177e4SLinus Torvalds 
32025e3633SBen Hutchings 	return LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
331da177e4SLinus Torvalds 	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
341da177e4SLinus Torvalds 	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
35af1c0e4eSChan Shu Tak, Alex 	       !pdu->dsap;				/* NULL DSAP value */
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds 
llc_stat_ev_rx_null_dsap_test_c(struct sk_buff * skb)381da177e4SLinus Torvalds static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
391da177e4SLinus Torvalds {
401da177e4SLinus Torvalds 	struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
411da177e4SLinus Torvalds 
42025e3633SBen Hutchings 	return LLC_PDU_IS_CMD(pdu) &&			/* command PDU */
431da177e4SLinus Torvalds 	       LLC_PDU_TYPE_IS_U(pdu) &&		/* U type PDU */
441da177e4SLinus Torvalds 	       LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
45af1c0e4eSChan Shu Tak, Alex 	       !pdu->dsap;				/* NULL DSAP */
461da177e4SLinus Torvalds }
471da177e4SLinus Torvalds 
llc_station_ac_send_xid_r(struct sk_buff * skb)481da177e4SLinus Torvalds static int llc_station_ac_send_xid_r(struct sk_buff *skb)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	u8 mac_da[ETH_ALEN], dsap;
511da177e4SLinus Torvalds 	int rc = 1;
52f83f1768SJoonwoo Park 	struct sk_buff *nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U,
53f83f1768SJoonwoo Park 					       sizeof(struct llc_xid_info));
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds 	if (!nskb)
561da177e4SLinus Torvalds 		goto out;
571da177e4SLinus Torvalds 	llc_pdu_decode_sa(skb, mac_da);
581da177e4SLinus Torvalds 	llc_pdu_decode_ssap(skb, &dsap);
591da177e4SLinus Torvalds 	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
601da177e4SLinus Torvalds 	llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
61a5a04819SJoonwoo Park 	rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
62249ff1c6SArnaldo Carvalho de Melo 	if (unlikely(rc))
631da177e4SLinus Torvalds 		goto free;
645ecf9eeaSBen Hutchings 	dev_queue_xmit(nskb);
651da177e4SLinus Torvalds out:
661da177e4SLinus Torvalds 	return rc;
671da177e4SLinus Torvalds free:
6891d27a86SSorin Dumitru 	kfree_skb(nskb);
691da177e4SLinus Torvalds 	goto out;
701da177e4SLinus Torvalds }
711da177e4SLinus Torvalds 
llc_station_ac_send_test_r(struct sk_buff * skb)721da177e4SLinus Torvalds static int llc_station_ac_send_test_r(struct sk_buff *skb)
731da177e4SLinus Torvalds {
741da177e4SLinus Torvalds 	u8 mac_da[ETH_ALEN], dsap;
751da177e4SLinus Torvalds 	int rc = 1;
76f83f1768SJoonwoo Park 	u32 data_size;
77f83f1768SJoonwoo Park 	struct sk_buff *nskb;
78f83f1768SJoonwoo Park 
79*ff5cb6a4SWillem de Bruijn 	if (skb->mac_len < ETH_HLEN)
80*ff5cb6a4SWillem de Bruijn 		goto out;
81*ff5cb6a4SWillem de Bruijn 
82f83f1768SJoonwoo Park 	/* The test request command is type U (llc_len = 3) */
83f83f1768SJoonwoo Park 	data_size = ntohs(eth_hdr(skb)->h_proto) - 3;
84f83f1768SJoonwoo Park 	nskb = llc_alloc_frame(NULL, skb->dev, LLC_PDU_TYPE_U, data_size);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	if (!nskb)
871da177e4SLinus Torvalds 		goto out;
881da177e4SLinus Torvalds 	llc_pdu_decode_sa(skb, mac_da);
891da177e4SLinus Torvalds 	llc_pdu_decode_ssap(skb, &dsap);
901da177e4SLinus Torvalds 	llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
911da177e4SLinus Torvalds 	llc_pdu_init_as_test_rsp(nskb, skb);
92a5a04819SJoonwoo Park 	rc = llc_mac_hdr_init(nskb, skb->dev->dev_addr, mac_da);
93249ff1c6SArnaldo Carvalho de Melo 	if (unlikely(rc))
941da177e4SLinus Torvalds 		goto free;
955ecf9eeaSBen Hutchings 	dev_queue_xmit(nskb);
961da177e4SLinus Torvalds out:
971da177e4SLinus Torvalds 	return rc;
981da177e4SLinus Torvalds free:
9991d27a86SSorin Dumitru 	kfree_skb(nskb);
1001da177e4SLinus Torvalds 	goto out;
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds /**
1041da177e4SLinus Torvalds  *	llc_station_rcv - send received pdu to the station state machine
1051da177e4SLinus Torvalds  *	@skb: received frame.
1061da177e4SLinus Torvalds  *
1071da177e4SLinus Torvalds  *	Sends data unit to station state machine.
1081da177e4SLinus Torvalds  */
llc_station_rcv(struct sk_buff * skb)1091da177e4SLinus Torvalds static void llc_station_rcv(struct sk_buff *skb)
1101da177e4SLinus Torvalds {
11112ebc8b9SBen Hutchings 	if (llc_stat_ev_rx_null_dsap_xid_c(skb))
11212ebc8b9SBen Hutchings 		llc_station_ac_send_xid_r(skb);
11312ebc8b9SBen Hutchings 	else if (llc_stat_ev_rx_null_dsap_test_c(skb))
11412ebc8b9SBen Hutchings 		llc_station_ac_send_test_r(skb);
11504d191c2SBen Hutchings 	kfree_skb(skb);
1161da177e4SLinus Torvalds }
1171da177e4SLinus Torvalds 
llc_station_init(void)1186024935fSBen Hutchings void __init llc_station_init(void)
1191da177e4SLinus Torvalds {
120aadf31deSBen Hutchings 	llc_set_station_handler(llc_station_rcv);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds 
llc_station_exit(void)123f4f8720fSBen Hutchings void llc_station_exit(void)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds 	llc_set_station_handler(NULL);
1261da177e4SLinus Torvalds }
127